@posiwise/user-module 0.0.147 → 0.0.150
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,41 +1,43 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as i8 from '@angular/common';
|
|
2
2
|
import { CommonModule } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { ViewChild, Component, EventEmitter, Output, Input, NgModule } from '@angular/core';
|
|
4
|
+
import { ViewChild, Component, EventEmitter, Output, Input, HostListener, Optional, Self, Directive, Pipe, NgModule } from '@angular/core';
|
|
5
5
|
import * as i2 from '@angular/forms';
|
|
6
6
|
import { Validators, ReactiveFormsModule, FormsModule } from '@angular/forms';
|
|
7
7
|
import * as i1 from '@angular/router';
|
|
8
8
|
import { RouterModule } from '@angular/router';
|
|
9
|
-
import * as
|
|
9
|
+
import * as i7 from '@angular-magic/ngx-gp-autocomplete';
|
|
10
10
|
import { NgxGpAutocompleteModule } from '@angular-magic/ngx-gp-autocomplete';
|
|
11
11
|
import { AppConfigService } from '@posiwise/app-config-service';
|
|
12
|
+
import * as i3$1 from '@posiwise/app-loader';
|
|
13
|
+
import { AppLoaderModule } from '@posiwise/app-loader';
|
|
12
14
|
import { CoreTranslocoModule } from '@posiwise/core-transloco';
|
|
13
|
-
import * as
|
|
15
|
+
import * as i3 from '@posiwise/directives';
|
|
14
16
|
import { DirectivesModule } from '@posiwise/directives';
|
|
15
|
-
import * as i6
|
|
17
|
+
import * as i6 from '@posiwise/pipes';
|
|
16
18
|
import { PipesModule } from '@posiwise/pipes';
|
|
17
19
|
import * as i5 from '@posiwise/shared-components';
|
|
18
20
|
import { SharedComponentsModule } from '@posiwise/shared-components';
|
|
19
|
-
import * as i6$
|
|
21
|
+
import * as i6$1 from 'ngx-captcha';
|
|
20
22
|
import { NgxCaptchaModule } from 'ngx-captcha';
|
|
21
23
|
import * as i11$1 from 'ngx-ui-switch';
|
|
22
24
|
import { UiSwitchModule } from 'ngx-ui-switch';
|
|
23
25
|
import * as i2$2 from 'primeng/accordion';
|
|
24
26
|
import { AccordionModule } from 'primeng/accordion';
|
|
25
|
-
import * as i7$
|
|
27
|
+
import * as i7$2 from 'primeng/datepicker';
|
|
26
28
|
import { DatePickerModule } from 'primeng/datepicker';
|
|
27
|
-
import * as i7 from 'primeng/fileupload';
|
|
29
|
+
import * as i7$1 from 'primeng/fileupload';
|
|
28
30
|
import { FileUploadModule } from 'primeng/fileupload';
|
|
29
31
|
import * as i1$3 from 'primeng/inputtext';
|
|
30
32
|
import { InputTextModule } from 'primeng/inputtext';
|
|
31
33
|
import { MultiSelectModule } from 'primeng/multiselect';
|
|
32
|
-
import * as i4
|
|
34
|
+
import * as i4 from 'primeng/progressspinner';
|
|
33
35
|
import { ProgressSpinnerModule } from 'primeng/progressspinner';
|
|
34
|
-
import * as i6$
|
|
36
|
+
import * as i6$2 from 'primeng/rating';
|
|
35
37
|
import { RatingModule } from 'primeng/rating';
|
|
36
|
-
import * as
|
|
38
|
+
import * as i8$1 from 'primeng/select';
|
|
37
39
|
import { SelectModule } from 'primeng/select';
|
|
38
|
-
import * as i8$
|
|
40
|
+
import * as i8$3 from 'primeng/selectbutton';
|
|
39
41
|
import { SelectButtonModule } from 'primeng/selectbutton';
|
|
40
42
|
import * as i11 from 'primeng/tooltip';
|
|
41
43
|
import { TooltipModule } from 'primeng/tooltip';
|
|
@@ -48,26 +50,25 @@ import * as i1$2 from '@posiwise/common-services';
|
|
|
48
50
|
import { FormHelperService, ValidationService, PermissionService } from '@posiwise/common-services';
|
|
49
51
|
import { AppUser, PRODUCT_CATEGORY, POLL_TIMEOUT, Project, TAG_TYPE, TAG_ENTITY } from '@posiwise/common-utilities';
|
|
50
52
|
import { HelperService } from '@posiwise/helper-service';
|
|
51
|
-
import * as
|
|
53
|
+
import * as i10 from '@posiwise/utils';
|
|
52
54
|
import { ValidateForm, clearQueryParams, appendQueryParam } from '@posiwise/utils';
|
|
53
55
|
import { StatusCodes } from 'http-status-codes';
|
|
54
56
|
import { map, from, forkJoin, interval } from 'rxjs';
|
|
55
|
-
import
|
|
56
|
-
import * as i8 from '@jsverse/transloco';
|
|
57
|
+
import * as i8$2 from '@jsverse/transloco';
|
|
57
58
|
import cloneDeep from 'lodash/cloneDeep';
|
|
58
59
|
import sortBy from 'lodash/sortBy';
|
|
59
60
|
import { distinct, mergeMap } from 'rxjs/operators';
|
|
60
61
|
import { GetUser, getUser } from '@posiwise/app-store';
|
|
61
|
-
import * as i4$
|
|
62
|
+
import * as i4$1 from '@ngrx/store';
|
|
62
63
|
import * as i5$1 from '@angular/cdk/clipboard';
|
|
63
64
|
import { HttpParams } from '@angular/common/http';
|
|
64
65
|
import * as i2$1 from '@posiwise/admin-module-utils';
|
|
65
66
|
import { AppAdmin } from '@posiwise/admin-module-utils';
|
|
66
|
-
import * as i4$
|
|
67
|
+
import * as i4$2 from 'primeng/table';
|
|
67
68
|
import * as i5$2 from 'primeng/api';
|
|
68
69
|
import moment from 'moment';
|
|
69
|
-
import * as i4$
|
|
70
|
-
import * as i4$
|
|
70
|
+
import * as i4$3 from 'primeng/autocomplete';
|
|
71
|
+
import * as i4$4 from 'primeng/tabs';
|
|
71
72
|
|
|
72
73
|
class AccountComponent {
|
|
73
74
|
constructor(router) {
|
|
@@ -110,7 +111,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
|
|
|
110
111
|
}] } });
|
|
111
112
|
|
|
112
113
|
class AccountDetailsComponent extends AppBaseComponent {
|
|
113
|
-
constructor(fb, modalService, authService, geoService, profileService, injector, cdr) {
|
|
114
|
+
constructor(fb, modalService, authService, geoService, profileService, injector, cdr, confirmDialog) {
|
|
114
115
|
super(injector);
|
|
115
116
|
this.fb = fb;
|
|
116
117
|
this.modalService = modalService;
|
|
@@ -118,6 +119,7 @@ class AccountDetailsComponent extends AppBaseComponent {
|
|
|
118
119
|
this.geoService = geoService;
|
|
119
120
|
this.profileService = profileService;
|
|
120
121
|
this.cdr = cdr;
|
|
122
|
+
this.confirmDialog = confirmDialog;
|
|
121
123
|
this.image = 'assets/img/icons/male.png';
|
|
122
124
|
this.states = [];
|
|
123
125
|
this.passwordVerified = false;
|
|
@@ -412,9 +414,9 @@ class AccountDetailsComponent extends AppBaseComponent {
|
|
|
412
414
|
this.toggleEmail = !this.toggleEmail;
|
|
413
415
|
}
|
|
414
416
|
else {
|
|
415
|
-
|
|
416
|
-
text:
|
|
417
|
-
|
|
417
|
+
this.confirmDialog.open({
|
|
418
|
+
text: "You don't have password, please reset your password first and then try changing email",
|
|
419
|
+
confirmOnly: true
|
|
418
420
|
});
|
|
419
421
|
}
|
|
420
422
|
}
|
|
@@ -425,16 +427,15 @@ class AccountDetailsComponent extends AppBaseComponent {
|
|
|
425
427
|
this.showApiClientId = !this.showApiClientId;
|
|
426
428
|
}
|
|
427
429
|
refreshApiTokens() {
|
|
428
|
-
|
|
430
|
+
this.confirmDialog
|
|
431
|
+
.open({
|
|
429
432
|
title: 'Are you sure?',
|
|
430
433
|
text: this.translation.translate('User.Subscriptions.APICredentials.RefreshWarning'),
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
}).then(result => {
|
|
437
|
-
if (result.isConfirmed) {
|
|
434
|
+
destructive: true,
|
|
435
|
+
confirmLabel: 'Yes, refresh tokens!'
|
|
436
|
+
})
|
|
437
|
+
.then(ok => {
|
|
438
|
+
if (ok) {
|
|
438
439
|
this.performTokenRefresh();
|
|
439
440
|
}
|
|
440
441
|
});
|
|
@@ -473,8 +474,8 @@ class AccountDetailsComponent extends AppBaseComponent {
|
|
|
473
474
|
this.cdr.markForCheck();
|
|
474
475
|
});
|
|
475
476
|
}
|
|
476
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: AccountDetailsComponent, deps: [{ token: i2.UntypedFormBuilder }, { token: i1$1.NgbModal }, { token: i1$2.AuthService }, { token: i1$2.GeoService }, { token: i1$2.ProfileService }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
477
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: AccountDetailsComponent, isStandalone: false, selector: "pw-account-details", viewQueries: [{ propertyName: "placesRef", first: true, predicate: ["ngxPlaces"], descendants: true }, { propertyName: "passwordRef", first: true, predicate: ["password"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"w-100 text-center\">\n @if (!isLoaded) {\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n }\n</div>\n<div class=\"row gx-3 mb-3\">\n <div class=\"col-md-4\">\n <section class=\"card p-4 h-100 d-flex flex-column\">\n <h2>{{ 'User.Profile.Avatar' | transloco }}</h2>\n <div class=\"text-center d-flex flex-column justify-content-center flex-grow-1 mt-1\">\n <div class=\"image-container\">\n <img [src]=\"image\"\n width=\"150\"\n height=\"150\"\n class=\"image rounded-circle\"\n alt=\"User Male\"\n (error)=\"handleImageError($event, 'assets/img/icons/male.png')\" />\n <div class=\"overlay\"\n (keydown.enter)=\"openModal(content)\"\n (click)=\"openModal(content)\">\n <div class=\"overlay-text\">{{ 'User.Profile.Change' | transloco }}</div>\n </div>\n </div>\n <h4 class=\"mt-2\">{{ user?.first_name }} {{ user?.last_name }}</h4>\n <a aria-label=\"Navigate to Target\"\n class=\"d-inline-block mb-2\"\n (click)=\"openModal(content)\">\n {{ 'User.Profile.EditAvatar' | transloco }}</a>\n </div>\n </section>\n </div>\n <div class=\"col-md-8\">\n <section id=\"user-profile\"\n class=\"card p-4 overflow-visible h-100\">\n <form [formGroup]=\"profileForm\"\n (ngSubmit)=\"onProfileFormSubmit()\">\n <h2>{{ 'User.Profile.UserProfile' | transloco }}</h2>\n <div class=\"row mt-3\">\n <div class=\"col-sm-12 col-md-6 col-lg-6\">\n <pw-input-container label=\"First Name\"\n name=\"first_name\"\n controlId=\"account-first_name\"\n errorMsg=\"Please enter first Name\">\n <input type=\"text\"\n id=\"account-first_name\"\n class=\"form-control\"\n formControlName=\"first_name\"\n autocomplete=\"given-name\" name=\"input_first_name_9\"/>\n </pw-input-container>\n <pw-input-container label=\"Preferred name\"\n name=\"preferred_name\"\n controlId=\"account-preferred_name\"\n errorMsg=\"Please enter preferred Name\">\n <input type=\"text\"\n id=\"account-preferred_name\"\n class=\"form-control\"\n formControlName=\"preferred_name\"\n autocomplete=\"username\" name=\"input_preferred_name_10\"/>\n </pw-input-container>\n @if (countries$ | async; as countries) {\n <pw-input-container label=\"Country\"\n name=\"country\"\n controlId=\"account-country\"\n [useAriaLabelledbyOnly]=\"true\"\n errorMsg=\"Please select a country\">\n <p-select\n [attr.aria-labelledby]=\"'account-country-label'\"\n [options]=\"countries\"\n optionLabel=\"name\"\n optionValue=\"code\"\n formControlName=\"country\"\n (onChange)=\"getRegion($event.value)\"\n placeholder=\"{{ 'User.Profile.SelectCountry' | transloco }}\">\n </p-select>\n </pw-input-container>\n }\n <pw-input-container label=\"Province\"\n name=\"province\"\n controlId=\"account-province\"\n errorMsg=\"Please enter province\">\n <input type=\"text\"\n id=\"account-province\"\n class=\"form-control\"\n formControlName=\"province\"\n autocomplete=\"postal-code\" name=\"input_province_11\"/>\n </pw-input-container>\n <pw-input-container label=\"Website Url\"\n name=\"website_url\"\n controlId=\"account-website_url\"\n errorMsg=\"Please enter Website\">\n <input type=\"text\"\n id=\"account-website_url\"\n class=\"form-control\"\n formControlName=\"website_url\"\n autocomplete=\"url\" name=\"input_website_url_12\"/>\n </pw-input-container>\n </div>\n <div class=\"col-sm-12 col-md-6 col-lg-6\">\n <pw-input-container label=\"Last Name\"\n name=\"last_name\"\n controlId=\"account-last_name\"\n errorMsg=\"Please enter last Name\">\n <input type=\"text\"\n id=\"account-last_name\"\n class=\"form-control\"\n formControlName=\"last_name\"\n autocomplete=\"family-name\" name=\"input_last_name_13\"/>\n </pw-input-container>\n <pw-input-container label=\"Date of Birth\"\n name=\"dob\"\n controlId=\"account-dob\"\n errorMsg=\"Please enter date of birth\">\n <div class=\"input-group\">\n <input class=\"form-control\"\n id=\"account-dob\"\n name=\"dob\"\n placeholder=\"dd-mmm-yyyy\"\n formControlName=\"dob\"\n ngbDatepicker\n #d=\"ngbDatepicker\"\n [minDate]=\"{ day: 1, month: 1, year: 1950 }\"\n [maxDate]=\"{ day: 31, month: 12, year: 2018 }\" />\n <button class=\"btn btn-primary\"\n type=\"button\"\n id=\"account-dob-trigger\"\n aria-label=\"Open date picker for date of birth\"\n (click)=\"d.toggle()\">\n <i class=\"fa fa-calendar\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </pw-input-container>\n <pw-input-container label=\"State\"\n name=\"state\"\n controlId=\"account-state\"\n [useAriaLabelledbyOnly]=\"true\"\n errorMsg=\"Please select a state\">\n <p-select\n [attr.aria-labelledby]=\"'account-state-label'\"\n [options]=\"states\"\n [(ngModel)]=\"selectedState\"\n optionLabel=\"name\"\n optionValue=\"code\"\n formControlName=\"state\"\n [placeholder]=\"'User.Profile.SelectState' | transloco\">\n </p-select>\n </pw-input-container>\n <pw-input-container label=\"Location\"\n name=\"location\"\n controlId=\"account-location\"\n [useAriaLabelledbyOnly]=\"true\">\n <input ngx-gp-autocomplete\n id=\"account-location\"\n name=\"location\"\n class=\"form-control\"\n [attr.aria-labelledby]=\"'account-location-label'\"\n #places=\"ngx-places\"\n formControlName=\"location\"\n (onAddressChange)=\"handleAddressChange($event)\" />\n </pw-input-container>\n <pw-input-container label=\"Phone Number\"\n name=\"phone_number\"\n controlId=\"account-phone_number\"\n errorMsg=\"Please enter phone number\">\n <input type=\"text\"\n id=\"account-phone_number\"\n class=\"form-control\"\n formControlName=\"phone_number\"\n autocomplete=\"tel\" name=\"input_phone_number_16\"/>\n </pw-input-container>\n </div>\n <div class=\"col-12 text-end\">\n <div class=\"mb-3\">\n <button class=\"btn btn-raised btn-primary\" [buttonBusy]=\"profileBusyButton\">\n {{ 'Button.Save' | transloco }}\n </button>\n </div>\n </div>\n </div>\n </form>\n </section>\n </div>\n</div>\n<div class=\"row gx-3 mb-3\">\n <div class=\"col-md-6\">\n <section id=\"email-section\"\n class=\"card p-4 h-100\">\n <div class=\"row\">\n <div class=\"col-12\">\n <h2>{{ 'User.Account.RegisteredEmail' | transloco }}</h2>\n <section id=\"email-form\">\n <form [formGroup]=\"emailForm\"\n (ngSubmit)=\"onEmailFormSubmit()\">\n <!-- Email Address -->\n <div class=\"mt-0\">\n <span id=\"account-primary-email-label\" class=\"me-3 pw-label-style\">{{ 'User.Account.PrimaryEmail' | transloco }}:\n </span>\n <strong>{{ validatedEmail }}</strong>\n <div class=\"mt-1\">\n @if (!toggleEmail) {\n <a class=\"btn btn-raised btn-outline-primary\"\n aria-label=\"Navigate to Target\"\n (click)=\"shouldUserChangeEmail()\">\n {{ 'User.Account.ChangeEmail' | transloco }}</a>\n }\n @if (toggleEmail) {\n <div class=\"row\">\n <div class=\"clearfix\"></div>\n <div class=\"col-12 mb-3\">\n @if (!passwordVerified) {\n <input type=\"password\"\n class=\"form-control\"\n id=\"account-email-current-password\"\n name=\"currentPassword\"\n #password\n placeholder=\"Current Password\"\n autocomplete=\"current-password\"\n (keyup)=\"checkValidity()\" />\n }\n @if (passwordVerified) {\n <input type=\"text\"\n class=\"form-control\"\n id=\"account-new-email\"\n name=\"newEmail\"\n placeholder=\"New Email\"\n autocomplete=\"email\"\n formControlName=\"email\" />\n }\n </div>\n <div class=\"col-12\">\n @if (toggleEmail) {\n <a\n class=\"btn btn-raised btn-outline-default my-2 me-2\"\n aria-label=\"Navigate to Target\"\n (click)=\"onToggleEmail()\">{{ 'Button.Cancel' | transloco }}</a>\n }\n @if (!passwordVerified) {\n <button class=\"btn btn-raised btn-primary\"\n type=\"submit\"\n [buttonBusy]=\"validatePasswordBusyButton\"\n (click)=\"validatePassword()\"\n [disabled]=\"isCurrentPasswordValid\">\n {{ 'User.Account.Validate' | transloco }}\n </button>\n }\n @if (passwordVerified) {\n <button type=\"submit\"\n class=\"btn btn-raised btn-primary\"\n [buttonBusy]=\"emailBusyButton\"\n >\n {{\n 'User.Account.SendVerification' | transloco\n }}\n </button>\n }\n </div>\n </div>\n }\n </div>\n </div>\n <section id=\"slug\"\n class=\"mb-2 mt-3\">\n <div>\n <span class=\"me-3 pw-label-style\" id=\"account-nickname-label\">{{ 'User.Account.NickName' | transloco }}:</span>\n <span class=\"tooltip-wrap me-3\" [pTooltip]=\"'User.Account.HandleTooltip' | transloco\" [appendTo]=\"'body'\" tooltipPosition=\"top\"><i class=\"far fa-info-circle text-muted\"></i></span>\n <strong>{{ slug }}</strong>\n <div class=\"mt-1\">\n @if (!toggleNickName) {\n <a class=\"btn btn-raised btn-outline-primary me-2\"\n aria-label=\"Navigate to Target\"\n (click)=\"toggleNickName = true\">\n {{ 'User.Account.ChangeNickname' | transloco }}</a>\n }\n @if (toggleNickName) {\n <div class=\"mb-3\">\n <input type=\"text\"\n id=\"account-nickname\"\n name=\"nickname\"\n class=\"form-control slug-input\"\n aria-labelledby=\"account-nickname-label\"\n [(ngModel)]=\"slug\"\n [ngModelOptions]=\"{ standalone: true }\" />\n </div>\n <div>\n <button type=\"button\"\n class=\"btn btn-raised btn-outline-default\"\n (click)=\"toggleNickName = false\">\n {{ 'Button.Cancel' | transloco }}\n </button>\n <button type=\"button\"\n class=\"btn btn-raised btn-primary ms-2\"\n [buttonBusy]=\"slugBusyButton\"\n [disabled]=\"slug?.length < 2\"\n (click)=\"onUpdateSlug()\">\n {{ 'User.Account.UpdateNickname' | transloco }}\n </button>\n </div>\n }\n </div>\n </div>\n </section>\n </form>\n </section>\n </div>\n </div>\n </section>\n </div>\n <div class=\"col-md-6\">\n <section id=\"password-change\"\n class=\"card p-4 h-100\">\n <form [formGroup]=\"passwordForm\"\n (ngSubmit)=\"onPasswordFormSubmit()\">\n <div class=\"row\">\n <div class=\"col-12\">\n <h2>{{ 'User.Account.ChangePassword' | transloco }}</h2>\n </div>\n @if (!user?.has_password) {\n <div class=\"text-danger mx-3 my-2\">\n <div>\n You don't have a password set, click on\n <em>{{ 'User.Account.ChangePassword' | transloco }}</em>.\n </div>\n <div>{{ 'User.Profile.PictureMessage' | transloco }}</div>\n </div>\n }\n @if (user?.has_password) {\n <div class=\"col-12\"\n >\n @if (togglePassword) {\n <div class=\"mb-3\">\n <label for=\"account-current-password\">{{ 'User.Account.CurrentPassword' | transloco }}</label>\n <input type=\"password\"\n id=\"account-current-password\"\n class=\"form-control\"\n formControlName=\"currentPassword\"\n autocomplete=\"current-password\" name=\"input_currentPassword_4\"/>\n @if (\n !passwordForm.get('currentPassword').valid &&\n (passwordForm.get('currentPassword').dirty ||\n passwordForm.get('currentPassword').touched)\n ) {\n <small class=\"form-text text-muted danger\"\n >\n {{ 'User.Account.Required' | transloco }}\n </small>\n }\n </div>\n <div class=\"mb-3\">\n <label for=\"account-new-password\">{{ 'User.Account.NewPassword' | transloco }}</label>\n <input type=\"password\"\n id=\"account-new-password\"\n class=\"form-control\"\n formControlName=\"newPassword\"\n autocomplete=\"new-password\" name=\"input_newPassword_5\"/>\n @if (\n !passwordForm.get('newPassword').valid &&\n (passwordForm.get('newPassword').dirty ||\n passwordForm.get('newPassword').touched)\n ) {\n <small class=\"form-text text-muted danger\"\n >{{ 'User.Account.Validation.StrongPassword' | transloco }}\n </small>\n }\n </div>\n <div class=\"mb-3\">\n <label for=\"account-confirm-password\">{{\n 'User.Account.ConfirmPassword' | transloco\n }}</label>\n <input type=\"password\"\n id=\"account-confirm-password\"\n class=\"form-control\"\n formControlName=\"confirmPassword\"\n autocomplete=\"new-password\" name=\"input_confirmPassword_6\"/>\n @if (\n passwordForm.get('confirmPassword').touched &&\n passwordForm.get('confirmPassword').errors\n ?.MatchPassword\n ) {\n <div class=\"text-danger\"\n >\n {{ 'User.Account.Validation.PasswordsMatch' | transloco }}\n </div>\n }\n </div>\n <div class=\"mb-3\">\n @if (togglePassword) {\n <a class=\"btn btn-raised btn-outline-default\"\n aria-label=\"Navigate to Target\"\n data-bs-target=\"\"\n (click)=\"onTogglePassword()\">\n {{ 'Button.Cancel' | transloco }}</a>\n }\n <button class=\"btn btn-raised btn-primary ms-2\"\n [buttonBusy]=\"passwordBusyButton\"\n [disabled]=\"!passwordForm.valid\">\n {{ 'User.Account.UpdatePassword' | transloco }}\n </button>\n </div>\n }\n <div>\n @if (!togglePassword) {\n <a class=\"btn btn-raised btn-outline-primary\"\n aria-label=\"Navigate to Target\"\n data-bs-target=\"\"\n (click)=\"togglePassword = !togglePassword\">\n {{ 'User.Account.ChangePassword' | transloco }}</a>\n }\n </div>\n </div>\n }\n @if (!user?.has_password) {\n <div class=\"col-12\"\n >\n <a class=\"btn btn-raised btn-primary me-2\"\n aria-label=\"Navigate to Target\"\n data-bs-target=\"\"\n (click)=\"sendMailToResetPassword()\">\n {{ 'User.Account.ChangePassword' | transloco }}</a>\n </div>\n }\n </div>\n </form>\n </section>\n </div>\n @if (user?.api_keys?.api_hits_max > 0) {\n <div class=\"col-12 mt-3\">\n <section id=\"api-credentials\"\n class=\"card p-4 h-auto\">\n <div class=\"row\">\n <div class=\"col-12\">\n <h2>{{ 'User.Subscriptions.APICredentials.Title' | transloco }}</h2>\n <p>\n {{ 'User.Subscriptions.APICredentials.Description' | transloco }}\n </p>\n <!-- pb (not mb): .card .mb-3:last-child is margin-reset in this component's scss -->\n <p class=\"text-muted small mb-0 pb-3\">\n <i class=\"fas fa-info-circle me-1\"></i>\n {{ 'User.Subscriptions.APICredentials.SubscriptionClientIdNote' | transloco }}\n </p>\n </div>\n <div class=\"col-12 col-md-6\">\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"account-api-token\">{{ 'User.Account.APIUserToken' | transloco }}</label>\n <div class=\"input-group\">\n <input type=\"text\"\n id=\"account-api-token\"\n name=\"api_token\"\n class=\"form-control\"\n [value]=\"showApiToken ? user?.api_keys?.api_user_token || ('User.Subscriptions.APICredentials.NoTokenAvailable' | transloco) : '*************************'\"\n readonly />\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"toggleApiTokenVisibility()\">\n {{ showApiToken ? ('User.Subscriptions.APICredentials.Hide' | transloco) : ('User.Subscriptions.APICredentials.View' | transloco) }}\n </button>\n </div>\n </div>\n </div>\n <div class=\"col-12 col-md-6\">\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"account-api-client-id\">{{ 'User.Account.APIUserId' | transloco }}</label>\n <div class=\"input-group\">\n <input type=\"text\"\n id=\"account-api-client-id\"\n name=\"api_client_id\"\n class=\"form-control\"\n [value]=\"showApiClientId ? user?.api_keys?.api_user_id || ('User.Subscriptions.APICredentials.NoClientIdAvailable' | transloco) : '*************************'\"\n readonly />\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"toggleApiClientIdVisibility()\">\n {{ showApiClientId ? ('User.Subscriptions.APICredentials.Hide' | transloco) : ('User.Subscriptions.APICredentials.View' | transloco) }}\n </button>\n </div>\n </div>\n </div>\n <div class=\"col-12 mt-3\">\n <div class=\"d-flex align-items-center gap-3\">\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"refreshApiTokens()\"\n [disabled]=\"refreshingTokens\">\n <i class=\"fas fa-sync-alt me-2\" [class.fa-spin]=\"refreshingTokens\"></i>\n {{ refreshingTokens ? ('User.Subscriptions.APICredentials.Refreshing' | transloco) : ('User.Subscriptions.APICredentials.RefreshTokens' | transloco) }}\n </button>\n <div class=\"d-flex align-items-center gap-2\">\n @if (user?.api_keys?.api_hits !== null) {\n <span class=\"text-muted\">{{ 'User.Subscriptions.APICredentials.ApiHits' | transloco }}:</span>\n <span class=\"fw-bold\">{{ user.api_keys.api_hits | number }}</span>\n }\n @if (user?.api_keys?.api_hits_max !== null) {\n <span class=\"text-muted\">{{ 'User.Subscriptions.APICredentials.ApiHitsMax' | transloco }}:</span>\n <span class=\"fw-bold\">{{ user.api_keys.api_hits_max | number }}</span>\n }\n <!-- Show utilization percentage when both values exist -->\n @if (user?.api_keys?.api_hits !== null && user?.api_keys?.api_hits_max !== null && user?.api_keys?.api_hits_max > 0) {\n <span class=\"text-muted ms-2\">(</span>\n <span class=\"fw-bold\" [ngClass]=\"{\n 'text-success': (user.api_keys.api_hits / user.api_keys.api_hits_max) <= 0.8,\n 'text-warning': (user.api_keys.api_hits / user.api_keys.api_hits_max) > 0.8 && (user.api_keys.api_hits / user.api_keys.api_hits_max) <= 0.9,\n 'text-danger': (user.api_keys.api_hits / user.api_keys.api_hits_max) > 0.9\n }\">\n {{ (user.api_keys.api_hits / user.api_keys.api_hits_max * 100) | number:'1.0-0' }}% consumed\n </span>\n <span class=\"text-muted\">)</span>\n }\n </div>\n </div>\n </div>\n </div>\n </section>\n </div>\n }\n</div>\n<ng-template #content\n let-modal>\n <div class=\"card m-0\">\n <div class=\"card-content\">\n <div class=\"card-title\">\n <h3 class=\"modal-title\">{{ 'User.Profile.ProfilePicture' | transloco }}</h3>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n </button>\n </div>\n <div class=\"card-header\">\n <small> {{ 'User.Profile.PictureMessage' | transloco }}</small>\n <pw-image-cropper #profile\n aspectRatio=\"auto\"\n (imageSelectionEvent)=\"onImageSelection($event)\"\n (closeEvent)=\"onClose()\">\n </pw-image-cropper>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [".card .mb-2:last-child,.card .mb-3:last-child{margin-bottom:0!important}.overlay{left:50%;opacity:0;position:absolute;text-align:center;top:50%;transform:translate(-50%,-50%);transition:.5s ease}.image-container{position:relative}.image-container:hover .image{opacity:.3}.image-container:hover .overlay{opacity:0}.overlay-text{background:#f0efef80;border-radius:50%;color:#000;font-size:16px;height:150px;line-height:150px;text-align:center;vertical-align:middle;width:150px}@media screen and (max-width:767px){.card-body{padding:20px!important}}\n"], dependencies: [{ kind: "directive", type: i4.ButtonBusyDirective, selector: "[buttonBusy]", inputs: ["buttonBusy", "busyText"] }, { kind: "directive", type: i4.LazyImgDirective, selector: "img" }, { kind: "directive", type: i6.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i6$1.NgxGpAutocompleteDirective, selector: "[ngx-gp-autocomplete]", inputs: ["options"], outputs: ["onAddressChange"], exportAs: ["ngx-places"] }, { kind: "component", type: i6$2.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i4$1.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i9.ProfileImageCropperComponent, selector: "pw-image-cropper", inputs: ["aspectRatio", "dynamicData"], outputs: ["imageSelectionEvent", "closeEvent", "fileChangeEvent"] }, { kind: "component", type: i5.InputContainerComponent, selector: "pw-input-container", inputs: ["name", "controlId", "useAriaLabelledbyOnly", "label", "labelClass", "tooltipPosition", "required", "errorMsg", "isReadOnly", "showTooltip", "tooltipText", "showTriangle", "afterLabel", "showAfterLabel", "showTriangleText", "isLeftTooltip"] }, { kind: "directive", type: i11.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "directive", type: i1$1.NgbInputDatepicker, selector: "input[ngbDatepicker]", inputs: ["autoClose", "contentTemplate", "datepickerClass", "dayTemplate", "dayTemplateData", "displayMonths", "firstDayOfWeek", "footerTemplate", "markDisabled", "minDate", "maxDate", "navigation", "outsideDays", "placement", "popperOptions", "restoreFocus", "showWeekNumbers", "startDate", "container", "positionTarget", "weekdays", "disabled"], outputs: ["dateSelect", "navigate", "closed"], exportAs: ["ngbDatepicker"] }, { kind: "pipe", type: i6.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.DecimalPipe, name: "number" }, { kind: "pipe", type: i8.TranslocoPipe, name: "transloco" }] }); }
|
|
477
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: AccountDetailsComponent, deps: [{ token: i2.UntypedFormBuilder }, { token: i1$1.NgbModal }, { token: i1$2.AuthService }, { token: i1$2.GeoService }, { token: i1$2.ProfileService }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }, { token: i5.ConfirmDialogService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
478
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: AccountDetailsComponent, isStandalone: false, selector: "pw-account-details", viewQueries: [{ propertyName: "placesRef", first: true, predicate: ["ngxPlaces"], descendants: true }, { propertyName: "passwordRef", first: true, predicate: ["password"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"w-100 text-center\">\n @if (!isLoaded) {\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n }\n</div>\n<div class=\"row gx-3 mb-3\">\n <div class=\"col-md-4\">\n <section class=\"card p-4 h-100 d-flex flex-column\">\n <h2>{{ 'User.Profile.Avatar' | transloco }}</h2>\n <div class=\"text-center d-flex flex-column justify-content-center flex-grow-1 mt-1\">\n <div class=\"image-container\">\n <img [src]=\"image\"\n width=\"150\"\n height=\"150\"\n class=\"image rounded-circle\"\n alt=\"User Male\"\n (error)=\"handleImageError($event, 'assets/img/icons/male.png')\" />\n <div class=\"overlay\"\n (keydown.enter)=\"openModal(content)\"\n (click)=\"openModal(content)\">\n <div class=\"overlay-text\">{{ 'User.Profile.Change' | transloco }}</div>\n </div>\n </div>\n <h4 class=\"mt-2\">{{ user?.first_name }} {{ user?.last_name }}</h4>\n <a aria-label=\"Navigate to Target\"\n class=\"d-inline-block mb-2\"\n (click)=\"openModal(content)\">\n {{ 'User.Profile.EditAvatar' | transloco }}</a>\n </div>\n </section>\n </div>\n <div class=\"col-md-8\">\n <section id=\"user-profile\"\n class=\"card p-4 overflow-visible h-100\">\n <form [formGroup]=\"profileForm\"\n (ngSubmit)=\"onProfileFormSubmit()\">\n <h2>{{ 'User.Profile.UserProfile' | transloco }}</h2>\n <div class=\"row mt-3\">\n <div class=\"col-sm-12 col-md-6 col-lg-6\">\n <pw-input-container label=\"First Name\"\n name=\"first_name\"\n controlId=\"account-first_name\"\n errorMsg=\"Please enter first Name\">\n <input type=\"text\"\n id=\"account-first_name\"\n class=\"form-control\"\n formControlName=\"first_name\"\n autocomplete=\"given-name\" name=\"input_first_name_9\"/>\n </pw-input-container>\n <pw-input-container label=\"Preferred name\"\n name=\"preferred_name\"\n controlId=\"account-preferred_name\"\n errorMsg=\"Please enter preferred Name\">\n <input type=\"text\"\n id=\"account-preferred_name\"\n class=\"form-control\"\n formControlName=\"preferred_name\"\n autocomplete=\"username\" name=\"input_preferred_name_10\"/>\n </pw-input-container>\n @if (countries$ | async; as countries) {\n <pw-input-container label=\"Country\"\n name=\"country\"\n controlId=\"account-country\"\n [useAriaLabelledbyOnly]=\"true\"\n errorMsg=\"Please select a country\">\n <p-select\n [attr.aria-labelledby]=\"'account-country-label'\"\n [options]=\"countries\"\n optionLabel=\"name\"\n optionValue=\"code\"\n formControlName=\"country\"\n (onChange)=\"getRegion($event.value)\"\n placeholder=\"{{ 'User.Profile.SelectCountry' | transloco }}\">\n </p-select>\n </pw-input-container>\n }\n <pw-input-container label=\"Province\"\n name=\"province\"\n controlId=\"account-province\"\n errorMsg=\"Please enter province\">\n <input type=\"text\"\n id=\"account-province\"\n class=\"form-control\"\n formControlName=\"province\"\n autocomplete=\"postal-code\" name=\"input_province_11\"/>\n </pw-input-container>\n <pw-input-container label=\"Website Url\"\n name=\"website_url\"\n controlId=\"account-website_url\"\n errorMsg=\"Please enter Website\">\n <input type=\"text\"\n id=\"account-website_url\"\n class=\"form-control\"\n formControlName=\"website_url\"\n autocomplete=\"url\" name=\"input_website_url_12\"/>\n </pw-input-container>\n </div>\n <div class=\"col-sm-12 col-md-6 col-lg-6\">\n <pw-input-container label=\"Last Name\"\n name=\"last_name\"\n controlId=\"account-last_name\"\n errorMsg=\"Please enter last Name\">\n <input type=\"text\"\n id=\"account-last_name\"\n class=\"form-control\"\n formControlName=\"last_name\"\n autocomplete=\"family-name\" name=\"input_last_name_13\"/>\n </pw-input-container>\n <pw-input-container label=\"Date of Birth\"\n name=\"dob\"\n controlId=\"account-dob\"\n errorMsg=\"Please enter date of birth\">\n <div class=\"input-group\">\n <input class=\"form-control\"\n id=\"account-dob\"\n name=\"dob\"\n placeholder=\"dd-mmm-yyyy\"\n formControlName=\"dob\"\n ngbDatepicker\n #d=\"ngbDatepicker\"\n [minDate]=\"{ day: 1, month: 1, year: 1950 }\"\n [maxDate]=\"{ day: 31, month: 12, year: 2018 }\" />\n <button class=\"btn btn-primary\"\n type=\"button\"\n id=\"account-dob-trigger\"\n aria-label=\"Open date picker for date of birth\"\n (click)=\"d.toggle()\">\n <i class=\"fa fa-calendar\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </pw-input-container>\n <pw-input-container label=\"State\"\n name=\"state\"\n controlId=\"account-state\"\n [useAriaLabelledbyOnly]=\"true\"\n errorMsg=\"Please select a state\">\n <p-select\n [attr.aria-labelledby]=\"'account-state-label'\"\n [options]=\"states\"\n [(ngModel)]=\"selectedState\"\n optionLabel=\"name\"\n optionValue=\"code\"\n formControlName=\"state\"\n [placeholder]=\"'User.Profile.SelectState' | transloco\">\n </p-select>\n </pw-input-container>\n <pw-input-container label=\"Location\"\n name=\"location\"\n controlId=\"account-location\"\n [useAriaLabelledbyOnly]=\"true\">\n <input ngx-gp-autocomplete\n id=\"account-location\"\n name=\"location\"\n class=\"form-control\"\n [attr.aria-labelledby]=\"'account-location-label'\"\n #places=\"ngx-places\"\n formControlName=\"location\"\n (onAddressChange)=\"handleAddressChange($event)\" />\n </pw-input-container>\n <pw-input-container label=\"Phone Number\"\n name=\"phone_number\"\n controlId=\"account-phone_number\"\n errorMsg=\"Please enter phone number\">\n <input type=\"text\"\n id=\"account-phone_number\"\n class=\"form-control\"\n formControlName=\"phone_number\"\n autocomplete=\"tel\" name=\"input_phone_number_16\"/>\n </pw-input-container>\n </div>\n <div class=\"col-12 text-end\">\n <div class=\"mb-3\">\n <button class=\"btn btn-raised btn-primary\" [buttonBusy]=\"profileBusyButton\">\n {{ 'Button.Save' | transloco }}\n </button>\n </div>\n </div>\n </div>\n </form>\n </section>\n </div>\n</div>\n<div class=\"row gx-3 mb-3\">\n <div class=\"col-md-6\">\n <section id=\"email-section\"\n class=\"card p-4 h-100\">\n <div class=\"row\">\n <div class=\"col-12\">\n <h2>{{ 'User.Account.RegisteredEmail' | transloco }}</h2>\n <section id=\"email-form\">\n <form [formGroup]=\"emailForm\"\n (ngSubmit)=\"onEmailFormSubmit()\">\n <!-- Email Address -->\n <div class=\"mt-0\">\n <span id=\"account-primary-email-label\" class=\"me-3 pw-label-style\">{{ 'User.Account.PrimaryEmail' | transloco }}:\n </span>\n <strong>{{ validatedEmail }}</strong>\n <div class=\"mt-1\">\n @if (!toggleEmail) {\n <a class=\"btn btn-raised btn-outline-primary\"\n aria-label=\"Navigate to Target\"\n (click)=\"shouldUserChangeEmail()\">\n {{ 'User.Account.ChangeEmail' | transloco }}</a>\n }\n @if (toggleEmail) {\n <div class=\"row\">\n <div class=\"clearfix\"></div>\n <div class=\"col-12 mb-3\">\n @if (!passwordVerified) {\n <input type=\"password\"\n class=\"form-control\"\n id=\"account-email-current-password\"\n name=\"currentPassword\"\n #password\n placeholder=\"Current Password\"\n autocomplete=\"current-password\"\n (keyup)=\"checkValidity()\" />\n }\n @if (passwordVerified) {\n <input type=\"text\"\n class=\"form-control\"\n id=\"account-new-email\"\n name=\"newEmail\"\n placeholder=\"New Email\"\n autocomplete=\"email\"\n formControlName=\"email\" />\n }\n </div>\n <div class=\"col-12\">\n @if (toggleEmail) {\n <a\n class=\"btn btn-raised btn-outline-default my-2 me-2\"\n aria-label=\"Navigate to Target\"\n (click)=\"onToggleEmail()\">{{ 'Button.Cancel' | transloco }}</a>\n }\n @if (!passwordVerified) {\n <button class=\"btn btn-raised btn-primary\"\n type=\"submit\"\n [buttonBusy]=\"validatePasswordBusyButton\"\n (click)=\"validatePassword()\"\n [disabled]=\"isCurrentPasswordValid\">\n {{ 'User.Account.Validate' | transloco }}\n </button>\n }\n @if (passwordVerified) {\n <button type=\"submit\"\n class=\"btn btn-raised btn-primary\"\n [buttonBusy]=\"emailBusyButton\"\n >\n {{\n 'User.Account.SendVerification' | transloco\n }}\n </button>\n }\n </div>\n </div>\n }\n </div>\n </div>\n <section id=\"slug\"\n class=\"mb-2 mt-3\">\n <div>\n <span class=\"me-3 pw-label-style\" id=\"account-nickname-label\">{{ 'User.Account.NickName' | transloco }}:</span>\n <span class=\"tooltip-wrap me-3\" [pTooltip]=\"'User.Account.HandleTooltip' | transloco\" [appendTo]=\"'body'\" tooltipPosition=\"top\"><i class=\"far fa-info-circle text-muted\"></i></span>\n <strong>{{ slug }}</strong>\n <div class=\"mt-1\">\n @if (!toggleNickName) {\n <a class=\"btn btn-raised btn-outline-primary me-2\"\n aria-label=\"Navigate to Target\"\n (click)=\"toggleNickName = true\">\n {{ 'User.Account.ChangeNickname' | transloco }}</a>\n }\n @if (toggleNickName) {\n <div class=\"mb-3\">\n <input type=\"text\"\n id=\"account-nickname\"\n name=\"nickname\"\n class=\"form-control slug-input\"\n aria-labelledby=\"account-nickname-label\"\n [(ngModel)]=\"slug\"\n [ngModelOptions]=\"{ standalone: true }\" />\n </div>\n <div>\n <button type=\"button\"\n class=\"btn btn-raised btn-outline-default\"\n (click)=\"toggleNickName = false\">\n {{ 'Button.Cancel' | transloco }}\n </button>\n <button type=\"button\"\n class=\"btn btn-raised btn-primary ms-2\"\n [buttonBusy]=\"slugBusyButton\"\n [disabled]=\"slug?.length < 2\"\n (click)=\"onUpdateSlug()\">\n {{ 'User.Account.UpdateNickname' | transloco }}\n </button>\n </div>\n }\n </div>\n </div>\n </section>\n </form>\n </section>\n </div>\n </div>\n </section>\n </div>\n <div class=\"col-md-6\">\n <section id=\"password-change\"\n class=\"card p-4 h-100\">\n <form [formGroup]=\"passwordForm\"\n (ngSubmit)=\"onPasswordFormSubmit()\">\n <div class=\"row\">\n <div class=\"col-12\">\n <h2>{{ 'User.Account.ChangePassword' | transloco }}</h2>\n </div>\n @if (!user?.has_password) {\n <div class=\"text-danger mx-3 my-2\">\n <div>\n You don't have a password set, click on\n <em>{{ 'User.Account.ChangePassword' | transloco }}</em>.\n </div>\n <div>{{ 'User.Profile.PictureMessage' | transloco }}</div>\n </div>\n }\n @if (user?.has_password) {\n <div class=\"col-12\"\n >\n @if (togglePassword) {\n <div class=\"mb-3\">\n <label for=\"account-current-password\">{{ 'User.Account.CurrentPassword' | transloco }}</label>\n <input type=\"password\"\n id=\"account-current-password\"\n class=\"form-control\"\n formControlName=\"currentPassword\"\n autocomplete=\"current-password\" name=\"input_currentPassword_4\"/>\n @if (\n !passwordForm.get('currentPassword').valid &&\n (passwordForm.get('currentPassword').dirty ||\n passwordForm.get('currentPassword').touched)\n ) {\n <small class=\"form-text text-muted danger\"\n >\n {{ 'User.Account.Required' | transloco }}\n </small>\n }\n </div>\n <div class=\"mb-3\">\n <label for=\"account-new-password\">{{ 'User.Account.NewPassword' | transloco }}</label>\n <input type=\"password\"\n id=\"account-new-password\"\n class=\"form-control\"\n formControlName=\"newPassword\"\n autocomplete=\"new-password\" name=\"input_newPassword_5\"/>\n @if (\n !passwordForm.get('newPassword').valid &&\n (passwordForm.get('newPassword').dirty ||\n passwordForm.get('newPassword').touched)\n ) {\n <small class=\"form-text text-muted danger\"\n >{{ 'User.Account.Validation.StrongPassword' | transloco }}\n </small>\n }\n </div>\n <div class=\"mb-3\">\n <label for=\"account-confirm-password\">{{\n 'User.Account.ConfirmPassword' | transloco\n }}</label>\n <input type=\"password\"\n id=\"account-confirm-password\"\n class=\"form-control\"\n formControlName=\"confirmPassword\"\n autocomplete=\"new-password\" name=\"input_confirmPassword_6\"/>\n @if (\n passwordForm.get('confirmPassword').touched &&\n passwordForm.get('confirmPassword').errors\n ?.MatchPassword\n ) {\n <div class=\"text-danger\"\n >\n {{ 'User.Account.Validation.PasswordsMatch' | transloco }}\n </div>\n }\n </div>\n <div class=\"mb-3\">\n @if (togglePassword) {\n <a class=\"btn btn-raised btn-outline-default\"\n aria-label=\"Navigate to Target\"\n data-bs-target=\"\"\n (click)=\"onTogglePassword()\">\n {{ 'Button.Cancel' | transloco }}</a>\n }\n <button class=\"btn btn-raised btn-primary ms-2\"\n [buttonBusy]=\"passwordBusyButton\"\n [disabled]=\"!passwordForm.valid\">\n {{ 'User.Account.UpdatePassword' | transloco }}\n </button>\n </div>\n }\n <div>\n @if (!togglePassword) {\n <a class=\"btn btn-raised btn-outline-primary\"\n aria-label=\"Navigate to Target\"\n data-bs-target=\"\"\n (click)=\"togglePassword = !togglePassword\">\n {{ 'User.Account.ChangePassword' | transloco }}</a>\n }\n </div>\n </div>\n }\n @if (!user?.has_password) {\n <div class=\"col-12\"\n >\n <a class=\"btn btn-raised btn-primary me-2\"\n aria-label=\"Navigate to Target\"\n data-bs-target=\"\"\n (click)=\"sendMailToResetPassword()\">\n {{ 'User.Account.ChangePassword' | transloco }}</a>\n </div>\n }\n </div>\n </form>\n </section>\n </div>\n @if (user?.api_keys?.api_hits_max > 0) {\n <div class=\"col-12 mt-3\">\n <section id=\"api-credentials\"\n class=\"card p-4 h-auto\">\n <div class=\"row\">\n <div class=\"col-12\">\n <h2>{{ 'User.Subscriptions.APICredentials.Title' | transloco }}</h2>\n <p>\n {{ 'User.Subscriptions.APICredentials.Description' | transloco }}\n </p>\n <!-- pb (not mb): .card .mb-3:last-child is margin-reset in this component's scss -->\n <p class=\"text-muted small mb-0 pb-3\">\n <i class=\"fas fa-info-circle me-1\"></i>\n {{ 'User.Subscriptions.APICredentials.SubscriptionClientIdNote' | transloco }}\n </p>\n </div>\n <div class=\"col-12 col-md-6\">\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"account-api-token\">{{ 'User.Account.APIUserToken' | transloco }}</label>\n <div class=\"input-group\">\n <input type=\"text\"\n id=\"account-api-token\"\n name=\"api_token\"\n class=\"form-control\"\n [value]=\"showApiToken ? user?.api_keys?.api_user_token || ('User.Subscriptions.APICredentials.NoTokenAvailable' | transloco) : '*************************'\"\n readonly />\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"toggleApiTokenVisibility()\">\n {{ showApiToken ? ('User.Subscriptions.APICredentials.Hide' | transloco) : ('User.Subscriptions.APICredentials.View' | transloco) }}\n </button>\n </div>\n </div>\n </div>\n <div class=\"col-12 col-md-6\">\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"account-api-client-id\">{{ 'User.Account.APIUserId' | transloco }}</label>\n <div class=\"input-group\">\n <input type=\"text\"\n id=\"account-api-client-id\"\n name=\"api_client_id\"\n class=\"form-control\"\n [value]=\"showApiClientId ? user?.api_keys?.api_user_id || ('User.Subscriptions.APICredentials.NoClientIdAvailable' | transloco) : '*************************'\"\n readonly />\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"toggleApiClientIdVisibility()\">\n {{ showApiClientId ? ('User.Subscriptions.APICredentials.Hide' | transloco) : ('User.Subscriptions.APICredentials.View' | transloco) }}\n </button>\n </div>\n </div>\n </div>\n <div class=\"col-12 mt-3\">\n <div class=\"d-flex align-items-center gap-3\">\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"refreshApiTokens()\"\n [disabled]=\"refreshingTokens\">\n <i class=\"fas fa-sync-alt me-2\" [class.fa-spin]=\"refreshingTokens\"></i>\n {{ refreshingTokens ? ('User.Subscriptions.APICredentials.Refreshing' | transloco) : ('User.Subscriptions.APICredentials.RefreshTokens' | transloco) }}\n </button>\n <div class=\"d-flex align-items-center gap-2\">\n @if (user?.api_keys?.api_hits !== null) {\n <span class=\"text-muted\">{{ 'User.Subscriptions.APICredentials.ApiHits' | transloco }}:</span>\n <span class=\"fw-bold\">{{ user.api_keys.api_hits | number }}</span>\n }\n @if (user?.api_keys?.api_hits_max !== null) {\n <span class=\"text-muted\">{{ 'User.Subscriptions.APICredentials.ApiHitsMax' | transloco }}:</span>\n <span class=\"fw-bold\">{{ user.api_keys.api_hits_max | number }}</span>\n }\n <!-- Show utilization percentage when both values exist -->\n @if (user?.api_keys?.api_hits !== null && user?.api_keys?.api_hits_max !== null && user?.api_keys?.api_hits_max > 0) {\n <span class=\"text-muted ms-2\">(</span>\n <span class=\"fw-bold\" [ngClass]=\"{\n 'text-success-muted': (user.api_keys.api_hits / user.api_keys.api_hits_max) <= 0.8,\n 'text-warning': (user.api_keys.api_hits / user.api_keys.api_hits_max) > 0.8 && (user.api_keys.api_hits / user.api_keys.api_hits_max) <= 0.9,\n 'text-danger': (user.api_keys.api_hits / user.api_keys.api_hits_max) > 0.9\n }\">\n {{ (user.api_keys.api_hits / user.api_keys.api_hits_max * 100) | number:'1.0-0' }}% consumed\n </span>\n <span class=\"text-muted\">)</span>\n }\n </div>\n </div>\n </div>\n </div>\n </section>\n </div>\n }\n</div>\n<ng-template #content\n let-modal>\n <div class=\"card m-0\">\n <div class=\"card-content\">\n <div class=\"card-title\">\n <h3 class=\"modal-title\">{{ 'User.Profile.ProfilePicture' | transloco }}</h3>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n </button>\n </div>\n <div class=\"card-header\">\n <small> {{ 'User.Profile.PictureMessage' | transloco }}</small>\n <pw-image-cropper #profile\n aspectRatio=\"auto\"\n (imageSelectionEvent)=\"onImageSelection($event)\"\n (closeEvent)=\"onClose()\">\n </pw-image-cropper>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [".card .mb-2:last-child,.card .mb-3:last-child{margin-bottom:0!important}.overlay{left:50%;opacity:0;position:absolute;text-align:center;top:50%;transform:translate(-50%,-50%);transition:.5s ease}.image-container{position:relative}.image-container:hover .image{opacity:.3}.image-container:hover .overlay{opacity:0}.overlay-text{background:#f0efef80;border-radius:50%;color:#000;font-size:16px;height:150px;line-height:150px;text-align:center;vertical-align:middle;width:150px}@media screen and (max-width:767px){.card-body{padding:20px!important}}\n"], dependencies: [{ kind: "directive", type: i3.ButtonBusyDirective, selector: "[buttonBusy]", inputs: ["buttonBusy", "busyText"] }, { kind: "directive", type: i3.LazyImgDirective, selector: "img" }, { kind: "directive", type: i8.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i7.NgxGpAutocompleteDirective, selector: "[ngx-gp-autocomplete]", inputs: ["options"], outputs: ["onAddressChange"], exportAs: ["ngx-places"] }, { kind: "component", type: i8$1.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i10.ProfileImageCropperComponent, selector: "pw-image-cropper", inputs: ["aspectRatio", "dynamicData"], outputs: ["imageSelectionEvent", "closeEvent", "fileChangeEvent"] }, { kind: "component", type: i5.InputContainerComponent, selector: "pw-input-container", inputs: ["name", "controlId", "useAriaLabelledbyOnly", "label", "labelClass", "tooltipPosition", "required", "errorMsg", "isReadOnly", "showTooltip", "tooltipText", "showTriangle", "afterLabel", "showAfterLabel", "showTriangleText", "isLeftTooltip"] }, { kind: "directive", type: i11.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "directive", type: i1$1.NgbInputDatepicker, selector: "input[ngbDatepicker]", inputs: ["autoClose", "contentTemplate", "datepickerClass", "dayTemplate", "dayTemplateData", "displayMonths", "firstDayOfWeek", "footerTemplate", "markDisabled", "minDate", "maxDate", "navigation", "outsideDays", "placement", "popperOptions", "restoreFocus", "showWeekNumbers", "startDate", "container", "positionTarget", "weekdays", "disabled"], outputs: ["dateSelect", "navigate", "closed"], exportAs: ["ngbDatepicker"] }, { kind: "pipe", type: i8.AsyncPipe, name: "async" }, { kind: "pipe", type: i8.DecimalPipe, name: "number" }, { kind: "pipe", type: i8$2.TranslocoPipe, name: "transloco" }] }); }
|
|
478
479
|
}
|
|
479
480
|
__decorate([
|
|
480
481
|
ValidateForm('profileForm'),
|
|
@@ -484,8 +485,8 @@ __decorate([
|
|
|
484
485
|
], AccountDetailsComponent.prototype, "onProfileFormSubmit", null);
|
|
485
486
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: AccountDetailsComponent, decorators: [{
|
|
486
487
|
type: Component,
|
|
487
|
-
args: [{ selector: 'pw-account-details', standalone: false, template: "<div class=\"w-100 text-center\">\n @if (!isLoaded) {\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n }\n</div>\n<div class=\"row gx-3 mb-3\">\n <div class=\"col-md-4\">\n <section class=\"card p-4 h-100 d-flex flex-column\">\n <h2>{{ 'User.Profile.Avatar' | transloco }}</h2>\n <div class=\"text-center d-flex flex-column justify-content-center flex-grow-1 mt-1\">\n <div class=\"image-container\">\n <img [src]=\"image\"\n width=\"150\"\n height=\"150\"\n class=\"image rounded-circle\"\n alt=\"User Male\"\n (error)=\"handleImageError($event, 'assets/img/icons/male.png')\" />\n <div class=\"overlay\"\n (keydown.enter)=\"openModal(content)\"\n (click)=\"openModal(content)\">\n <div class=\"overlay-text\">{{ 'User.Profile.Change' | transloco }}</div>\n </div>\n </div>\n <h4 class=\"mt-2\">{{ user?.first_name }} {{ user?.last_name }}</h4>\n <a aria-label=\"Navigate to Target\"\n class=\"d-inline-block mb-2\"\n (click)=\"openModal(content)\">\n {{ 'User.Profile.EditAvatar' | transloco }}</a>\n </div>\n </section>\n </div>\n <div class=\"col-md-8\">\n <section id=\"user-profile\"\n class=\"card p-4 overflow-visible h-100\">\n <form [formGroup]=\"profileForm\"\n (ngSubmit)=\"onProfileFormSubmit()\">\n <h2>{{ 'User.Profile.UserProfile' | transloco }}</h2>\n <div class=\"row mt-3\">\n <div class=\"col-sm-12 col-md-6 col-lg-6\">\n <pw-input-container label=\"First Name\"\n name=\"first_name\"\n controlId=\"account-first_name\"\n errorMsg=\"Please enter first Name\">\n <input type=\"text\"\n id=\"account-first_name\"\n class=\"form-control\"\n formControlName=\"first_name\"\n autocomplete=\"given-name\" name=\"input_first_name_9\"/>\n </pw-input-container>\n <pw-input-container label=\"Preferred name\"\n name=\"preferred_name\"\n controlId=\"account-preferred_name\"\n errorMsg=\"Please enter preferred Name\">\n <input type=\"text\"\n id=\"account-preferred_name\"\n class=\"form-control\"\n formControlName=\"preferred_name\"\n autocomplete=\"username\" name=\"input_preferred_name_10\"/>\n </pw-input-container>\n @if (countries$ | async; as countries) {\n <pw-input-container label=\"Country\"\n name=\"country\"\n controlId=\"account-country\"\n [useAriaLabelledbyOnly]=\"true\"\n errorMsg=\"Please select a country\">\n <p-select\n [attr.aria-labelledby]=\"'account-country-label'\"\n [options]=\"countries\"\n optionLabel=\"name\"\n optionValue=\"code\"\n formControlName=\"country\"\n (onChange)=\"getRegion($event.value)\"\n placeholder=\"{{ 'User.Profile.SelectCountry' | transloco }}\">\n </p-select>\n </pw-input-container>\n }\n <pw-input-container label=\"Province\"\n name=\"province\"\n controlId=\"account-province\"\n errorMsg=\"Please enter province\">\n <input type=\"text\"\n id=\"account-province\"\n class=\"form-control\"\n formControlName=\"province\"\n autocomplete=\"postal-code\" name=\"input_province_11\"/>\n </pw-input-container>\n <pw-input-container label=\"Website Url\"\n name=\"website_url\"\n controlId=\"account-website_url\"\n errorMsg=\"Please enter Website\">\n <input type=\"text\"\n id=\"account-website_url\"\n class=\"form-control\"\n formControlName=\"website_url\"\n autocomplete=\"url\" name=\"input_website_url_12\"/>\n </pw-input-container>\n </div>\n <div class=\"col-sm-12 col-md-6 col-lg-6\">\n <pw-input-container label=\"Last Name\"\n name=\"last_name\"\n controlId=\"account-last_name\"\n errorMsg=\"Please enter last Name\">\n <input type=\"text\"\n id=\"account-last_name\"\n class=\"form-control\"\n formControlName=\"last_name\"\n autocomplete=\"family-name\" name=\"input_last_name_13\"/>\n </pw-input-container>\n <pw-input-container label=\"Date of Birth\"\n name=\"dob\"\n controlId=\"account-dob\"\n errorMsg=\"Please enter date of birth\">\n <div class=\"input-group\">\n <input class=\"form-control\"\n id=\"account-dob\"\n name=\"dob\"\n placeholder=\"dd-mmm-yyyy\"\n formControlName=\"dob\"\n ngbDatepicker\n #d=\"ngbDatepicker\"\n [minDate]=\"{ day: 1, month: 1, year: 1950 }\"\n [maxDate]=\"{ day: 31, month: 12, year: 2018 }\" />\n <button class=\"btn btn-primary\"\n type=\"button\"\n id=\"account-dob-trigger\"\n aria-label=\"Open date picker for date of birth\"\n (click)=\"d.toggle()\">\n <i class=\"fa fa-calendar\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </pw-input-container>\n <pw-input-container label=\"State\"\n name=\"state\"\n controlId=\"account-state\"\n [useAriaLabelledbyOnly]=\"true\"\n errorMsg=\"Please select a state\">\n <p-select\n [attr.aria-labelledby]=\"'account-state-label'\"\n [options]=\"states\"\n [(ngModel)]=\"selectedState\"\n optionLabel=\"name\"\n optionValue=\"code\"\n formControlName=\"state\"\n [placeholder]=\"'User.Profile.SelectState' | transloco\">\n </p-select>\n </pw-input-container>\n <pw-input-container label=\"Location\"\n name=\"location\"\n controlId=\"account-location\"\n [useAriaLabelledbyOnly]=\"true\">\n <input ngx-gp-autocomplete\n id=\"account-location\"\n name=\"location\"\n class=\"form-control\"\n [attr.aria-labelledby]=\"'account-location-label'\"\n #places=\"ngx-places\"\n formControlName=\"location\"\n (onAddressChange)=\"handleAddressChange($event)\" />\n </pw-input-container>\n <pw-input-container label=\"Phone Number\"\n name=\"phone_number\"\n controlId=\"account-phone_number\"\n errorMsg=\"Please enter phone number\">\n <input type=\"text\"\n id=\"account-phone_number\"\n class=\"form-control\"\n formControlName=\"phone_number\"\n autocomplete=\"tel\" name=\"input_phone_number_16\"/>\n </pw-input-container>\n </div>\n <div class=\"col-12 text-end\">\n <div class=\"mb-3\">\n <button class=\"btn btn-raised btn-primary\" [buttonBusy]=\"profileBusyButton\">\n {{ 'Button.Save' | transloco }}\n </button>\n </div>\n </div>\n </div>\n </form>\n </section>\n </div>\n</div>\n<div class=\"row gx-3 mb-3\">\n <div class=\"col-md-6\">\n <section id=\"email-section\"\n class=\"card p-4 h-100\">\n <div class=\"row\">\n <div class=\"col-12\">\n <h2>{{ 'User.Account.RegisteredEmail' | transloco }}</h2>\n <section id=\"email-form\">\n <form [formGroup]=\"emailForm\"\n (ngSubmit)=\"onEmailFormSubmit()\">\n <!-- Email Address -->\n <div class=\"mt-0\">\n <span id=\"account-primary-email-label\" class=\"me-3 pw-label-style\">{{ 'User.Account.PrimaryEmail' | transloco }}:\n </span>\n <strong>{{ validatedEmail }}</strong>\n <div class=\"mt-1\">\n @if (!toggleEmail) {\n <a class=\"btn btn-raised btn-outline-primary\"\n aria-label=\"Navigate to Target\"\n (click)=\"shouldUserChangeEmail()\">\n {{ 'User.Account.ChangeEmail' | transloco }}</a>\n }\n @if (toggleEmail) {\n <div class=\"row\">\n <div class=\"clearfix\"></div>\n <div class=\"col-12 mb-3\">\n @if (!passwordVerified) {\n <input type=\"password\"\n class=\"form-control\"\n id=\"account-email-current-password\"\n name=\"currentPassword\"\n #password\n placeholder=\"Current Password\"\n autocomplete=\"current-password\"\n (keyup)=\"checkValidity()\" />\n }\n @if (passwordVerified) {\n <input type=\"text\"\n class=\"form-control\"\n id=\"account-new-email\"\n name=\"newEmail\"\n placeholder=\"New Email\"\n autocomplete=\"email\"\n formControlName=\"email\" />\n }\n </div>\n <div class=\"col-12\">\n @if (toggleEmail) {\n <a\n class=\"btn btn-raised btn-outline-default my-2 me-2\"\n aria-label=\"Navigate to Target\"\n (click)=\"onToggleEmail()\">{{ 'Button.Cancel' | transloco }}</a>\n }\n @if (!passwordVerified) {\n <button class=\"btn btn-raised btn-primary\"\n type=\"submit\"\n [buttonBusy]=\"validatePasswordBusyButton\"\n (click)=\"validatePassword()\"\n [disabled]=\"isCurrentPasswordValid\">\n {{ 'User.Account.Validate' | transloco }}\n </button>\n }\n @if (passwordVerified) {\n <button type=\"submit\"\n class=\"btn btn-raised btn-primary\"\n [buttonBusy]=\"emailBusyButton\"\n >\n {{\n 'User.Account.SendVerification' | transloco\n }}\n </button>\n }\n </div>\n </div>\n }\n </div>\n </div>\n <section id=\"slug\"\n class=\"mb-2 mt-3\">\n <div>\n <span class=\"me-3 pw-label-style\" id=\"account-nickname-label\">{{ 'User.Account.NickName' | transloco }}:</span>\n <span class=\"tooltip-wrap me-3\" [pTooltip]=\"'User.Account.HandleTooltip' | transloco\" [appendTo]=\"'body'\" tooltipPosition=\"top\"><i class=\"far fa-info-circle text-muted\"></i></span>\n <strong>{{ slug }}</strong>\n <div class=\"mt-1\">\n @if (!toggleNickName) {\n <a class=\"btn btn-raised btn-outline-primary me-2\"\n aria-label=\"Navigate to Target\"\n (click)=\"toggleNickName = true\">\n {{ 'User.Account.ChangeNickname' | transloco }}</a>\n }\n @if (toggleNickName) {\n <div class=\"mb-3\">\n <input type=\"text\"\n id=\"account-nickname\"\n name=\"nickname\"\n class=\"form-control slug-input\"\n aria-labelledby=\"account-nickname-label\"\n [(ngModel)]=\"slug\"\n [ngModelOptions]=\"{ standalone: true }\" />\n </div>\n <div>\n <button type=\"button\"\n class=\"btn btn-raised btn-outline-default\"\n (click)=\"toggleNickName = false\">\n {{ 'Button.Cancel' | transloco }}\n </button>\n <button type=\"button\"\n class=\"btn btn-raised btn-primary ms-2\"\n [buttonBusy]=\"slugBusyButton\"\n [disabled]=\"slug?.length < 2\"\n (click)=\"onUpdateSlug()\">\n {{ 'User.Account.UpdateNickname' | transloco }}\n </button>\n </div>\n }\n </div>\n </div>\n </section>\n </form>\n </section>\n </div>\n </div>\n </section>\n </div>\n <div class=\"col-md-6\">\n <section id=\"password-change\"\n class=\"card p-4 h-100\">\n <form [formGroup]=\"passwordForm\"\n (ngSubmit)=\"onPasswordFormSubmit()\">\n <div class=\"row\">\n <div class=\"col-12\">\n <h2>{{ 'User.Account.ChangePassword' | transloco }}</h2>\n </div>\n @if (!user?.has_password) {\n <div class=\"text-danger mx-3 my-2\">\n <div>\n You don't have a password set, click on\n <em>{{ 'User.Account.ChangePassword' | transloco }}</em>.\n </div>\n <div>{{ 'User.Profile.PictureMessage' | transloco }}</div>\n </div>\n }\n @if (user?.has_password) {\n <div class=\"col-12\"\n >\n @if (togglePassword) {\n <div class=\"mb-3\">\n <label for=\"account-current-password\">{{ 'User.Account.CurrentPassword' | transloco }}</label>\n <input type=\"password\"\n id=\"account-current-password\"\n class=\"form-control\"\n formControlName=\"currentPassword\"\n autocomplete=\"current-password\" name=\"input_currentPassword_4\"/>\n @if (\n !passwordForm.get('currentPassword').valid &&\n (passwordForm.get('currentPassword').dirty ||\n passwordForm.get('currentPassword').touched)\n ) {\n <small class=\"form-text text-muted danger\"\n >\n {{ 'User.Account.Required' | transloco }}\n </small>\n }\n </div>\n <div class=\"mb-3\">\n <label for=\"account-new-password\">{{ 'User.Account.NewPassword' | transloco }}</label>\n <input type=\"password\"\n id=\"account-new-password\"\n class=\"form-control\"\n formControlName=\"newPassword\"\n autocomplete=\"new-password\" name=\"input_newPassword_5\"/>\n @if (\n !passwordForm.get('newPassword').valid &&\n (passwordForm.get('newPassword').dirty ||\n passwordForm.get('newPassword').touched)\n ) {\n <small class=\"form-text text-muted danger\"\n >{{ 'User.Account.Validation.StrongPassword' | transloco }}\n </small>\n }\n </div>\n <div class=\"mb-3\">\n <label for=\"account-confirm-password\">{{\n 'User.Account.ConfirmPassword' | transloco\n }}</label>\n <input type=\"password\"\n id=\"account-confirm-password\"\n class=\"form-control\"\n formControlName=\"confirmPassword\"\n autocomplete=\"new-password\" name=\"input_confirmPassword_6\"/>\n @if (\n passwordForm.get('confirmPassword').touched &&\n passwordForm.get('confirmPassword').errors\n ?.MatchPassword\n ) {\n <div class=\"text-danger\"\n >\n {{ 'User.Account.Validation.PasswordsMatch' | transloco }}\n </div>\n }\n </div>\n <div class=\"mb-3\">\n @if (togglePassword) {\n <a class=\"btn btn-raised btn-outline-default\"\n aria-label=\"Navigate to Target\"\n data-bs-target=\"\"\n (click)=\"onTogglePassword()\">\n {{ 'Button.Cancel' | transloco }}</a>\n }\n <button class=\"btn btn-raised btn-primary ms-2\"\n [buttonBusy]=\"passwordBusyButton\"\n [disabled]=\"!passwordForm.valid\">\n {{ 'User.Account.UpdatePassword' | transloco }}\n </button>\n </div>\n }\n <div>\n @if (!togglePassword) {\n <a class=\"btn btn-raised btn-outline-primary\"\n aria-label=\"Navigate to Target\"\n data-bs-target=\"\"\n (click)=\"togglePassword = !togglePassword\">\n {{ 'User.Account.ChangePassword' | transloco }}</a>\n }\n </div>\n </div>\n }\n @if (!user?.has_password) {\n <div class=\"col-12\"\n >\n <a class=\"btn btn-raised btn-primary me-2\"\n aria-label=\"Navigate to Target\"\n data-bs-target=\"\"\n (click)=\"sendMailToResetPassword()\">\n {{ 'User.Account.ChangePassword' | transloco }}</a>\n </div>\n }\n </div>\n </form>\n </section>\n </div>\n @if (user?.api_keys?.api_hits_max > 0) {\n <div class=\"col-12 mt-3\">\n <section id=\"api-credentials\"\n class=\"card p-4 h-auto\">\n <div class=\"row\">\n <div class=\"col-12\">\n <h2>{{ 'User.Subscriptions.APICredentials.Title' | transloco }}</h2>\n <p>\n {{ 'User.Subscriptions.APICredentials.Description' | transloco }}\n </p>\n <!-- pb (not mb): .card .mb-3:last-child is margin-reset in this component's scss -->\n <p class=\"text-muted small mb-0 pb-3\">\n <i class=\"fas fa-info-circle me-1\"></i>\n {{ 'User.Subscriptions.APICredentials.SubscriptionClientIdNote' | transloco }}\n </p>\n </div>\n <div class=\"col-12 col-md-6\">\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"account-api-token\">{{ 'User.Account.APIUserToken' | transloco }}</label>\n <div class=\"input-group\">\n <input type=\"text\"\n id=\"account-api-token\"\n name=\"api_token\"\n class=\"form-control\"\n [value]=\"showApiToken ? user?.api_keys?.api_user_token || ('User.Subscriptions.APICredentials.NoTokenAvailable' | transloco) : '*************************'\"\n readonly />\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"toggleApiTokenVisibility()\">\n {{ showApiToken ? ('User.Subscriptions.APICredentials.Hide' | transloco) : ('User.Subscriptions.APICredentials.View' | transloco) }}\n </button>\n </div>\n </div>\n </div>\n <div class=\"col-12 col-md-6\">\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"account-api-client-id\">{{ 'User.Account.APIUserId' | transloco }}</label>\n <div class=\"input-group\">\n <input type=\"text\"\n id=\"account-api-client-id\"\n name=\"api_client_id\"\n class=\"form-control\"\n [value]=\"showApiClientId ? user?.api_keys?.api_user_id || ('User.Subscriptions.APICredentials.NoClientIdAvailable' | transloco) : '*************************'\"\n readonly />\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"toggleApiClientIdVisibility()\">\n {{ showApiClientId ? ('User.Subscriptions.APICredentials.Hide' | transloco) : ('User.Subscriptions.APICredentials.View' | transloco) }}\n </button>\n </div>\n </div>\n </div>\n <div class=\"col-12 mt-3\">\n <div class=\"d-flex align-items-center gap-3\">\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"refreshApiTokens()\"\n [disabled]=\"refreshingTokens\">\n <i class=\"fas fa-sync-alt me-2\" [class.fa-spin]=\"refreshingTokens\"></i>\n {{ refreshingTokens ? ('User.Subscriptions.APICredentials.Refreshing' | transloco) : ('User.Subscriptions.APICredentials.RefreshTokens' | transloco) }}\n </button>\n <div class=\"d-flex align-items-center gap-2\">\n @if (user?.api_keys?.api_hits !== null) {\n <span class=\"text-muted\">{{ 'User.Subscriptions.APICredentials.ApiHits' | transloco }}:</span>\n <span class=\"fw-bold\">{{ user.api_keys.api_hits | number }}</span>\n }\n @if (user?.api_keys?.api_hits_max !== null) {\n <span class=\"text-muted\">{{ 'User.Subscriptions.APICredentials.ApiHitsMax' | transloco }}:</span>\n <span class=\"fw-bold\">{{ user.api_keys.api_hits_max | number }}</span>\n }\n <!-- Show utilization percentage when both values exist -->\n @if (user?.api_keys?.api_hits !== null && user?.api_keys?.api_hits_max !== null && user?.api_keys?.api_hits_max > 0) {\n <span class=\"text-muted ms-2\">(</span>\n <span class=\"fw-bold\" [ngClass]=\"{\n 'text-success': (user.api_keys.api_hits / user.api_keys.api_hits_max) <= 0.8,\n 'text-warning': (user.api_keys.api_hits / user.api_keys.api_hits_max) > 0.8 && (user.api_keys.api_hits / user.api_keys.api_hits_max) <= 0.9,\n 'text-danger': (user.api_keys.api_hits / user.api_keys.api_hits_max) > 0.9\n }\">\n {{ (user.api_keys.api_hits / user.api_keys.api_hits_max * 100) | number:'1.0-0' }}% consumed\n </span>\n <span class=\"text-muted\">)</span>\n }\n </div>\n </div>\n </div>\n </div>\n </section>\n </div>\n }\n</div>\n<ng-template #content\n let-modal>\n <div class=\"card m-0\">\n <div class=\"card-content\">\n <div class=\"card-title\">\n <h3 class=\"modal-title\">{{ 'User.Profile.ProfilePicture' | transloco }}</h3>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n </button>\n </div>\n <div class=\"card-header\">\n <small> {{ 'User.Profile.PictureMessage' | transloco }}</small>\n <pw-image-cropper #profile\n aspectRatio=\"auto\"\n (imageSelectionEvent)=\"onImageSelection($event)\"\n (closeEvent)=\"onClose()\">\n </pw-image-cropper>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [".card .mb-2:last-child,.card .mb-3:last-child{margin-bottom:0!important}.overlay{left:50%;opacity:0;position:absolute;text-align:center;top:50%;transform:translate(-50%,-50%);transition:.5s ease}.image-container{position:relative}.image-container:hover .image{opacity:.3}.image-container:hover .overlay{opacity:0}.overlay-text{background:#f0efef80;border-radius:50%;color:#000;font-size:16px;height:150px;line-height:150px;text-align:center;vertical-align:middle;width:150px}@media screen and (max-width:767px){.card-body{padding:20px!important}}\n"] }]
|
|
488
|
-
}], ctorParameters: () => [{ type: i2.UntypedFormBuilder }, { type: i1$1.NgbModal }, { type: i1$2.AuthService }, { type: i1$2.GeoService }, { type: i1$2.ProfileService }, { type: i0.Injector }, { type: i0.ChangeDetectorRef }], propDecorators: { placesRef: [{
|
|
488
|
+
args: [{ selector: 'pw-account-details', standalone: false, template: "<div class=\"w-100 text-center\">\n @if (!isLoaded) {\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n }\n</div>\n<div class=\"row gx-3 mb-3\">\n <div class=\"col-md-4\">\n <section class=\"card p-4 h-100 d-flex flex-column\">\n <h2>{{ 'User.Profile.Avatar' | transloco }}</h2>\n <div class=\"text-center d-flex flex-column justify-content-center flex-grow-1 mt-1\">\n <div class=\"image-container\">\n <img [src]=\"image\"\n width=\"150\"\n height=\"150\"\n class=\"image rounded-circle\"\n alt=\"User Male\"\n (error)=\"handleImageError($event, 'assets/img/icons/male.png')\" />\n <div class=\"overlay\"\n (keydown.enter)=\"openModal(content)\"\n (click)=\"openModal(content)\">\n <div class=\"overlay-text\">{{ 'User.Profile.Change' | transloco }}</div>\n </div>\n </div>\n <h4 class=\"mt-2\">{{ user?.first_name }} {{ user?.last_name }}</h4>\n <a aria-label=\"Navigate to Target\"\n class=\"d-inline-block mb-2\"\n (click)=\"openModal(content)\">\n {{ 'User.Profile.EditAvatar' | transloco }}</a>\n </div>\n </section>\n </div>\n <div class=\"col-md-8\">\n <section id=\"user-profile\"\n class=\"card p-4 overflow-visible h-100\">\n <form [formGroup]=\"profileForm\"\n (ngSubmit)=\"onProfileFormSubmit()\">\n <h2>{{ 'User.Profile.UserProfile' | transloco }}</h2>\n <div class=\"row mt-3\">\n <div class=\"col-sm-12 col-md-6 col-lg-6\">\n <pw-input-container label=\"First Name\"\n name=\"first_name\"\n controlId=\"account-first_name\"\n errorMsg=\"Please enter first Name\">\n <input type=\"text\"\n id=\"account-first_name\"\n class=\"form-control\"\n formControlName=\"first_name\"\n autocomplete=\"given-name\" name=\"input_first_name_9\"/>\n </pw-input-container>\n <pw-input-container label=\"Preferred name\"\n name=\"preferred_name\"\n controlId=\"account-preferred_name\"\n errorMsg=\"Please enter preferred Name\">\n <input type=\"text\"\n id=\"account-preferred_name\"\n class=\"form-control\"\n formControlName=\"preferred_name\"\n autocomplete=\"username\" name=\"input_preferred_name_10\"/>\n </pw-input-container>\n @if (countries$ | async; as countries) {\n <pw-input-container label=\"Country\"\n name=\"country\"\n controlId=\"account-country\"\n [useAriaLabelledbyOnly]=\"true\"\n errorMsg=\"Please select a country\">\n <p-select\n [attr.aria-labelledby]=\"'account-country-label'\"\n [options]=\"countries\"\n optionLabel=\"name\"\n optionValue=\"code\"\n formControlName=\"country\"\n (onChange)=\"getRegion($event.value)\"\n placeholder=\"{{ 'User.Profile.SelectCountry' | transloco }}\">\n </p-select>\n </pw-input-container>\n }\n <pw-input-container label=\"Province\"\n name=\"province\"\n controlId=\"account-province\"\n errorMsg=\"Please enter province\">\n <input type=\"text\"\n id=\"account-province\"\n class=\"form-control\"\n formControlName=\"province\"\n autocomplete=\"postal-code\" name=\"input_province_11\"/>\n </pw-input-container>\n <pw-input-container label=\"Website Url\"\n name=\"website_url\"\n controlId=\"account-website_url\"\n errorMsg=\"Please enter Website\">\n <input type=\"text\"\n id=\"account-website_url\"\n class=\"form-control\"\n formControlName=\"website_url\"\n autocomplete=\"url\" name=\"input_website_url_12\"/>\n </pw-input-container>\n </div>\n <div class=\"col-sm-12 col-md-6 col-lg-6\">\n <pw-input-container label=\"Last Name\"\n name=\"last_name\"\n controlId=\"account-last_name\"\n errorMsg=\"Please enter last Name\">\n <input type=\"text\"\n id=\"account-last_name\"\n class=\"form-control\"\n formControlName=\"last_name\"\n autocomplete=\"family-name\" name=\"input_last_name_13\"/>\n </pw-input-container>\n <pw-input-container label=\"Date of Birth\"\n name=\"dob\"\n controlId=\"account-dob\"\n errorMsg=\"Please enter date of birth\">\n <div class=\"input-group\">\n <input class=\"form-control\"\n id=\"account-dob\"\n name=\"dob\"\n placeholder=\"dd-mmm-yyyy\"\n formControlName=\"dob\"\n ngbDatepicker\n #d=\"ngbDatepicker\"\n [minDate]=\"{ day: 1, month: 1, year: 1950 }\"\n [maxDate]=\"{ day: 31, month: 12, year: 2018 }\" />\n <button class=\"btn btn-primary\"\n type=\"button\"\n id=\"account-dob-trigger\"\n aria-label=\"Open date picker for date of birth\"\n (click)=\"d.toggle()\">\n <i class=\"fa fa-calendar\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </pw-input-container>\n <pw-input-container label=\"State\"\n name=\"state\"\n controlId=\"account-state\"\n [useAriaLabelledbyOnly]=\"true\"\n errorMsg=\"Please select a state\">\n <p-select\n [attr.aria-labelledby]=\"'account-state-label'\"\n [options]=\"states\"\n [(ngModel)]=\"selectedState\"\n optionLabel=\"name\"\n optionValue=\"code\"\n formControlName=\"state\"\n [placeholder]=\"'User.Profile.SelectState' | transloco\">\n </p-select>\n </pw-input-container>\n <pw-input-container label=\"Location\"\n name=\"location\"\n controlId=\"account-location\"\n [useAriaLabelledbyOnly]=\"true\">\n <input ngx-gp-autocomplete\n id=\"account-location\"\n name=\"location\"\n class=\"form-control\"\n [attr.aria-labelledby]=\"'account-location-label'\"\n #places=\"ngx-places\"\n formControlName=\"location\"\n (onAddressChange)=\"handleAddressChange($event)\" />\n </pw-input-container>\n <pw-input-container label=\"Phone Number\"\n name=\"phone_number\"\n controlId=\"account-phone_number\"\n errorMsg=\"Please enter phone number\">\n <input type=\"text\"\n id=\"account-phone_number\"\n class=\"form-control\"\n formControlName=\"phone_number\"\n autocomplete=\"tel\" name=\"input_phone_number_16\"/>\n </pw-input-container>\n </div>\n <div class=\"col-12 text-end\">\n <div class=\"mb-3\">\n <button class=\"btn btn-raised btn-primary\" [buttonBusy]=\"profileBusyButton\">\n {{ 'Button.Save' | transloco }}\n </button>\n </div>\n </div>\n </div>\n </form>\n </section>\n </div>\n</div>\n<div class=\"row gx-3 mb-3\">\n <div class=\"col-md-6\">\n <section id=\"email-section\"\n class=\"card p-4 h-100\">\n <div class=\"row\">\n <div class=\"col-12\">\n <h2>{{ 'User.Account.RegisteredEmail' | transloco }}</h2>\n <section id=\"email-form\">\n <form [formGroup]=\"emailForm\"\n (ngSubmit)=\"onEmailFormSubmit()\">\n <!-- Email Address -->\n <div class=\"mt-0\">\n <span id=\"account-primary-email-label\" class=\"me-3 pw-label-style\">{{ 'User.Account.PrimaryEmail' | transloco }}:\n </span>\n <strong>{{ validatedEmail }}</strong>\n <div class=\"mt-1\">\n @if (!toggleEmail) {\n <a class=\"btn btn-raised btn-outline-primary\"\n aria-label=\"Navigate to Target\"\n (click)=\"shouldUserChangeEmail()\">\n {{ 'User.Account.ChangeEmail' | transloco }}</a>\n }\n @if (toggleEmail) {\n <div class=\"row\">\n <div class=\"clearfix\"></div>\n <div class=\"col-12 mb-3\">\n @if (!passwordVerified) {\n <input type=\"password\"\n class=\"form-control\"\n id=\"account-email-current-password\"\n name=\"currentPassword\"\n #password\n placeholder=\"Current Password\"\n autocomplete=\"current-password\"\n (keyup)=\"checkValidity()\" />\n }\n @if (passwordVerified) {\n <input type=\"text\"\n class=\"form-control\"\n id=\"account-new-email\"\n name=\"newEmail\"\n placeholder=\"New Email\"\n autocomplete=\"email\"\n formControlName=\"email\" />\n }\n </div>\n <div class=\"col-12\">\n @if (toggleEmail) {\n <a\n class=\"btn btn-raised btn-outline-default my-2 me-2\"\n aria-label=\"Navigate to Target\"\n (click)=\"onToggleEmail()\">{{ 'Button.Cancel' | transloco }}</a>\n }\n @if (!passwordVerified) {\n <button class=\"btn btn-raised btn-primary\"\n type=\"submit\"\n [buttonBusy]=\"validatePasswordBusyButton\"\n (click)=\"validatePassword()\"\n [disabled]=\"isCurrentPasswordValid\">\n {{ 'User.Account.Validate' | transloco }}\n </button>\n }\n @if (passwordVerified) {\n <button type=\"submit\"\n class=\"btn btn-raised btn-primary\"\n [buttonBusy]=\"emailBusyButton\"\n >\n {{\n 'User.Account.SendVerification' | transloco\n }}\n </button>\n }\n </div>\n </div>\n }\n </div>\n </div>\n <section id=\"slug\"\n class=\"mb-2 mt-3\">\n <div>\n <span class=\"me-3 pw-label-style\" id=\"account-nickname-label\">{{ 'User.Account.NickName' | transloco }}:</span>\n <span class=\"tooltip-wrap me-3\" [pTooltip]=\"'User.Account.HandleTooltip' | transloco\" [appendTo]=\"'body'\" tooltipPosition=\"top\"><i class=\"far fa-info-circle text-muted\"></i></span>\n <strong>{{ slug }}</strong>\n <div class=\"mt-1\">\n @if (!toggleNickName) {\n <a class=\"btn btn-raised btn-outline-primary me-2\"\n aria-label=\"Navigate to Target\"\n (click)=\"toggleNickName = true\">\n {{ 'User.Account.ChangeNickname' | transloco }}</a>\n }\n @if (toggleNickName) {\n <div class=\"mb-3\">\n <input type=\"text\"\n id=\"account-nickname\"\n name=\"nickname\"\n class=\"form-control slug-input\"\n aria-labelledby=\"account-nickname-label\"\n [(ngModel)]=\"slug\"\n [ngModelOptions]=\"{ standalone: true }\" />\n </div>\n <div>\n <button type=\"button\"\n class=\"btn btn-raised btn-outline-default\"\n (click)=\"toggleNickName = false\">\n {{ 'Button.Cancel' | transloco }}\n </button>\n <button type=\"button\"\n class=\"btn btn-raised btn-primary ms-2\"\n [buttonBusy]=\"slugBusyButton\"\n [disabled]=\"slug?.length < 2\"\n (click)=\"onUpdateSlug()\">\n {{ 'User.Account.UpdateNickname' | transloco }}\n </button>\n </div>\n }\n </div>\n </div>\n </section>\n </form>\n </section>\n </div>\n </div>\n </section>\n </div>\n <div class=\"col-md-6\">\n <section id=\"password-change\"\n class=\"card p-4 h-100\">\n <form [formGroup]=\"passwordForm\"\n (ngSubmit)=\"onPasswordFormSubmit()\">\n <div class=\"row\">\n <div class=\"col-12\">\n <h2>{{ 'User.Account.ChangePassword' | transloco }}</h2>\n </div>\n @if (!user?.has_password) {\n <div class=\"text-danger mx-3 my-2\">\n <div>\n You don't have a password set, click on\n <em>{{ 'User.Account.ChangePassword' | transloco }}</em>.\n </div>\n <div>{{ 'User.Profile.PictureMessage' | transloco }}</div>\n </div>\n }\n @if (user?.has_password) {\n <div class=\"col-12\"\n >\n @if (togglePassword) {\n <div class=\"mb-3\">\n <label for=\"account-current-password\">{{ 'User.Account.CurrentPassword' | transloco }}</label>\n <input type=\"password\"\n id=\"account-current-password\"\n class=\"form-control\"\n formControlName=\"currentPassword\"\n autocomplete=\"current-password\" name=\"input_currentPassword_4\"/>\n @if (\n !passwordForm.get('currentPassword').valid &&\n (passwordForm.get('currentPassword').dirty ||\n passwordForm.get('currentPassword').touched)\n ) {\n <small class=\"form-text text-muted danger\"\n >\n {{ 'User.Account.Required' | transloco }}\n </small>\n }\n </div>\n <div class=\"mb-3\">\n <label for=\"account-new-password\">{{ 'User.Account.NewPassword' | transloco }}</label>\n <input type=\"password\"\n id=\"account-new-password\"\n class=\"form-control\"\n formControlName=\"newPassword\"\n autocomplete=\"new-password\" name=\"input_newPassword_5\"/>\n @if (\n !passwordForm.get('newPassword').valid &&\n (passwordForm.get('newPassword').dirty ||\n passwordForm.get('newPassword').touched)\n ) {\n <small class=\"form-text text-muted danger\"\n >{{ 'User.Account.Validation.StrongPassword' | transloco }}\n </small>\n }\n </div>\n <div class=\"mb-3\">\n <label for=\"account-confirm-password\">{{\n 'User.Account.ConfirmPassword' | transloco\n }}</label>\n <input type=\"password\"\n id=\"account-confirm-password\"\n class=\"form-control\"\n formControlName=\"confirmPassword\"\n autocomplete=\"new-password\" name=\"input_confirmPassword_6\"/>\n @if (\n passwordForm.get('confirmPassword').touched &&\n passwordForm.get('confirmPassword').errors\n ?.MatchPassword\n ) {\n <div class=\"text-danger\"\n >\n {{ 'User.Account.Validation.PasswordsMatch' | transloco }}\n </div>\n }\n </div>\n <div class=\"mb-3\">\n @if (togglePassword) {\n <a class=\"btn btn-raised btn-outline-default\"\n aria-label=\"Navigate to Target\"\n data-bs-target=\"\"\n (click)=\"onTogglePassword()\">\n {{ 'Button.Cancel' | transloco }}</a>\n }\n <button class=\"btn btn-raised btn-primary ms-2\"\n [buttonBusy]=\"passwordBusyButton\"\n [disabled]=\"!passwordForm.valid\">\n {{ 'User.Account.UpdatePassword' | transloco }}\n </button>\n </div>\n }\n <div>\n @if (!togglePassword) {\n <a class=\"btn btn-raised btn-outline-primary\"\n aria-label=\"Navigate to Target\"\n data-bs-target=\"\"\n (click)=\"togglePassword = !togglePassword\">\n {{ 'User.Account.ChangePassword' | transloco }}</a>\n }\n </div>\n </div>\n }\n @if (!user?.has_password) {\n <div class=\"col-12\"\n >\n <a class=\"btn btn-raised btn-primary me-2\"\n aria-label=\"Navigate to Target\"\n data-bs-target=\"\"\n (click)=\"sendMailToResetPassword()\">\n {{ 'User.Account.ChangePassword' | transloco }}</a>\n </div>\n }\n </div>\n </form>\n </section>\n </div>\n @if (user?.api_keys?.api_hits_max > 0) {\n <div class=\"col-12 mt-3\">\n <section id=\"api-credentials\"\n class=\"card p-4 h-auto\">\n <div class=\"row\">\n <div class=\"col-12\">\n <h2>{{ 'User.Subscriptions.APICredentials.Title' | transloco }}</h2>\n <p>\n {{ 'User.Subscriptions.APICredentials.Description' | transloco }}\n </p>\n <!-- pb (not mb): .card .mb-3:last-child is margin-reset in this component's scss -->\n <p class=\"text-muted small mb-0 pb-3\">\n <i class=\"fas fa-info-circle me-1\"></i>\n {{ 'User.Subscriptions.APICredentials.SubscriptionClientIdNote' | transloco }}\n </p>\n </div>\n <div class=\"col-12 col-md-6\">\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"account-api-token\">{{ 'User.Account.APIUserToken' | transloco }}</label>\n <div class=\"input-group\">\n <input type=\"text\"\n id=\"account-api-token\"\n name=\"api_token\"\n class=\"form-control\"\n [value]=\"showApiToken ? user?.api_keys?.api_user_token || ('User.Subscriptions.APICredentials.NoTokenAvailable' | transloco) : '*************************'\"\n readonly />\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"toggleApiTokenVisibility()\">\n {{ showApiToken ? ('User.Subscriptions.APICredentials.Hide' | transloco) : ('User.Subscriptions.APICredentials.View' | transloco) }}\n </button>\n </div>\n </div>\n </div>\n <div class=\"col-12 col-md-6\">\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"account-api-client-id\">{{ 'User.Account.APIUserId' | transloco }}</label>\n <div class=\"input-group\">\n <input type=\"text\"\n id=\"account-api-client-id\"\n name=\"api_client_id\"\n class=\"form-control\"\n [value]=\"showApiClientId ? user?.api_keys?.api_user_id || ('User.Subscriptions.APICredentials.NoClientIdAvailable' | transloco) : '*************************'\"\n readonly />\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"toggleApiClientIdVisibility()\">\n {{ showApiClientId ? ('User.Subscriptions.APICredentials.Hide' | transloco) : ('User.Subscriptions.APICredentials.View' | transloco) }}\n </button>\n </div>\n </div>\n </div>\n <div class=\"col-12 mt-3\">\n <div class=\"d-flex align-items-center gap-3\">\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"refreshApiTokens()\"\n [disabled]=\"refreshingTokens\">\n <i class=\"fas fa-sync-alt me-2\" [class.fa-spin]=\"refreshingTokens\"></i>\n {{ refreshingTokens ? ('User.Subscriptions.APICredentials.Refreshing' | transloco) : ('User.Subscriptions.APICredentials.RefreshTokens' | transloco) }}\n </button>\n <div class=\"d-flex align-items-center gap-2\">\n @if (user?.api_keys?.api_hits !== null) {\n <span class=\"text-muted\">{{ 'User.Subscriptions.APICredentials.ApiHits' | transloco }}:</span>\n <span class=\"fw-bold\">{{ user.api_keys.api_hits | number }}</span>\n }\n @if (user?.api_keys?.api_hits_max !== null) {\n <span class=\"text-muted\">{{ 'User.Subscriptions.APICredentials.ApiHitsMax' | transloco }}:</span>\n <span class=\"fw-bold\">{{ user.api_keys.api_hits_max | number }}</span>\n }\n <!-- Show utilization percentage when both values exist -->\n @if (user?.api_keys?.api_hits !== null && user?.api_keys?.api_hits_max !== null && user?.api_keys?.api_hits_max > 0) {\n <span class=\"text-muted ms-2\">(</span>\n <span class=\"fw-bold\" [ngClass]=\"{\n 'text-success-muted': (user.api_keys.api_hits / user.api_keys.api_hits_max) <= 0.8,\n 'text-warning': (user.api_keys.api_hits / user.api_keys.api_hits_max) > 0.8 && (user.api_keys.api_hits / user.api_keys.api_hits_max) <= 0.9,\n 'text-danger': (user.api_keys.api_hits / user.api_keys.api_hits_max) > 0.9\n }\">\n {{ (user.api_keys.api_hits / user.api_keys.api_hits_max * 100) | number:'1.0-0' }}% consumed\n </span>\n <span class=\"text-muted\">)</span>\n }\n </div>\n </div>\n </div>\n </div>\n </section>\n </div>\n }\n</div>\n<ng-template #content\n let-modal>\n <div class=\"card m-0\">\n <div class=\"card-content\">\n <div class=\"card-title\">\n <h3 class=\"modal-title\">{{ 'User.Profile.ProfilePicture' | transloco }}</h3>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n </button>\n </div>\n <div class=\"card-header\">\n <small> {{ 'User.Profile.PictureMessage' | transloco }}</small>\n <pw-image-cropper #profile\n aspectRatio=\"auto\"\n (imageSelectionEvent)=\"onImageSelection($event)\"\n (closeEvent)=\"onClose()\">\n </pw-image-cropper>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: [".card .mb-2:last-child,.card .mb-3:last-child{margin-bottom:0!important}.overlay{left:50%;opacity:0;position:absolute;text-align:center;top:50%;transform:translate(-50%,-50%);transition:.5s ease}.image-container{position:relative}.image-container:hover .image{opacity:.3}.image-container:hover .overlay{opacity:0}.overlay-text{background:#f0efef80;border-radius:50%;color:#000;font-size:16px;height:150px;line-height:150px;text-align:center;vertical-align:middle;width:150px}@media screen and (max-width:767px){.card-body{padding:20px!important}}\n"] }]
|
|
489
|
+
}], ctorParameters: () => [{ type: i2.UntypedFormBuilder }, { type: i1$1.NgbModal }, { type: i1$2.AuthService }, { type: i1$2.GeoService }, { type: i1$2.ProfileService }, { type: i0.Injector }, { type: i0.ChangeDetectorRef }, { type: i5.ConfirmDialogService }], propDecorators: { placesRef: [{
|
|
489
490
|
type: ViewChild,
|
|
490
491
|
args: ['ngxPlaces']
|
|
491
492
|
}], passwordRef: [{
|
|
@@ -565,7 +566,7 @@ class AddSubscriptionComponent extends AppBaseComponent {
|
|
|
565
566
|
super.ngOnDestroy();
|
|
566
567
|
}
|
|
567
568
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: AddSubscriptionComponent, deps: [{ token: i1$2.ProductService }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
568
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: AddSubscriptionComponent, isStandalone: false, selector: "pw-add-subscription", usesInheritance: true, ngImport: i0, template: "@if (isLoaded && !selectedProduct) {\n <div\n class=\"mt-4\">\n <div class=\"d-flex align-items-start category-tabs-row\">\n <a aria-label=\"Navigate to Target\"\n [routerLink]=\"['/account/subscriptions']\"\n class=\"previous\"><i class=\"fa fa-arrow-alt-circle-left\" aria-hidden=\"true\"></i>\n </a>\n <div class=\"d-flex category-tabs\">\n @for (item of subscribedPermissionKeys; track item; let i = $index) {\n <div class=\"toggle\"\n >\n <input type=\"radio\"\n name=\"sizeBy\"\n value=\"option{{ i + 1 }}\"\n id=\"option{{ i + 1 }}\"\n (change)=\"onChangeCategory(item)\"\n [checked]=\"i === 0\" />\n <label for=\"option{{ i + 1 }}\">{{ item }}</label>\n </div>\n }\n </div>\n </div>\n <ul class=\"row animated fadeIn d-flex\">\n @for (product of availableProducts; track trackByProduct($index, product)) {\n <li\n class=\"col-sm-12 col-md-6 col-xl-4 my-3 mt-sm-2\">\n <div class=\"card\">\n <div class=\"card-content\">\n <div class=\"card-header\">\n <h4 class=\"text-bold-500 primary mb-3\">{{ product.name }}</h4>\n @if (product.price_per_unit) {\n @if (product?.purchased_units) {\n <h5\n class=\"my-3 branding-color-1\">\n Currently {{ product.currency | currencySymbol\n }}{{\n (\n (product.purchased_units * product.price_per_unit) /\n 100\n ) | number:'1.2-2'\n }} / {{ product.billing_frequency }}\n </h5>\n }\n <h5 class=\"my-3\">\n Min\n {{product.min_units > 1 ? (product.min_units + ' Seats'): (product.min_units + ' Seat')}}\n - {{ product.currency | currencySymbol\n }}{{\n ((product.min_units * product.price_per_unit) / 100) | number:'1.2-2'\n }} / {{ product.billing_frequency }}\n </h5>\n <h5 class=\"d-inline-block text-bold-600 mb-2\">\n {{ product.currency | currencySymbol\n }}{{ (product.price_per_unit / 100) | number:'1.2-2' }} / {{\n product.billing_frequency\n }} / seat\n </h5>\n } @else {\n <div class=\"d-inline-block text-bold-600 mb-2\">Free</div>\n }\n <p class=\"mb-2\"\n [innerHTML]=\"product?.description\"></p>\n </div>\n <div class=\"card-footer px-3\">\n @if (\n !product.is_subscribed &&\n !product.trial_subscription &&\n product.stripe_plan_id\n ) {\n <a aria-label=\"Navigate to Target\"\n (click)=\"onSelection(product)\"\n class=\"card-btn btn btn-raised me-1 btn-primary btn-sm\">\n {{ 'User.Subscriptions.Subscribe' | transloco }}\n </a>\n }\n @if (\n !product.is_subscribed &&\n product.trial_subscription &&\n product.stripe_plan_id\n ) {\n <div class=\"mt-3\"\n >\n <a aria-label=\"Navigate to Target\"\n (click)=\"onSelection(product)\"\n class=\"card-btn btn btn-raised me-1 btn-primary btn-sm\">\n {{ 'Button.Upgrade' | transloco }}\n </a>\n <span class=\"badge bg-secondary position-absolute trial-badge\">{{ 'User.Subscriptions.Trial' | transloco }}\n </span>\n </div>\n }\n @if (\n product.is_subscribed &&\n !product.trial_subscription &&\n !product.is_deleted\n ) {\n <span\n class=\"card-btn badge bg-default text-white\">\n {{ 'User.Subscriptions.Subscribed' | transloco }}\n </span>\n }\n @if (\n product.is_subscribed &&\n product.trial_subscription &&\n product.price_per_unit === 0 &&\n !product.is_deleted &&\n !product.stripe_plan_id\n ) {\n <span\n class=\"card-btn badge bg-default text-white\">\n Free\n </span>\n }\n @if (product.is_deleted) {\n <span\n class=\"card-btn badge bg-default text-white\">\n {{ 'User.Subscriptions.UnsubscribedButActive' | transloco }}\n </span>\n }\n </div>\n </div>\n </div>\n </li>\n }\n </ul>\n <div class=\"row\">\n <div class=\"col-12\">\n @if (availableProducts && availableProducts.length === 0) {\n <pw-no-data [withImage]=\"true\" message=\"No products available under this category.\"\n >\n </pw-no-data>\n }\n </div>\n </div>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:root{--first: rgb(23 105 225);--second: rgb(54 194 131);--third: rgb(255 171 0);--text: rgb(34 34 34);--tabs_bg: rgb(23 105 225);--tabs_sub_bg: rgb(70, 136, 236);--tabs_text: rgb(255 255 255);--titles: rgb(34 34 34);--sidebar_bg: rgb(0, 48, 63);--sidebar_text: rgb(255 255 255)}.card .card-body{position:relative}.card .card-body .bottom-text{bottom:15px;left:20px;position:absolute}.card .card-body .card-btn{bottom:15px;position:absolute}.card.shadow-md{height:100%}.card .primary{text-transform:uppercase}.trial-badge{bottom:15px;left:20px}.category-tabs{flex-wrap:nowrap;justify-content:safe center;max-width:100%;min-width:0;overflow-x:auto;scrollbar-width:thin}.category-tabs .toggle{flex:0 0 auto}.category-tabs .toggle input+label{white-space:nowrap}.category-tabs-row .previous i{top:0}.toggle{align-items:stretch;box-sizing:border-box;display:flex;flex-flow:row nowrap;font-size:0;justify-content:flex-start;margin:0}.toggle input{height:0;left:-9999px;position:absolute;width:0}.toggle input+label{background-color:#fff;border:solid 1px rgb(221,221,221);box-shadow:0 0 #fff0;box-sizing:border-box;display:inline-block;font-size:1rem;font-weight:600;line-height:140%;margin:0;padding:.75rem 2rem;position:relative;text-align:center;transition:border-color .15s ease-out,color .25s ease-out,background-color .15s ease-out,box-shadow .15s ease-out}.toggle input:hover+label{border-color:#213140}.toggle input:checked+label{background-color:var(--tabs_bg);border-color:var(--tabs_bg);box-shadow:0 0 10px #66b3fb80;color:var(--tabs_text);z-index:1}.toggle:first-of-type input+label{border-radius:4px 0 0 4px}.toggle:last-of-type input+label{border-radius:0 4px 4px 0}.toggle:first-of-type:last-of-type input+label{border-radius:4px}.shadow-md{height:100%;padding-bottom:50px!important}.fadeIn{animation-name:fadeIn}.animated{animation-duration:2s;animation-fill-mode:both}.card-btn{bottom:15px;position:absolute;right:20px}.card-footer{height:60px}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@media(max-width:800px){.toggle input+label{padding:.75rem 1rem}}.branding-color-1{color:var(--first)!important}\n"], dependencies: [{ kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: i5.NoDataComponent, selector: "pw-no-data", inputs: ["message", "description", "withImage"] }, { kind: "pipe", type:
|
|
569
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: AddSubscriptionComponent, isStandalone: false, selector: "pw-add-subscription", usesInheritance: true, ngImport: i0, template: "@if (isLoaded && !selectedProduct) {\n <div\n class=\"mt-4\">\n <div class=\"d-flex align-items-start category-tabs-row\">\n <a aria-label=\"Navigate to Target\"\n [routerLink]=\"['/account/subscriptions']\"\n class=\"previous\"><i class=\"fa fa-arrow-alt-circle-left\" aria-hidden=\"true\"></i>\n </a>\n <div class=\"d-flex category-tabs\">\n @for (item of subscribedPermissionKeys; track item; let i = $index) {\n <div class=\"toggle\"\n >\n <input type=\"radio\"\n name=\"sizeBy\"\n value=\"option{{ i + 1 }}\"\n id=\"option{{ i + 1 }}\"\n (change)=\"onChangeCategory(item)\"\n [checked]=\"i === 0\" />\n <label for=\"option{{ i + 1 }}\">{{ item }}</label>\n </div>\n }\n </div>\n </div>\n <ul class=\"row animated fadeIn d-flex\">\n @for (product of availableProducts; track trackByProduct($index, product)) {\n <li\n class=\"col-sm-12 col-md-6 col-xl-4 my-3 mt-sm-2\">\n <div class=\"card\">\n <div class=\"card-content\">\n <div class=\"card-header\">\n <h4 class=\"text-bold-500 primary mb-3\">{{ product.name }}</h4>\n @if (product.price_per_unit) {\n @if (product?.purchased_units) {\n <h5\n class=\"my-3 branding-color-1\">\n Currently {{ product.currency | currencySymbol\n }}{{\n (\n (product.purchased_units * product.price_per_unit) /\n 100\n ) | number:'1.2-2'\n }} / {{ product.billing_frequency }}\n </h5>\n }\n <h5 class=\"my-3\">\n Min\n {{product.min_units > 1 ? (product.min_units + ' Seats'): (product.min_units + ' Seat')}}\n - {{ product.currency | currencySymbol\n }}{{\n ((product.min_units * product.price_per_unit) / 100) | number:'1.2-2'\n }} / {{ product.billing_frequency }}\n </h5>\n <h5 class=\"d-inline-block text-bold-600 mb-2\">\n {{ product.currency | currencySymbol\n }}{{ (product.price_per_unit / 100) | number:'1.2-2' }} / {{\n product.billing_frequency\n }} / seat\n </h5>\n } @else {\n <div class=\"d-inline-block text-bold-600 mb-2\">Free</div>\n }\n <p class=\"mb-2\"\n [innerHTML]=\"product?.description\"></p>\n </div>\n <div class=\"card-footer px-3\">\n @if (\n !product.is_subscribed &&\n !product.trial_subscription &&\n product.stripe_plan_id\n ) {\n <a aria-label=\"Navigate to Target\"\n (click)=\"onSelection(product)\"\n class=\"card-btn btn btn-raised me-1 btn-primary btn-sm\">\n {{ 'User.Subscriptions.Subscribe' | transloco }}\n </a>\n }\n @if (\n !product.is_subscribed &&\n product.trial_subscription &&\n product.stripe_plan_id\n ) {\n <div class=\"mt-3\"\n >\n <a aria-label=\"Navigate to Target\"\n (click)=\"onSelection(product)\"\n class=\"card-btn btn btn-raised me-1 btn-primary btn-sm\">\n {{ 'Button.Upgrade' | transloco }}\n </a>\n <span class=\"badge bg-secondary position-absolute trial-badge\">{{ 'User.Subscriptions.Trial' | transloco }}\n </span>\n </div>\n }\n @if (\n product.is_subscribed &&\n !product.trial_subscription &&\n !product.is_deleted\n ) {\n <span\n class=\"card-btn badge bg-default text-white\">\n {{ 'User.Subscriptions.Subscribed' | transloco }}\n </span>\n }\n @if (\n product.is_subscribed &&\n product.trial_subscription &&\n product.price_per_unit === 0 &&\n !product.is_deleted &&\n !product.stripe_plan_id\n ) {\n <span\n class=\"card-btn badge bg-default text-white\">\n Free\n </span>\n }\n @if (product.is_deleted) {\n <span\n class=\"card-btn badge bg-default text-white\">\n {{ 'User.Subscriptions.UnsubscribedButActive' | transloco }}\n </span>\n }\n </div>\n </div>\n </div>\n </li>\n }\n </ul>\n <div class=\"row\">\n <div class=\"col-12\">\n @if (availableProducts && availableProducts.length === 0) {\n <pw-no-data [withImage]=\"true\" message=\"No products available under this category.\"\n >\n </pw-no-data>\n }\n </div>\n </div>\n </div>\n}\n", styles: ["@charset \"UTF-8\";:root{--first: rgb(23 105 225);--second: rgb(54 194 131);--third: rgb(255 171 0);--text: rgb(34 34 34);--tabs_bg: rgb(23 105 225);--tabs_sub_bg: rgb(70, 136, 236);--tabs_text: rgb(255 255 255);--titles: rgb(34 34 34);--sidebar_bg: rgb(0, 48, 63);--sidebar_text: rgb(255 255 255)}.card .card-body{position:relative}.card .card-body .bottom-text{bottom:15px;left:20px;position:absolute}.card .card-body .card-btn{bottom:15px;position:absolute}.card.shadow-md{height:100%}.card .primary{text-transform:uppercase}.trial-badge{bottom:15px;left:20px}.category-tabs{flex-wrap:nowrap;justify-content:safe center;max-width:100%;min-width:0;overflow-x:auto;scrollbar-width:thin}.category-tabs .toggle{flex:0 0 auto}.category-tabs .toggle input+label{white-space:nowrap}.category-tabs-row .previous i{top:0}.toggle{align-items:stretch;box-sizing:border-box;display:flex;flex-flow:row nowrap;font-size:0;justify-content:flex-start;margin:0}.toggle input{height:0;left:-9999px;position:absolute;width:0}.toggle input+label{background-color:#fff;border:solid 1px rgb(221,221,221);box-shadow:0 0 #fff0;box-sizing:border-box;display:inline-block;font-size:1rem;font-weight:600;line-height:140%;margin:0;padding:.75rem 2rem;position:relative;text-align:center;transition:border-color .15s ease-out,color .25s ease-out,background-color .15s ease-out,box-shadow .15s ease-out}.toggle input:hover+label{border-color:#213140}.toggle input:checked+label{background-color:var(--tabs_bg);border-color:var(--tabs_bg);box-shadow:0 0 10px #66b3fb80;color:var(--tabs_text);z-index:1}.toggle:first-of-type input+label{border-radius:4px 0 0 4px}.toggle:last-of-type input+label{border-radius:0 4px 4px 0}.toggle:first-of-type:last-of-type input+label{border-radius:4px}.shadow-md{height:100%;padding-bottom:50px!important}.fadeIn{animation-name:fadeIn}.animated{animation-duration:2s;animation-fill-mode:both}.card-btn{bottom:15px;position:absolute;right:20px}.card-footer{height:60px}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@media(max-width:800px){.toggle input+label{padding:.75rem 1rem}}.branding-color-1{color:var(--first)!important}\n"], dependencies: [{ kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: i5.NoDataComponent, selector: "pw-no-data", inputs: ["message", "description", "withImage"] }, { kind: "pipe", type: i8.DecimalPipe, name: "number" }, { kind: "pipe", type: i8$2.TranslocoPipe, name: "transloco" }, { kind: "pipe", type: i6.CurrencySymbolPipe, name: "currencySymbol" }] }); }
|
|
569
570
|
}
|
|
570
571
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: AddSubscriptionComponent, decorators: [{
|
|
571
572
|
type: Component,
|
|
@@ -605,6 +606,102 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
|
|
|
605
606
|
type: Output
|
|
606
607
|
}] } });
|
|
607
608
|
|
|
609
|
+
class ClearMaskedOnFocusDirective {
|
|
610
|
+
constructor(control) {
|
|
611
|
+
this.control = control;
|
|
612
|
+
}
|
|
613
|
+
onFocus(event) {
|
|
614
|
+
const input = event.target;
|
|
615
|
+
const value = input?.value ?? '';
|
|
616
|
+
if (/\*{3,}/.test(value)) {
|
|
617
|
+
this.control?.control?.setValue('');
|
|
618
|
+
input.value = '';
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: ClearMaskedOnFocusDirective, deps: [{ token: i2.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
622
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.6", type: ClearMaskedOnFocusDirective, isStandalone: false, selector: "input[pwClearMaskedOnFocus]", host: { listeners: { "focus": "onFocus($event)" } }, ngImport: i0 }); }
|
|
623
|
+
}
|
|
624
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: ClearMaskedOnFocusDirective, decorators: [{
|
|
625
|
+
type: Directive,
|
|
626
|
+
args: [{
|
|
627
|
+
selector: 'input[pwClearMaskedOnFocus]',
|
|
628
|
+
standalone: false
|
|
629
|
+
}]
|
|
630
|
+
}], ctorParameters: () => [{ type: i2.NgControl, decorators: [{
|
|
631
|
+
type: Optional
|
|
632
|
+
}, {
|
|
633
|
+
type: Self
|
|
634
|
+
}] }], propDecorators: { onFocus: [{
|
|
635
|
+
type: HostListener,
|
|
636
|
+
args: ['focus', ['$event']]
|
|
637
|
+
}] } });
|
|
638
|
+
|
|
639
|
+
const ACRONYMS = new Set([
|
|
640
|
+
'id',
|
|
641
|
+
'url',
|
|
642
|
+
'api',
|
|
643
|
+
'aws',
|
|
644
|
+
'smtp',
|
|
645
|
+
'ssl',
|
|
646
|
+
'tls',
|
|
647
|
+
'iam',
|
|
648
|
+
'sso',
|
|
649
|
+
'sdk',
|
|
650
|
+
'jwt',
|
|
651
|
+
'oauth'
|
|
652
|
+
]);
|
|
653
|
+
class SubscriptionNameByIdPipe {
|
|
654
|
+
transform(subs, id) {
|
|
655
|
+
if (!subs || id == null)
|
|
656
|
+
return '';
|
|
657
|
+
const found = subs.find(s => String(s.id) === String(id));
|
|
658
|
+
return (found?.organisation || found?.organization || found?.name || '');
|
|
659
|
+
}
|
|
660
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: SubscriptionNameByIdPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
661
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.6", ngImport: i0, type: SubscriptionNameByIdPipe, isStandalone: false, name: "subscriptionNameById" }); }
|
|
662
|
+
}
|
|
663
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: SubscriptionNameByIdPipe, decorators: [{
|
|
664
|
+
type: Pipe,
|
|
665
|
+
args: [{ name: 'subscriptionNameById', standalone: false }]
|
|
666
|
+
}] });
|
|
667
|
+
class CredentialAvatarHuePipe {
|
|
668
|
+
transform(value) {
|
|
669
|
+
if (!value)
|
|
670
|
+
return 215;
|
|
671
|
+
let hash = 0;
|
|
672
|
+
for (let i = 0; i < value.length; i++) {
|
|
673
|
+
hash = (hash * 31 + value.charCodeAt(i)) | 0;
|
|
674
|
+
}
|
|
675
|
+
return Math.abs(hash) % 360;
|
|
676
|
+
}
|
|
677
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: CredentialAvatarHuePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
678
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.6", ngImport: i0, type: CredentialAvatarHuePipe, isStandalone: false, name: "credentialAvatarHue" }); }
|
|
679
|
+
}
|
|
680
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: CredentialAvatarHuePipe, decorators: [{
|
|
681
|
+
type: Pipe,
|
|
682
|
+
args: [{ name: 'credentialAvatarHue', standalone: false }]
|
|
683
|
+
}] });
|
|
684
|
+
class HumanizeCredentialNamePipe {
|
|
685
|
+
transform(value) {
|
|
686
|
+
if (!value)
|
|
687
|
+
return '';
|
|
688
|
+
return value
|
|
689
|
+
.replace(/[_-]+/g, ' ')
|
|
690
|
+
.split(' ')
|
|
691
|
+
.filter(Boolean)
|
|
692
|
+
.map(word => ACRONYMS.has(word.toLowerCase())
|
|
693
|
+
? word.toUpperCase()
|
|
694
|
+
: word.charAt(0).toUpperCase() + word.slice(1).toLowerCase())
|
|
695
|
+
.join(' ');
|
|
696
|
+
}
|
|
697
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: HumanizeCredentialNamePipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe }); }
|
|
698
|
+
static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.2.6", ngImport: i0, type: HumanizeCredentialNamePipe, isStandalone: false, name: "humanizeCredentialName" }); }
|
|
699
|
+
}
|
|
700
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: HumanizeCredentialNamePipe, decorators: [{
|
|
701
|
+
type: Pipe,
|
|
702
|
+
args: [{ name: 'humanizeCredentialName', standalone: false }]
|
|
703
|
+
}] });
|
|
704
|
+
|
|
608
705
|
class SubscriptionCredentialComponent extends AppBaseComponent {
|
|
609
706
|
constructor(fb, subscriptionService, injector, cdr) {
|
|
610
707
|
super(injector);
|
|
@@ -788,11 +885,11 @@ class SubscriptionCredentialComponent extends AppBaseComponent {
|
|
|
788
885
|
super.ngOnDestroy();
|
|
789
886
|
}
|
|
790
887
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: SubscriptionCredentialComponent, deps: [{ token: i2.UntypedFormBuilder }, { token: i1$2.SubscriptionService }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
791
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: SubscriptionCredentialComponent, isStandalone: false, selector: "pw-subscription-credential", viewQueries: [{ propertyName: "passwordValidationModalForRevealCredential", first: true, predicate: ["passwordValidationModalForRevealCredential"], descendants: true }, { propertyName: "passwordValidationModalForEditCredential", first: true, predicate: ["passwordValidationModalForEditCredential"], descendants: true }, { propertyName: "passwordValidationModalForAddCredential", first: true, predicate: ["passwordValidationModalForAddCredential"], descendants: true }], usesInheritance: true, ngImport: i0, template: "@if (showForm) {\n <div class=\"row\"\n >\n <div class=\"col-12 d-flex\">\n <a aria-label=\"Navigate to Target\"\n (click)=\"onCancel()\"\n (keydown.enter)=\"onCancel()\"\n class=\"previous\"><i class=\"fa fa-arrow-alt-circle-left\" aria-hidden=\"true\"></i></a>\n <h3 class=\"m-subheader__title m-subheader__title--separator\">\n <span>{{ data.length ? 'Edit' : 'Create new' }} Credential</span>\n </h3>\n </div>\n </div>\n }\n @if (showForm) {\n <div class=\"container-fluid pw-tab\">\n <div class=\"p-2 mt-3\">\n <form>\n <div class=\"row mb-3\">\n @if (!isEdit && showForm) {\n <div class=\"col-12 col-md-4\"\n >\n <div class=\"mb-3\">\n <span id=\"subscription-credential-select-label\" class=\"pw-label-style\">Credential <span class=\"text-danger required-icon\">*</span> </span>\n <p-select\n [attr.aria-labelledby]=\"'subscription-credential-select-label'\"\n [options]=\"uniqueCredential\"\n [placeholder]=\"'Select credential'\"\n optionLabel=\"name\"\n optionValue=\"name\"\n (onChange)=\"selectedOption($event)\">\n </p-select>\n </div>\n </div>\n }\n @if (credentialsSelect?.length) {\n <div class=\"col-12 col-md-4\"\n >\n <div class=\"card pb-2 pt-2 overflow-visible\">\n <div class=\"card-content\">\n <div class=\"card-header\">\n <form [formGroup]=\"form\"\n novalidate\n (ngSubmit)=\"saveCredentials()\">\n <div formArrayName=\"credentials\">\n @for (\n credential of credentialsGroup.controls; track\n credential; let i = $index) {\n <div>\n <div [formGroupName]=\"i\">\n <div class=\"mb-3\">\n <pw-input-container label=\"{{\n credential.get('field').value\n }}\"\n [class.info-circle]=\"\n credential.get('description').value\n \"\n name=\"value\"\n errorMsg=\"Please enter value\">\n @if (\n credential.get('description')\n .value\n ) {\n <span\n class=\"tooltiptext gradient-custom-branding\">{{\n credential.get('description')\n .value\n }}</span>\n }\n <input type=\"text\"\n class=\"form-control\"\n formControlName=\"value\"\n [ngClass]=\"{\n 'is-invalid':\n submitted &&\n credential.get('value')\n .invalid\n }\" id=\"input_value_1\" name=\"input_value_1\"/>\n </pw-input-container>\n </div>\n </div>\n </div>\n }\n </div>\n <div class=\"text-end mt-3\">\n <button type=\"submit\"\n [buttonBusy]=\"buttonBusy\"\n class=\"btn btn-primary\">\n {{ 'Button.Submit' | transloco }}\n </button>\n </div>\n </form>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n <div class=\"row\">\n <div class=\"col-12 text-end mt-3\">\n <button type=\"button\"\n class=\"btn btn-outline-default me-2\"\n (click)=\"onCancel()\"\n (keydown.enter)=\"onCancel()\" >\n {{ 'Button.Back' | transloco }}\n </button>\n </div>\n </div>\n </form>\n </div>\n </div>\n }\n\n @if (!showForm) {\n <div class=\"row\">\n <div class=\"col-12 d-flex\">\n <a aria-label=\"Navigate to Target\"\n (click)=\"back()\"\n class=\"previous\"><i class=\"fa fa-arrow-alt-circle-left\" aria-hidden=\"true\"></i></a>\n <h2 class=\"mt-3\">Credentials</h2>\n </div>\n <div class=\"col-12 col-md-12 text-end\">\n <button class=\"btn btn-sm btn-outline-primary\"\n (click)=\"openCredentialsForAdd()\">\n <i class=\"fa fa-plus-circle\" aria-hidden=\"true\"></i> {{ 'Add Credential' }}\n </button>\n </div>\n </div>\n @if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\"\n >\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n <div class=\"row my-4\">\n @for (credential of credentials; track credential) {\n <div class=\"col-12 col-md-6 col-xl-4 mt-3 credential-cards\"\n >\n <div class=\"card\">\n <h2 class=\"credential-field mt-3\">{{ credential.credential_name }}</h2>\n @for (subscriptionCredential of credential.credentials; track subscriptionCredential) {\n <div class=\"card-content\"\n >\n <div class=\"card-header\">\n <div>\n <strong class=\"d-block\">{{ subscriptionCredential.field }}:</strong>\n <input class=\"credential-value\"\n [type]=\"\n credentialName === credential.credential_name\n ? 'text'\n : 'password'\n \"\n readonly\n #input\n [value]=\"subscriptionCredential?.value\" id=\"input_text_5520\" name=\"input_text_5520\" />\n </div>\n </div>\n <div class=\"card-footer\">\n <div class=\"float-end px-2\">\n @if (credentialName !== credential.credential_name) {\n <button class=\"btn btn-outline-primary me-2\"\n (click)=\"revealCredentials(credential)\">\n {{\n 'User.Subscriptions.SubscriptionCredentials.RevealCredential'\n | transloco\n }}\n </button>\n }\n @if (credentialName === credential.credential_name) {\n <button class=\"btn btn-outline-primary me-2\"\n (click)=\"hideCredentials()\">\n {{\n 'User.Subscriptions.SubscriptionCredentials.HideCredential'\n | transloco\n }}\n </button>\n }\n <a class=\"me-2 my-1\"\n aria-label=\"Edit Credential\"\n (click)=\"openCredentialsForEdit(credential.credential_name)\"><i class=\"fa fa-edit edit-icon\" aria-hidden=\"true\"></i></a>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n </div>\n @if (allSubscriptionCredentials?.length === 0 && isLoaded) {\n <div\n class=\"clearboth\">\n <pw-no-data [withImage]=\"true\" [message]=\"'User.Subscriptions.SubscriptionCredentials.NoDataMessage' | transloco\">\n </pw-no-data>\n </div>\n }\n }\n <!-- password validation modal for reveal Credential -->\n <pw-password-validation #passwordValidationModalForRevealCredential\n (successEvent)=\"showCredentials()\">\n </pw-password-validation>\n <!-- password validation modal for Edit Credential -->\n <pw-password-validation #passwordValidationModalForEditCredential\n (successEvent)=\"editCredentials()\">\n </pw-password-validation>\n <!-- password validation modal for Add Credential -->\n <pw-password-validation #passwordValidationModalForAddCredential\n (successEvent)=\"showEditForm()\">\n </pw-password-validation>\n", styles: [".credential-field{text-align:center}.card .card-header{padding:0 24px}.credentials-field{border:0}.credential-value{border:0;width:100%}.overflow-visible{overflow:visible}\n"], dependencies: [{ kind: "directive", type: i4.ButtonBusyDirective, selector: "[buttonBusy]", inputs: ["buttonBusy", "busyText"] }, { kind: "directive", type: i6.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i2.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "component", type: i5.PasswordValidationComponent, selector: "pw-password-validation", inputs: ["confirmMessage"], outputs: ["successEvent"] }, { kind: "component", type: i6$2.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i4$1.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "directive", type: i2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i5.InputContainerComponent, selector: "pw-input-container", inputs: ["name", "controlId", "useAriaLabelledbyOnly", "label", "labelClass", "tooltipPosition", "required", "errorMsg", "isReadOnly", "showTooltip", "tooltipText", "showTriangle", "afterLabel", "showAfterLabel", "showTriangleText", "isLeftTooltip"] }, { kind: "component", type: i5.NoDataComponent, selector: "pw-no-data", inputs: ["message", "description", "withImage"] }, { kind: "pipe", type: i8.TranslocoPipe, name: "transloco" }] }); }
|
|
888
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: SubscriptionCredentialComponent, isStandalone: false, selector: "pw-subscription-credential", viewQueries: [{ propertyName: "passwordValidationModalForRevealCredential", first: true, predicate: ["passwordValidationModalForRevealCredential"], descendants: true }, { propertyName: "passwordValidationModalForEditCredential", first: true, predicate: ["passwordValidationModalForEditCredential"], descendants: true }, { propertyName: "passwordValidationModalForAddCredential", first: true, predicate: ["passwordValidationModalForAddCredential"], descendants: true }], usesInheritance: true, ngImport: i0, template: "@let subName = ((userService.getUserState() | async)?.currentUser?.subscriptions | subscriptionNameById: subscriptionId);\n\n@if (showForm) {\n <div class=\"row\">\n <div class=\"col-12 d-flex\">\n <a aria-label=\"Navigate to Target\"\n (click)=\"onCancel()\"\n (keydown.enter)=\"onCancel()\"\n class=\"previous\">\n <i class=\"fa fa-arrow-alt-circle-left\" aria-hidden=\"true\"></i>\n </a>\n <h3 class=\"m-subheader__title m-subheader__title--separator\">\n <span>\n @if (subName) {\n {{ (isEdit ? 'User.Subscriptions.SubscriptionCredentials.EditTitle' : 'User.Subscriptions.SubscriptionCredentials.CreateTitle') | transloco: { name: subName } }}\n } @else {\n {{ (isEdit ? 'User.Subscriptions.SubscriptionCredentials.EditTitleFallback' : 'User.Subscriptions.SubscriptionCredentials.CreateTitleFallback') | transloco }}\n }\n </span>\n </h3>\n </div>\n </div>\n <p class=\"credential-page-subtitle text-muted mb-4\">\n @if (subName) {\n {{ 'User.Subscriptions.SubscriptionCredentials.FormSubtitle' | transloco: { name: subName } }}\n } @else {\n {{ 'User.Subscriptions.SubscriptionCredentials.FormSubtitleFallback' | transloco }}\n }\n </p>\n\n <section class=\"credential-form-shell\">\n @if (credentialsSelect?.length) {\n <div class=\"credential-form-band\"\n [style.--avatar-hue]=\"credentialsSelect[0].name | credentialAvatarHue\">\n <span class=\"credential-avatar\" aria-hidden=\"true\"\n [style.--avatar-hue]=\"credentialsSelect[0].name | credentialAvatarHue\">\n {{ (credentialsSelect[0].name | humanizeCredentialName).charAt(0) }}\n </span>\n <span class=\"credential-form-band-name\">\n {{ credentialsSelect[0].name | humanizeCredentialName }}\n </span>\n </div>\n }\n\n <form [formGroup]=\"form\" novalidate (ngSubmit)=\"saveCredentials()\" class=\"credential-form\">\n @if (!isEdit) {\n <div class=\"credential-form-row\">\n <pw-input-container\n [label]=\"'User.Subscriptions.SubscriptionCredentials.CredentialLabel' | transloco\"\n name=\"credentialType\">\n <p-select\n [options]=\"uniqueCredential\"\n [placeholder]=\"'User.Subscriptions.SubscriptionCredentials.CredentialPlaceholder' | transloco\"\n optionLabel=\"name\" optionValue=\"name\" appendTo=\"body\"\n (onChange)=\"selectedOption($event)\">\n </p-select>\n </pw-input-container>\n </div>\n }\n\n @if (credentialsSelect?.length) {\n <div formArrayName=\"credentials\" class=\"credential-form-fields\">\n @for (credential of credentialsGroup.controls; track credential; let i = $index) {\n <div [formGroupName]=\"i\" class=\"credential-form-row\">\n <pw-input-container\n [label]=\"credential.get('field').value | humanizeCredentialName\"\n [class.info-circle]=\"credential.get('description').value\"\n name=\"value\"\n [errorMsg]=\"'User.Subscriptions.SubscriptionCredentials.ValueError' | transloco\">\n @if (credential.get('description').value) {\n <span class=\"tooltiptext gradient-custom-branding\">{{ credential.get('description').value }}</span>\n }\n <input type=\"text\" class=\"form-control\" formControlName=\"value\" pwClearMaskedOnFocus\n [ngClass]=\"{ 'is-invalid': submitted && credential.get('value').invalid }\"\n [id]=\"'credential-value-' + i\" [name]=\"'credential-value-' + i\" />\n </pw-input-container>\n </div>\n }\n </div>\n }\n\n <div class=\"credential-form-actions\">\n <button type=\"button\" class=\"btn btn-outline-default\" (click)=\"onCancel()\" (keydown.enter)=\"onCancel()\">\n {{ 'Button.Back' | transloco }}\n </button>\n @if (credentialsSelect?.length) {\n <button type=\"submit\" [buttonBusy]=\"buttonBusy\" class=\"btn btn-primary\">\n {{ 'Button.Submit' | transloco }}\n </button>\n }\n </div>\n </form>\n </section>\n}\n\n@if (!showForm) {\n <div class=\"row\">\n <div class=\"col-12 d-flex\">\n <a aria-label=\"Navigate to Target\"\n (click)=\"back()\"\n (keydown.enter)=\"back()\"\n class=\"previous\">\n <i class=\"fa fa-arrow-alt-circle-left\" aria-hidden=\"true\"></i>\n </a>\n <h2 class=\"mt-3\">\n @if (subName) {\n {{ 'User.Subscriptions.SubscriptionCredentials.PageTitle' | transloco: { name: subName } }}\n } @else {\n {{ 'User.Subscriptions.SubscriptionCredentials.PageTitleFallback' | transloco }}\n }\n </h2>\n </div>\n <div class=\"col-12 col-md-12 text-end\">\n <button class=\"btn btn-sm btn-outline-primary\" (click)=\"openCredentialsForAdd()\">\n <i class=\"fa fa-plus-circle\" aria-hidden=\"true\"></i>\n {{ 'User.Subscriptions.SubscriptionCredentials.AddButton' | transloco }}\n </button>\n </div>\n </div>\n <p class=\"credential-page-subtitle text-muted mb-4\">\n @if (subName) {\n {{ 'User.Subscriptions.SubscriptionCredentials.ListSubtitle' | transloco: { name: subName } }}\n } @else {\n {{ 'User.Subscriptions.SubscriptionCredentials.ListSubtitleFallback' | transloco }}\n }\n </p>\n\n <pw-loader [isVisible]=\"!isLoaded\"></pw-loader>\n\n @if (isLoaded) {\n @if (allSubscriptionCredentials?.length === 0) {\n <div class=\"credential-empty\">\n <pw-no-data [withImage]=\"true\"\n [message]=\"'User.Subscriptions.SubscriptionCredentials.NoDataMessage' | transloco\"></pw-no-data>\n </div>\n } @else {\n <ul class=\"credential-grid\">\n @for (credential of credentials; track credential.credential_name) {\n <li class=\"credential-card\">\n <header class=\"credential-card-header\"\n [style.--avatar-hue]=\"credential.credential_name | credentialAvatarHue\">\n <span class=\"credential-avatar\" aria-hidden=\"true\">\n {{ (credential.credential_name | humanizeCredentialName).charAt(0) }}\n </span>\n <h3 class=\"credential-card-title\">\n {{ credential.credential_name | humanizeCredentialName }}\n </h3>\n <button type=\"button\" class=\"credential-icon-btn\"\n [attr.aria-label]=\"'User.Subscriptions.SubscriptionCredentials.EditAriaLabel' | transloco\"\n (click)=\"openCredentialsForEdit(credential.credential_name)\">\n <i class=\"fa fa-pen\" aria-hidden=\"true\"></i>\n </button>\n </header>\n <dl class=\"credential-card-fields\">\n @for (entry of credential.credentials; track entry.id) {\n <div class=\"credential-card-row\">\n <dt>{{ entry.field | humanizeCredentialName }}</dt>\n <dd><code class=\"credential-card-value\">{{ entry?.value }}</code></dd>\n </div>\n }\n </dl>\n </li>\n }\n </ul>\n }\n }\n}\n\n<pw-password-validation #passwordValidationModalForEditCredential (successEvent)=\"editCredentials()\"></pw-password-validation>\n<pw-password-validation #passwordValidationModalForAddCredential (successEvent)=\"showEditForm()\"></pw-password-validation>\n", styles: [".credential-page-subtitle{margin-bottom:24px}.credential-grid{list-style:none;padding:0;margin:16px 0 0;width:100%;display:grid;gap:16px;grid-template-columns:repeat(auto-fill,minmax(360px,1fr))}.credential-card{background:#fff;border:1px solid #e2e5ea;border-radius:10px;display:flex;flex-direction:column;overflow:hidden;transition:border-color .15s ease-out}.credential-card:hover{border-color:#cfd4dc}.credential-card-header{display:flex;align-items:center;gap:12px;padding:14px 16px;background:hsl(var(--avatar-hue, 215),60%,97%);border-bottom:1px solid hsl(var(--avatar-hue, 215),40%,90%)}.credential-avatar{width:36px;height:36px;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;font-size:15px;font-weight:700;line-height:1;color:hsl(var(--avatar-hue, 215),60%,28%);background:hsl(var(--avatar-hue, 215),70%,92%);border:1px solid hsl(var(--avatar-hue, 215),50%,82%);flex-shrink:0;text-transform:uppercase}.credential-card-header h3.credential-card-title{font-size:15px;font-weight:600;line-height:1;height:36px;color:#1a1d21;margin:0!important;padding:0!important;flex:1 1 auto;min-width:0;display:flex;align-items:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.credential-icon-btn{appearance:none;background:transparent;border:1px solid transparent;border-radius:6px;width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;color:#5a6473;cursor:pointer;transition:background-color .12s ease-out,color .12s ease-out,border-color .12s ease-out}.credential-icon-btn .fa{font-size:13px}.credential-icon-btn:hover,.credential-icon-btn:focus-visible{background-color:#fff;color:#1a1d21;border-color:#e2e5ea;outline:none}.credential-card-fields{margin:0;padding:4px 16px 12px;display:flex;flex-direction:column}.credential-card-row{display:grid;grid-template-columns:minmax(120px,1fr) minmax(0,2fr);align-items:center;gap:12px;padding:10px 0;border-bottom:1px dashed #eef0f3}.credential-card-row:last-child{border-bottom:0}.credential-card-row dt{font-size:11px;font-weight:500;color:#5a6473;letter-spacing:.05em;text-transform:uppercase;margin:0}.credential-card-row dd{margin:0;min-width:0;text-align:right}.credential-card-value{font-size:12.5px;font-weight:500;color:#5a6473;background:#f7f8fa;border:1px solid #e2e5ea;border-radius:4px;padding:3px 8px;display:inline-block;max-width:100%;word-break:break-all;line-height:1.5;-webkit-user-select:all;user-select:all}.credential-empty{padding:48px 0;text-align:center}.credential-form-shell{background:#fff;border:1px solid #e2e5ea;border-radius:10px;max-width:640px;overflow:hidden;margin-top:16px}.credential-form-band{display:flex;align-items:center;gap:12px;padding:14px 20px;background:hsl(var(--avatar-hue, 215),60%,97%);border-bottom:1px solid hsl(var(--avatar-hue, 215),40%,90%)}.credential-form-band .credential-form-band-name{font-size:15px;font-weight:600;line-height:1;color:hsl(var(--avatar-hue, 215),60%,22%);display:inline-flex;align-items:center;height:36px}.credential-form{padding:20px 24px 24px}.credential-form-fields{display:flex;flex-direction:column;gap:16px}.credential-form-row+.credential-form-fields{margin-top:16px;padding-top:16px;border-top:1px solid #e2e5ea}.credential-form-actions{margin-top:24px;padding-top:16px;border-top:1px solid #e2e5ea;display:flex;justify-content:flex-end;gap:8px}@media(max-width:575px){.credential-form{padding:16px}.credential-card-row{grid-template-columns:1fr;gap:4px}.credential-card-row dd{text-align:left}}\n"], dependencies: [{ kind: "component", type: i3$1.AppLoaderComponent, selector: "pw-loader", inputs: ["isVisible", "closeOnOutsideClick", "autoCloseTimeOut"] }, { kind: "directive", type: i3.ButtonBusyDirective, selector: "[buttonBusy]", inputs: ["buttonBusy", "busyText"] }, { kind: "directive", type: i8.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i2.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "component", type: i5.PasswordValidationComponent, selector: "pw-password-validation", inputs: ["confirmMessage", "destructive"], outputs: ["successEvent"] }, { kind: "component", type: i8$1.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i5.InputContainerComponent, selector: "pw-input-container", inputs: ["name", "controlId", "useAriaLabelledbyOnly", "label", "labelClass", "tooltipPosition", "required", "errorMsg", "isReadOnly", "showTooltip", "tooltipText", "showTriangle", "afterLabel", "showAfterLabel", "showTriangleText", "isLeftTooltip"] }, { kind: "component", type: i5.NoDataComponent, selector: "pw-no-data", inputs: ["message", "description", "withImage"] }, { kind: "directive", type: ClearMaskedOnFocusDirective, selector: "input[pwClearMaskedOnFocus]" }, { kind: "pipe", type: i8.AsyncPipe, name: "async" }, { kind: "pipe", type: i8$2.TranslocoPipe, name: "transloco" }, { kind: "pipe", type: HumanizeCredentialNamePipe, name: "humanizeCredentialName" }, { kind: "pipe", type: CredentialAvatarHuePipe, name: "credentialAvatarHue" }, { kind: "pipe", type: SubscriptionNameByIdPipe, name: "subscriptionNameById" }] }); }
|
|
792
889
|
}
|
|
793
890
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: SubscriptionCredentialComponent, decorators: [{
|
|
794
891
|
type: Component,
|
|
795
|
-
args: [{ selector: 'pw-subscription-credential', standalone: false, template: "@if (showForm) {\n <div class=\"row\"\n >\n <div class=\"col-12 d-flex\">\n <a aria-label=\"Navigate to Target\"\n (click)=\"onCancel()\"\n (keydown.enter)=\"onCancel()\"\n class=\"previous\"><i class=\"fa fa-arrow-alt-circle-left\" aria-hidden=\"true\"></i></a>\n <h3 class=\"m-subheader__title m-subheader__title--separator\">\n <span>{{ data.length ? 'Edit' : 'Create new' }} Credential</span>\n </h3>\n </div>\n </div>\n }\n @if (showForm) {\n <div class=\"container-fluid pw-tab\">\n <div class=\"p-2 mt-3\">\n <form>\n <div class=\"row mb-3\">\n @if (!isEdit && showForm) {\n <div class=\"col-12 col-md-4\"\n >\n <div class=\"mb-3\">\n <span id=\"subscription-credential-select-label\" class=\"pw-label-style\">Credential <span class=\"text-danger required-icon\">*</span> </span>\n <p-select\n [attr.aria-labelledby]=\"'subscription-credential-select-label'\"\n [options]=\"uniqueCredential\"\n [placeholder]=\"'Select credential'\"\n optionLabel=\"name\"\n optionValue=\"name\"\n (onChange)=\"selectedOption($event)\">\n </p-select>\n </div>\n </div>\n }\n @if (credentialsSelect?.length) {\n <div class=\"col-12 col-md-4\"\n >\n <div class=\"card pb-2 pt-2 overflow-visible\">\n <div class=\"card-content\">\n <div class=\"card-header\">\n <form [formGroup]=\"form\"\n novalidate\n (ngSubmit)=\"saveCredentials()\">\n <div formArrayName=\"credentials\">\n @for (\n credential of credentialsGroup.controls; track\n credential; let i = $index) {\n <div>\n <div [formGroupName]=\"i\">\n <div class=\"mb-3\">\n <pw-input-container label=\"{{\n credential.get('field').value\n }}\"\n [class.info-circle]=\"\n credential.get('description').value\n \"\n name=\"value\"\n errorMsg=\"Please enter value\">\n @if (\n credential.get('description')\n .value\n ) {\n <span\n class=\"tooltiptext gradient-custom-branding\">{{\n credential.get('description')\n .value\n }}</span>\n }\n <input type=\"text\"\n class=\"form-control\"\n formControlName=\"value\"\n [ngClass]=\"{\n 'is-invalid':\n submitted &&\n credential.get('value')\n .invalid\n }\" id=\"input_value_1\" name=\"input_value_1\"/>\n </pw-input-container>\n </div>\n </div>\n </div>\n }\n </div>\n <div class=\"text-end mt-3\">\n <button type=\"submit\"\n [buttonBusy]=\"buttonBusy\"\n class=\"btn btn-primary\">\n {{ 'Button.Submit' | transloco }}\n </button>\n </div>\n </form>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n <div class=\"row\">\n <div class=\"col-12 text-end mt-3\">\n <button type=\"button\"\n class=\"btn btn-outline-default me-2\"\n (click)=\"onCancel()\"\n (keydown.enter)=\"onCancel()\" >\n {{ 'Button.Back' | transloco }}\n </button>\n </div>\n </div>\n </form>\n </div>\n </div>\n }\n\n @if (!showForm) {\n <div class=\"row\">\n <div class=\"col-12 d-flex\">\n <a aria-label=\"Navigate to Target\"\n (click)=\"back()\"\n class=\"previous\"><i class=\"fa fa-arrow-alt-circle-left\" aria-hidden=\"true\"></i></a>\n <h2 class=\"mt-3\">Credentials</h2>\n </div>\n <div class=\"col-12 col-md-12 text-end\">\n <button class=\"btn btn-sm btn-outline-primary\"\n (click)=\"openCredentialsForAdd()\">\n <i class=\"fa fa-plus-circle\" aria-hidden=\"true\"></i> {{ 'Add Credential' }}\n </button>\n </div>\n </div>\n @if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\"\n >\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n <div class=\"row my-4\">\n @for (credential of credentials; track credential) {\n <div class=\"col-12 col-md-6 col-xl-4 mt-3 credential-cards\"\n >\n <div class=\"card\">\n <h2 class=\"credential-field mt-3\">{{ credential.credential_name }}</h2>\n @for (subscriptionCredential of credential.credentials; track subscriptionCredential) {\n <div class=\"card-content\"\n >\n <div class=\"card-header\">\n <div>\n <strong class=\"d-block\">{{ subscriptionCredential.field }}:</strong>\n <input class=\"credential-value\"\n [type]=\"\n credentialName === credential.credential_name\n ? 'text'\n : 'password'\n \"\n readonly\n #input\n [value]=\"subscriptionCredential?.value\" id=\"input_text_5520\" name=\"input_text_5520\" />\n </div>\n </div>\n <div class=\"card-footer\">\n <div class=\"float-end px-2\">\n @if (credentialName !== credential.credential_name) {\n <button class=\"btn btn-outline-primary me-2\"\n (click)=\"revealCredentials(credential)\">\n {{\n 'User.Subscriptions.SubscriptionCredentials.RevealCredential'\n | transloco\n }}\n </button>\n }\n @if (credentialName === credential.credential_name) {\n <button class=\"btn btn-outline-primary me-2\"\n (click)=\"hideCredentials()\">\n {{\n 'User.Subscriptions.SubscriptionCredentials.HideCredential'\n | transloco\n }}\n </button>\n }\n <a class=\"me-2 my-1\"\n aria-label=\"Edit Credential\"\n (click)=\"openCredentialsForEdit(credential.credential_name)\"><i class=\"fa fa-edit edit-icon\" aria-hidden=\"true\"></i></a>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n }\n </div>\n @if (allSubscriptionCredentials?.length === 0 && isLoaded) {\n <div\n class=\"clearboth\">\n <pw-no-data [withImage]=\"true\" [message]=\"'User.Subscriptions.SubscriptionCredentials.NoDataMessage' | transloco\">\n </pw-no-data>\n </div>\n }\n }\n <!-- password validation modal for reveal Credential -->\n <pw-password-validation #passwordValidationModalForRevealCredential\n (successEvent)=\"showCredentials()\">\n </pw-password-validation>\n <!-- password validation modal for Edit Credential -->\n <pw-password-validation #passwordValidationModalForEditCredential\n (successEvent)=\"editCredentials()\">\n </pw-password-validation>\n <!-- password validation modal for Add Credential -->\n <pw-password-validation #passwordValidationModalForAddCredential\n (successEvent)=\"showEditForm()\">\n </pw-password-validation>\n", styles: [".credential-field{text-align:center}.card .card-header{padding:0 24px}.credentials-field{border:0}.credential-value{border:0;width:100%}.overflow-visible{overflow:visible}\n"] }]
|
|
892
|
+
args: [{ selector: 'pw-subscription-credential', standalone: false, template: "@let subName = ((userService.getUserState() | async)?.currentUser?.subscriptions | subscriptionNameById: subscriptionId);\n\n@if (showForm) {\n <div class=\"row\">\n <div class=\"col-12 d-flex\">\n <a aria-label=\"Navigate to Target\"\n (click)=\"onCancel()\"\n (keydown.enter)=\"onCancel()\"\n class=\"previous\">\n <i class=\"fa fa-arrow-alt-circle-left\" aria-hidden=\"true\"></i>\n </a>\n <h3 class=\"m-subheader__title m-subheader__title--separator\">\n <span>\n @if (subName) {\n {{ (isEdit ? 'User.Subscriptions.SubscriptionCredentials.EditTitle' : 'User.Subscriptions.SubscriptionCredentials.CreateTitle') | transloco: { name: subName } }}\n } @else {\n {{ (isEdit ? 'User.Subscriptions.SubscriptionCredentials.EditTitleFallback' : 'User.Subscriptions.SubscriptionCredentials.CreateTitleFallback') | transloco }}\n }\n </span>\n </h3>\n </div>\n </div>\n <p class=\"credential-page-subtitle text-muted mb-4\">\n @if (subName) {\n {{ 'User.Subscriptions.SubscriptionCredentials.FormSubtitle' | transloco: { name: subName } }}\n } @else {\n {{ 'User.Subscriptions.SubscriptionCredentials.FormSubtitleFallback' | transloco }}\n }\n </p>\n\n <section class=\"credential-form-shell\">\n @if (credentialsSelect?.length) {\n <div class=\"credential-form-band\"\n [style.--avatar-hue]=\"credentialsSelect[0].name | credentialAvatarHue\">\n <span class=\"credential-avatar\" aria-hidden=\"true\"\n [style.--avatar-hue]=\"credentialsSelect[0].name | credentialAvatarHue\">\n {{ (credentialsSelect[0].name | humanizeCredentialName).charAt(0) }}\n </span>\n <span class=\"credential-form-band-name\">\n {{ credentialsSelect[0].name | humanizeCredentialName }}\n </span>\n </div>\n }\n\n <form [formGroup]=\"form\" novalidate (ngSubmit)=\"saveCredentials()\" class=\"credential-form\">\n @if (!isEdit) {\n <div class=\"credential-form-row\">\n <pw-input-container\n [label]=\"'User.Subscriptions.SubscriptionCredentials.CredentialLabel' | transloco\"\n name=\"credentialType\">\n <p-select\n [options]=\"uniqueCredential\"\n [placeholder]=\"'User.Subscriptions.SubscriptionCredentials.CredentialPlaceholder' | transloco\"\n optionLabel=\"name\" optionValue=\"name\" appendTo=\"body\"\n (onChange)=\"selectedOption($event)\">\n </p-select>\n </pw-input-container>\n </div>\n }\n\n @if (credentialsSelect?.length) {\n <div formArrayName=\"credentials\" class=\"credential-form-fields\">\n @for (credential of credentialsGroup.controls; track credential; let i = $index) {\n <div [formGroupName]=\"i\" class=\"credential-form-row\">\n <pw-input-container\n [label]=\"credential.get('field').value | humanizeCredentialName\"\n [class.info-circle]=\"credential.get('description').value\"\n name=\"value\"\n [errorMsg]=\"'User.Subscriptions.SubscriptionCredentials.ValueError' | transloco\">\n @if (credential.get('description').value) {\n <span class=\"tooltiptext gradient-custom-branding\">{{ credential.get('description').value }}</span>\n }\n <input type=\"text\" class=\"form-control\" formControlName=\"value\" pwClearMaskedOnFocus\n [ngClass]=\"{ 'is-invalid': submitted && credential.get('value').invalid }\"\n [id]=\"'credential-value-' + i\" [name]=\"'credential-value-' + i\" />\n </pw-input-container>\n </div>\n }\n </div>\n }\n\n <div class=\"credential-form-actions\">\n <button type=\"button\" class=\"btn btn-outline-default\" (click)=\"onCancel()\" (keydown.enter)=\"onCancel()\">\n {{ 'Button.Back' | transloco }}\n </button>\n @if (credentialsSelect?.length) {\n <button type=\"submit\" [buttonBusy]=\"buttonBusy\" class=\"btn btn-primary\">\n {{ 'Button.Submit' | transloco }}\n </button>\n }\n </div>\n </form>\n </section>\n}\n\n@if (!showForm) {\n <div class=\"row\">\n <div class=\"col-12 d-flex\">\n <a aria-label=\"Navigate to Target\"\n (click)=\"back()\"\n (keydown.enter)=\"back()\"\n class=\"previous\">\n <i class=\"fa fa-arrow-alt-circle-left\" aria-hidden=\"true\"></i>\n </a>\n <h2 class=\"mt-3\">\n @if (subName) {\n {{ 'User.Subscriptions.SubscriptionCredentials.PageTitle' | transloco: { name: subName } }}\n } @else {\n {{ 'User.Subscriptions.SubscriptionCredentials.PageTitleFallback' | transloco }}\n }\n </h2>\n </div>\n <div class=\"col-12 col-md-12 text-end\">\n <button class=\"btn btn-sm btn-outline-primary\" (click)=\"openCredentialsForAdd()\">\n <i class=\"fa fa-plus-circle\" aria-hidden=\"true\"></i>\n {{ 'User.Subscriptions.SubscriptionCredentials.AddButton' | transloco }}\n </button>\n </div>\n </div>\n <p class=\"credential-page-subtitle text-muted mb-4\">\n @if (subName) {\n {{ 'User.Subscriptions.SubscriptionCredentials.ListSubtitle' | transloco: { name: subName } }}\n } @else {\n {{ 'User.Subscriptions.SubscriptionCredentials.ListSubtitleFallback' | transloco }}\n }\n </p>\n\n <pw-loader [isVisible]=\"!isLoaded\"></pw-loader>\n\n @if (isLoaded) {\n @if (allSubscriptionCredentials?.length === 0) {\n <div class=\"credential-empty\">\n <pw-no-data [withImage]=\"true\"\n [message]=\"'User.Subscriptions.SubscriptionCredentials.NoDataMessage' | transloco\"></pw-no-data>\n </div>\n } @else {\n <ul class=\"credential-grid\">\n @for (credential of credentials; track credential.credential_name) {\n <li class=\"credential-card\">\n <header class=\"credential-card-header\"\n [style.--avatar-hue]=\"credential.credential_name | credentialAvatarHue\">\n <span class=\"credential-avatar\" aria-hidden=\"true\">\n {{ (credential.credential_name | humanizeCredentialName).charAt(0) }}\n </span>\n <h3 class=\"credential-card-title\">\n {{ credential.credential_name | humanizeCredentialName }}\n </h3>\n <button type=\"button\" class=\"credential-icon-btn\"\n [attr.aria-label]=\"'User.Subscriptions.SubscriptionCredentials.EditAriaLabel' | transloco\"\n (click)=\"openCredentialsForEdit(credential.credential_name)\">\n <i class=\"fa fa-pen\" aria-hidden=\"true\"></i>\n </button>\n </header>\n <dl class=\"credential-card-fields\">\n @for (entry of credential.credentials; track entry.id) {\n <div class=\"credential-card-row\">\n <dt>{{ entry.field | humanizeCredentialName }}</dt>\n <dd><code class=\"credential-card-value\">{{ entry?.value }}</code></dd>\n </div>\n }\n </dl>\n </li>\n }\n </ul>\n }\n }\n}\n\n<pw-password-validation #passwordValidationModalForEditCredential (successEvent)=\"editCredentials()\"></pw-password-validation>\n<pw-password-validation #passwordValidationModalForAddCredential (successEvent)=\"showEditForm()\"></pw-password-validation>\n", styles: [".credential-page-subtitle{margin-bottom:24px}.credential-grid{list-style:none;padding:0;margin:16px 0 0;width:100%;display:grid;gap:16px;grid-template-columns:repeat(auto-fill,minmax(360px,1fr))}.credential-card{background:#fff;border:1px solid #e2e5ea;border-radius:10px;display:flex;flex-direction:column;overflow:hidden;transition:border-color .15s ease-out}.credential-card:hover{border-color:#cfd4dc}.credential-card-header{display:flex;align-items:center;gap:12px;padding:14px 16px;background:hsl(var(--avatar-hue, 215),60%,97%);border-bottom:1px solid hsl(var(--avatar-hue, 215),40%,90%)}.credential-avatar{width:36px;height:36px;border-radius:8px;display:inline-flex;align-items:center;justify-content:center;font-size:15px;font-weight:700;line-height:1;color:hsl(var(--avatar-hue, 215),60%,28%);background:hsl(var(--avatar-hue, 215),70%,92%);border:1px solid hsl(var(--avatar-hue, 215),50%,82%);flex-shrink:0;text-transform:uppercase}.credential-card-header h3.credential-card-title{font-size:15px;font-weight:600;line-height:1;height:36px;color:#1a1d21;margin:0!important;padding:0!important;flex:1 1 auto;min-width:0;display:flex;align-items:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.credential-icon-btn{appearance:none;background:transparent;border:1px solid transparent;border-radius:6px;width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;color:#5a6473;cursor:pointer;transition:background-color .12s ease-out,color .12s ease-out,border-color .12s ease-out}.credential-icon-btn .fa{font-size:13px}.credential-icon-btn:hover,.credential-icon-btn:focus-visible{background-color:#fff;color:#1a1d21;border-color:#e2e5ea;outline:none}.credential-card-fields{margin:0;padding:4px 16px 12px;display:flex;flex-direction:column}.credential-card-row{display:grid;grid-template-columns:minmax(120px,1fr) minmax(0,2fr);align-items:center;gap:12px;padding:10px 0;border-bottom:1px dashed #eef0f3}.credential-card-row:last-child{border-bottom:0}.credential-card-row dt{font-size:11px;font-weight:500;color:#5a6473;letter-spacing:.05em;text-transform:uppercase;margin:0}.credential-card-row dd{margin:0;min-width:0;text-align:right}.credential-card-value{font-size:12.5px;font-weight:500;color:#5a6473;background:#f7f8fa;border:1px solid #e2e5ea;border-radius:4px;padding:3px 8px;display:inline-block;max-width:100%;word-break:break-all;line-height:1.5;-webkit-user-select:all;user-select:all}.credential-empty{padding:48px 0;text-align:center}.credential-form-shell{background:#fff;border:1px solid #e2e5ea;border-radius:10px;max-width:640px;overflow:hidden;margin-top:16px}.credential-form-band{display:flex;align-items:center;gap:12px;padding:14px 20px;background:hsl(var(--avatar-hue, 215),60%,97%);border-bottom:1px solid hsl(var(--avatar-hue, 215),40%,90%)}.credential-form-band .credential-form-band-name{font-size:15px;font-weight:600;line-height:1;color:hsl(var(--avatar-hue, 215),60%,22%);display:inline-flex;align-items:center;height:36px}.credential-form{padding:20px 24px 24px}.credential-form-fields{display:flex;flex-direction:column;gap:16px}.credential-form-row+.credential-form-fields{margin-top:16px;padding-top:16px;border-top:1px solid #e2e5ea}.credential-form-actions{margin-top:24px;padding-top:16px;border-top:1px solid #e2e5ea;display:flex;justify-content:flex-end;gap:8px}@media(max-width:575px){.credential-form{padding:16px}.credential-card-row{grid-template-columns:1fr;gap:4px}.credential-card-row dd{text-align:left}}\n"] }]
|
|
796
893
|
}], ctorParameters: () => [{ type: i2.UntypedFormBuilder }, { type: i1$2.SubscriptionService }, { type: i0.Injector }, { type: i0.ChangeDetectorRef }], propDecorators: { passwordValidationModalForRevealCredential: [{
|
|
797
894
|
type: ViewChild,
|
|
798
895
|
args: ['passwordValidationModalForRevealCredential', { static: false }]
|
|
@@ -1029,7 +1126,7 @@ class UpdatePaymentDetailsComponent extends AppBaseComponent {
|
|
|
1029
1126
|
this.cdr.markForCheck();
|
|
1030
1127
|
}
|
|
1031
1128
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: UpdatePaymentDetailsComponent, deps: [{ token: i2.UntypedFormBuilder }, { token: i1$2.ScriptLoaderService }, { token: i1$2.ProductService }, { token: i1$2.SubscriptionService }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1032
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: UpdatePaymentDetailsComponent, isStandalone: false, selector: "pw-update-payment-details", viewQueries: [{ propertyName: "braintreeContainer", first: true, predicate: ["braintreeContainer"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"container-fluid\">\n <div class=\"card-block\">\n <div class=\"row\">\n <div class=\"col-lg-12 ps-0\">\n <a aria-label=\"Navigate to Target\"\n (click)=\"back()\"\n class=\"previous float-start\"><i class=\"fa fa-arrow-alt-circle-left\" aria-hidden=\"true\"></i></a>\n <h4 class=\"form-section my-3\">\n <i class=\"ft-edit\" aria-hidden=\"true\"></i>\n {{ 'User.Payments.UpdateTitle' | transloco }}\n </h4>\n </div>\n </div>\n\n <div class=\"row g-3 mt-1\">\n <!-- Primary payment method (Stripe) -->\n <div class=\"col-12 col-lg-6\">\n <div class=\"card payment-left p-3 h-100\">\n <div class=\"card-body\">\n <h5 class=\"section-title\">{{ 'User.Payments.Primary.Title' | transloco }}</h5>\n <p class=\"text-muted\">{{ 'User.Payments.Primary.Description' | transloco }}</p>\n\n @if (errorMsg) {\n <div class=\"alert alert-danger\">{{ errorMsg }}</div>\n }\n @if (!isChangePayment && cardDetails) {\n <pw-saved-card-details [data]=\"cardDetails\"\n (changeEvent)=\"onChange($event)\">\n </pw-saved-card-details>\n }\n\n @if (loading) {\n <div class=\"text-center\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n\n @if ((!cardDetails && !loading) || isChangePayment) {\n <form [formGroup]=\"form\" (ngSubmit)=\"onSave()\">\n <h4 class=\"title\">{{ 'User.Payments.Primary.NewCard' | transloco }}</h4>\n <div class=\"row\">\n <div class=\"col-md-9\">\n <div class=\"mb-3\">\n <label for=\"update-payment-card_number\">{{ 'User.Payments.CardNumber' | transloco }}</label>\n <input type=\"text\"\n id=\"update-payment-card_number\"\n class=\"form-control\"\n formControlName=\"card_number\"\n [placeholder]=\"'User.Payments.CardNumber' | transloco\"\n name=\"card_number\" />\n @if (form.get('card_number').touched && form.get('card_number').errors?.required) {\n <div class=\"danger\"><span>{{ 'User.Payments.Errors.CardNumberRequired' | transloco }}</span></div>\n }\n </div>\n </div>\n <div class=\"col-md-3\">\n <div class=\"mb-3\">\n <label for=\"update-payment-cvc\">{{ 'User.Payments.Cvc' | transloco }}</label>\n <input type=\"text\"\n id=\"update-payment-cvc\"\n class=\"form-control\"\n formControlName=\"cvc\"\n [placeholder]=\"'User.Payments.Cvc' | transloco\"\n name=\"cvc\" />\n @if (form.get('cvc').touched && form.get('cvc').errors?.required) {\n <div class=\"danger\"><span>{{ 'User.Payments.Errors.CvcRequired' | transloco }}</span></div>\n }\n </div>\n </div>\n </div>\n <div class=\"row\">\n <div class=\"col-md-6\">\n <div class=\"mb-3\">\n <span class=\"sr-only\" id=\"update-payment-exp_month-label\" class=\"pw-label-style\">{{ 'User.Payments.ExpMonth' | transloco }}</span>\n <p-select\n [attr.aria-labelledby]=\"'update-payment-exp_month-label'\"\n [options]=\"months\"\n [appendTo]=\"'body'\"\n formControlName=\"exp_month\"\n [placeholder]=\"'User.Payments.ExpMonth' | transloco\"\n optionValue=\"value\"\n optionLabel=\"value\">\n </p-select>\n @if (form.get('exp_month').touched && form.get('exp_month').errors?.required) {\n <div class=\"danger\"><span>{{ 'User.Payments.Errors.ExpMonthRequired' | transloco }}</span></div>\n }\n </div>\n </div>\n <div class=\"col-md-6\">\n <div class=\"mb-3\">\n <span class=\"sr-only\" id=\"update-payment-exp_year-label\">{{ 'User.Payments.ExpYear' | transloco }}</span>\n <p-select\n [attr.aria-labelledby]=\"'update-payment-exp_year-label'\"\n [options]=\"years\"\n formControlName=\"exp_year\"\n [placeholder]=\"'User.Payments.ExpYear' | transloco\"\n optionValue=\"value\"\n [appendTo]=\"'body'\"\n optionLabel=\"value\">\n </p-select>\n @if (form.get('exp_year')?.touched && form.get('exp_year')?.errors?.['required']) {\n <div class=\"danger\"><span>{{ 'User.Payments.Errors.ExpYearRequired' | transloco }}</span></div>\n }\n </div>\n </div>\n <div class=\"col-12 text-center mt-4\">\n <img src=\"/assets/img/icons/powered_by_stripe_v2.png\"\n class=\"payment-provider\"\n alt=\"\" />\n </div>\n <div class=\"col-12 mt-4 text-end\">\n <button type=\"button\"\n (click)=\"cancel()\"\n class=\"btn btn-outline-default me-2\">\n {{ 'User.Payments.Cancel' | transloco }}\n </button>\n <button type=\"submit\"\n class=\"btn btn-primary\"\n [buttonBusy]=\"busy\">\n {{ 'User.Payments.Submit' | transloco }}\n </button>\n </div>\n </div>\n </form>\n }\n </div>\n </div>\n </div>\n\n <!-- Secondary payment method (Braintree) -->\n <div class=\"col-12 col-lg-6\">\n <div class=\"card payment-right p-3 h-100\">\n <div class=\"card-body\">\n <h5 class=\"section-title\">{{ 'User.Payments.Secondary.Title' | transloco }}</h5>\n <p class=\"alert alert-info\" [pTooltip]=\"'User.Payments.Secondary.Tooltip' | transloco\" tooltipPosition=\"top\" appendTo=\"body\">\n {{ 'User.Payments.Secondary.Callout' | transloco }}\n </p>\n\n @if (loading) {\n <div class=\"text-center\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n\n @if (secondaryCard && !showBraintreeForm) {\n <pw-saved-card-details [data]=\"secondaryCard\"\n (changeEvent)=\"startBraintreeFlow()\">\n </pw-saved-card-details>\n }\n\n @if (!secondaryCard && !showBraintreeForm && !loading) {\n <button type=\"button\"\n class=\"btn btn-primary\"\n (click)=\"startBraintreeFlow()\">\n {{ 'User.Payments.Secondary.AddCta' | transloco }}\n </button>\n }\n\n @if (showBraintreeForm) {\n <div #braintreeContainer class=\"braintree-dropin-container mt-3\"></div>\n <div class=\"col-12 mt-4 text-end\">\n <button type=\"button\"\n (click)=\"cancelBraintreeFlow()\"\n class=\"btn btn-outline-default me-2\">\n {{ 'User.Payments.Cancel' | transloco }}\n </button>\n <button type=\"button\"\n class=\"btn btn-primary\"\n [buttonBusy]=\"braintreeBusy\"\n (click)=\"submitBraintree()\">\n {{ 'User.Payments.Submit' | transloco }}\n </button>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n\n </div>\n</div>\n", styles: [".card-block .payment-left,.card-block .payment-right{border:1px solid rgb(204,204,204)}.card-block .payment-left h4,.card-block .payment-right h4{border-bottom:1px solid rgb(0,0,0);font-size:1rem;font-weight:600;margin:0 0 20px;padding:0 0 5px;text-transform:uppercase}.payment-provider{width:30%}@media(max-width:800px){.payment-provider{width:60%}}\n"], dependencies: [{ kind: "directive", type: i4.ButtonBusyDirective, selector: "[buttonBusy]", inputs: ["buttonBusy", "busyText"] }, { kind: "directive", type: i4.LazyImgDirective, selector: "img" }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i6$2.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i4$1.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "directive", type: i11.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "component", type: SavedCardDetailsComponent, selector: "pw-saved-card-details", inputs: ["data", "isChangePayment", "showNewCard"], outputs: ["changeEvent"] }, { kind: "pipe", type: i8.TranslocoPipe, name: "transloco" }] }); }
|
|
1129
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: UpdatePaymentDetailsComponent, isStandalone: false, selector: "pw-update-payment-details", viewQueries: [{ propertyName: "braintreeContainer", first: true, predicate: ["braintreeContainer"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"container-fluid\">\n <div class=\"card-block\">\n <div class=\"row\">\n <div class=\"col-lg-12 ps-0\">\n <a aria-label=\"Navigate to Target\"\n (click)=\"back()\"\n class=\"previous float-start\"><i class=\"fa fa-arrow-alt-circle-left\" aria-hidden=\"true\"></i></a>\n <h4 class=\"form-section my-3\">\n <i class=\"ft-edit\" aria-hidden=\"true\"></i>\n {{ 'User.Payments.UpdateTitle' | transloco }}\n </h4>\n </div>\n </div>\n\n <div class=\"row g-3 mt-1\">\n <!-- Primary payment method (Stripe) -->\n <div class=\"col-12 col-lg-6\">\n <div class=\"card payment-left p-3 h-100\">\n <div class=\"card-body\">\n <h5 class=\"section-title\">{{ 'User.Payments.Primary.Title' | transloco }}</h5>\n <p class=\"text-muted\">{{ 'User.Payments.Primary.Description' | transloco }}</p>\n\n @if (errorMsg) {\n <div class=\"alert alert-danger\">{{ errorMsg }}</div>\n }\n @if (!isChangePayment && cardDetails) {\n <pw-saved-card-details [data]=\"cardDetails\"\n (changeEvent)=\"onChange($event)\">\n </pw-saved-card-details>\n }\n\n @if (loading) {\n <div class=\"text-center\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n\n @if ((!cardDetails && !loading) || isChangePayment) {\n <form [formGroup]=\"form\" (ngSubmit)=\"onSave()\">\n <h4 class=\"title\">{{ 'User.Payments.Primary.NewCard' | transloco }}</h4>\n <div class=\"row\">\n <div class=\"col-md-9\">\n <div class=\"mb-3\">\n <label for=\"update-payment-card_number\">{{ 'User.Payments.CardNumber' | transloco }}</label>\n <input type=\"text\"\n id=\"update-payment-card_number\"\n class=\"form-control\"\n formControlName=\"card_number\"\n [placeholder]=\"'User.Payments.CardNumber' | transloco\"\n name=\"card_number\" />\n @if (form.get('card_number').touched && form.get('card_number').errors?.required) {\n <div class=\"danger\"><span>{{ 'User.Payments.Errors.CardNumberRequired' | transloco }}</span></div>\n }\n </div>\n </div>\n <div class=\"col-md-3\">\n <div class=\"mb-3\">\n <label for=\"update-payment-cvc\">{{ 'User.Payments.Cvc' | transloco }}</label>\n <input type=\"text\"\n id=\"update-payment-cvc\"\n class=\"form-control\"\n formControlName=\"cvc\"\n [placeholder]=\"'User.Payments.Cvc' | transloco\"\n name=\"cvc\" />\n @if (form.get('cvc').touched && form.get('cvc').errors?.required) {\n <div class=\"danger\"><span>{{ 'User.Payments.Errors.CvcRequired' | transloco }}</span></div>\n }\n </div>\n </div>\n </div>\n <div class=\"row\">\n <div class=\"col-md-6\">\n <div class=\"mb-3\">\n <span class=\"sr-only\" id=\"update-payment-exp_month-label\" class=\"pw-label-style\">{{ 'User.Payments.ExpMonth' | transloco }}</span>\n <p-select\n [attr.aria-labelledby]=\"'update-payment-exp_month-label'\"\n [options]=\"months\"\n [appendTo]=\"'body'\"\n formControlName=\"exp_month\"\n [placeholder]=\"'User.Payments.ExpMonth' | transloco\"\n optionValue=\"value\"\n optionLabel=\"value\">\n </p-select>\n @if (form.get('exp_month').touched && form.get('exp_month').errors?.required) {\n <div class=\"danger\"><span>{{ 'User.Payments.Errors.ExpMonthRequired' | transloco }}</span></div>\n }\n </div>\n </div>\n <div class=\"col-md-6\">\n <div class=\"mb-3\">\n <span class=\"sr-only\" id=\"update-payment-exp_year-label\">{{ 'User.Payments.ExpYear' | transloco }}</span>\n <p-select\n [attr.aria-labelledby]=\"'update-payment-exp_year-label'\"\n [options]=\"years\"\n formControlName=\"exp_year\"\n [placeholder]=\"'User.Payments.ExpYear' | transloco\"\n optionValue=\"value\"\n [appendTo]=\"'body'\"\n optionLabel=\"value\">\n </p-select>\n @if (form.get('exp_year')?.touched && form.get('exp_year')?.errors?.['required']) {\n <div class=\"danger\"><span>{{ 'User.Payments.Errors.ExpYearRequired' | transloco }}</span></div>\n }\n </div>\n </div>\n <div class=\"col-12 text-center mt-4\">\n <img src=\"/assets/img/icons/powered_by_stripe_v2.png\"\n class=\"payment-provider\"\n alt=\"\" />\n </div>\n <div class=\"col-12 mt-4 text-end\">\n <button type=\"button\"\n (click)=\"cancel()\"\n class=\"btn btn-outline-default me-2\">\n {{ 'User.Payments.Cancel' | transloco }}\n </button>\n <button type=\"submit\"\n class=\"btn btn-primary\"\n [buttonBusy]=\"busy\">\n {{ 'User.Payments.Submit' | transloco }}\n </button>\n </div>\n </div>\n </form>\n }\n </div>\n </div>\n </div>\n\n <!-- Secondary payment method (Braintree) -->\n <div class=\"col-12 col-lg-6\">\n <div class=\"card payment-right p-3 h-100\">\n <div class=\"card-body\">\n <h5 class=\"section-title\">{{ 'User.Payments.Secondary.Title' | transloco }}</h5>\n <p class=\"alert alert-info\" [pTooltip]=\"'User.Payments.Secondary.Tooltip' | transloco\" tooltipPosition=\"top\" appendTo=\"body\">\n {{ 'User.Payments.Secondary.Callout' | transloco }}\n </p>\n\n @if (loading) {\n <div class=\"text-center\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n\n @if (secondaryCard && !showBraintreeForm) {\n <pw-saved-card-details [data]=\"secondaryCard\"\n (changeEvent)=\"startBraintreeFlow()\">\n </pw-saved-card-details>\n }\n\n @if (!secondaryCard && !showBraintreeForm && !loading) {\n <button type=\"button\"\n class=\"btn btn-primary\"\n (click)=\"startBraintreeFlow()\">\n {{ 'User.Payments.Secondary.AddCta' | transloco }}\n </button>\n }\n\n @if (showBraintreeForm) {\n <div #braintreeContainer class=\"braintree-dropin-container mt-3\"></div>\n <div class=\"col-12 mt-4 text-end\">\n <button type=\"button\"\n (click)=\"cancelBraintreeFlow()\"\n class=\"btn btn-outline-default me-2\">\n {{ 'User.Payments.Cancel' | transloco }}\n </button>\n <button type=\"button\"\n class=\"btn btn-primary\"\n [buttonBusy]=\"braintreeBusy\"\n (click)=\"submitBraintree()\">\n {{ 'User.Payments.Submit' | transloco }}\n </button>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n\n </div>\n</div>\n", styles: [".card-block .payment-left,.card-block .payment-right{border:1px solid rgb(204,204,204)}.card-block .payment-left h4,.card-block .payment-right h4{border-bottom:1px solid rgb(0,0,0);font-size:1rem;font-weight:600;margin:0 0 20px;padding:0 0 5px;text-transform:uppercase}.payment-provider{width:30%}@media(max-width:800px){.payment-provider{width:60%}}\n"], dependencies: [{ kind: "directive", type: i3.ButtonBusyDirective, selector: "[buttonBusy]", inputs: ["buttonBusy", "busyText"] }, { kind: "directive", type: i3.LazyImgDirective, selector: "img" }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i8$1.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "directive", type: i11.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "component", type: SavedCardDetailsComponent, selector: "pw-saved-card-details", inputs: ["data", "isChangePayment", "showNewCard"], outputs: ["changeEvent"] }, { kind: "pipe", type: i8$2.TranslocoPipe, name: "transloco" }] }); }
|
|
1033
1130
|
}
|
|
1034
1131
|
__decorate([
|
|
1035
1132
|
ValidateForm('form'),
|
|
@@ -1056,7 +1153,7 @@ class UpgradeSubscriptionComponent extends AppBaseComponent {
|
|
|
1056
1153
|
}
|
|
1057
1154
|
return 0;
|
|
1058
1155
|
}
|
|
1059
|
-
constructor(injector, productService, fb, modalService, subscriptionService, store, scriptLoader, cdr) {
|
|
1156
|
+
constructor(injector, productService, fb, modalService, subscriptionService, store, scriptLoader, cdr, confirmDialog) {
|
|
1060
1157
|
super(injector);
|
|
1061
1158
|
this.productService = productService;
|
|
1062
1159
|
this.fb = fb;
|
|
@@ -1065,6 +1162,7 @@ class UpgradeSubscriptionComponent extends AppBaseComponent {
|
|
|
1065
1162
|
this.store = store;
|
|
1066
1163
|
this.scriptLoader = scriptLoader;
|
|
1067
1164
|
this.cdr = cdr;
|
|
1165
|
+
this.confirmDialog = confirmDialog;
|
|
1068
1166
|
this.months = [];
|
|
1069
1167
|
this.years = [];
|
|
1070
1168
|
this.form = this.fb.group({
|
|
@@ -1248,12 +1346,10 @@ class UpgradeSubscriptionComponent extends AppBaseComponent {
|
|
|
1248
1346
|
});
|
|
1249
1347
|
}
|
|
1250
1348
|
noPasswordModal() {
|
|
1251
|
-
|
|
1349
|
+
this.confirmDialog.open({
|
|
1252
1350
|
title: 'Set Password',
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
<strong><a href="/account/details">Click here to reset</a></strong>`,
|
|
1256
|
-
confirmButtonText: 'OK'
|
|
1351
|
+
text: '<div>Please set a password before changing the subscription in the account section.</div><br /><strong><a href="/account/details">Click here to reset</a></strong>',
|
|
1352
|
+
confirmOnly: true
|
|
1257
1353
|
});
|
|
1258
1354
|
}
|
|
1259
1355
|
getCardDetails(subscriptionId) {
|
|
@@ -1313,8 +1409,8 @@ class UpgradeSubscriptionComponent extends AppBaseComponent {
|
|
|
1313
1409
|
ngOnDestroy() {
|
|
1314
1410
|
super.ngOnDestroy();
|
|
1315
1411
|
}
|
|
1316
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: UpgradeSubscriptionComponent, deps: [{ token: i0.Injector }, { token: i1$2.ProductService }, { token: i2.UntypedFormBuilder }, { token: i1$1.NgbModal }, { token: i1$2.SubscriptionService }, { token: i4$
|
|
1317
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: UpgradeSubscriptionComponent, isStandalone: false, selector: "pw-upgrade-subscription", viewQueries: [{ propertyName: "passwordValidationModal", first: true, predicate: ["passwordValidationModal"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<h4 class=\"form-section m-3\">\n <i class=\"ft-check-circle\" aria-hidden=\"true\"></i> {{ 'Button.Payment' | transloco }}\n</h4>\n<div class=\"card-block\">\n <!-- Show Payment Page when there is user.has_stripe_account===false -->\n <ng-container>\n <form class=\"form\"\n (ngSubmit)=\"attemptPurchase()\"\n [formGroup]=\"form\">\n <div class=\"row\">\n <div class=\"col-md-6\">\n <div class=\"form-body p-3 payment-left card pb-0\">\n <div class=\"card-body\">\n @if (product?.max_units > 1) {\n <div class=\"row\"\n >\n <div class=\"col-12\">\n <div class=\"mb-3\">\n <h4 class=\"title\">\n {{ 'User.Subscriptions.LicensesRequired' | transloco }}\n </h4>\n <div class=\"row btns-row\">\n <div class=\"col-md-4 col-8\">\n <pw-number-picker name=\"number-picker\"\n [(value)]=\"units\"\n [min]=\"subscription.min_units || product.min_units\"\n [max]=\"product.max_units\"\n step=\"1\"\n postfix=\"Units\"\n placeholder=\"Total Licenses\"\n [inputReadOnly]=\"false\"\n size=\"small\"\n pickStartAfter=\"500\"\n pickTimer=\"100\"\n [arrowKeys]=\"true\"\n (minReached)=\"onMinReached($event)\"\n (maxReached)=\"onMaxReached($event)\"\n (valueChange)=\"onUnitChange($event)\">\n </pw-number-picker>\n </div>\n </div>\n <div class=\"text-center\">\n <small class=\"form-text text-muted danger\">\n {{ unitError }}\n </small>\n </div>\n </div>\n <p>\n If you proceed, your credit card will be charged\n <strong>{{ product.currency }}\n {{ totalAmount | number:'1.2-2' }}</strong>\n </p>\n </div>\n </div>\n }\n <!-- Shows Saved Card: Shows when user has card details and not trying to update the card details -->\n @if (cardDetails) {\n <pw-saved-card-details [data]=\"cardDetails\"\n (changeEvent)=\"showNewCard = $event\"\n [showNewCard]=\"showNewCard\">\n </pw-saved-card-details>\n }\n <!-- Add New Payment Starts, opens up when user doesn't have stripe account or tries to change the\n card details -->\n @if ((user && !cardDetails) || (cardDetails && showNewCard)) {\n <h4 class=\"title\">\n {{ 'User.Subscriptions.NewCard' | transloco }}?\n </h4>\n <div class=\"row\">\n <div class=\"col-md-9\">\n <div class=\"mb-3\">\n <label for=\"upgrade-subscription-card_number\">{{\n 'User.Subscriptions.CardNumber' | transloco\n }}</label>\n <input type=\"text\"\n id=\"upgrade-subscription-card_number\"\n class=\"form-control\"\n formControlName=\"card_number\"\n placeholder=\"Card Number\"\n name=\"card_number\" />\n @if (\n form.get('card_number').touched &&\n form.get('card_number').errors?.required\n ) {\n <div class=\"danger\"\n >\n <span> Please enter card number. </span>\n </div>\n }\n </div>\n </div>\n <div class=\"col-md-3\">\n <div class=\"mb-3\">\n <label for=\"upgrade-subscription-cvc\">{{\n 'User.Subscriptions.CVC' | transloco\n }}</label>\n <input type=\"text\"\n id=\"upgrade-subscription-cvc\"\n class=\"form-control\"\n formControlName=\"cvc\"\n placeholder=\"CVC\"\n name=\"cvc\" />\n @if (\n form.get('cvc').touched &&\n form.get('cvc').errors?.required\n ) {\n <div class=\"danger\"\n >\n <span> Please enter cvc. </span>\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"row\">\n <div class=\"col-md-6\">\n <div class=\"mb-3\">\n <span class=\"sr-only pw-label-style\" id=\"upgrade-subscription-exp_month-label\">Exp. Month</span>\n <p-select\n [attr.aria-labelledby]=\"'upgrade-subscription-exp_month-label'\"\n [options]=\"months\"\n formControlName=\"exp_month\"\n [placeholder]=\"'Exp. Month'\"\n optionValue=\"value\"\n [appendTo]=\"'body'\"\n optionLabel=\"value\">\n </p-select>\n @if (\n form.get('exp_month').touched &&\n form.get('exp_month').errors?.required\n ) {\n <div class=\"danger\"\n >\n <span> Please enter expiry month. </span>\n </div>\n }\n </div>\n </div>\n <div class=\"col-md-6\">\n <div class=\"mb-3\">\n <span class=\"sr-only\" id=\"upgrade-subscription-exp_year-label\">Exp. Year</span>\n <p-select\n [attr.aria-labelledby]=\"'upgrade-subscription-exp_year-label'\"\n [options]=\"years\"\n formControlName=\"exp_year\"\n [placeholder]=\"'Exp. Year'\"\n [appendTo]=\"'body'\"\n optionValue=\"value\"\n optionLabel=\"value\">\n </p-select>\n @if (\n form.get('exp_year').touched &&\n form.get('exp_year').errors?.required\n ) {\n <div class=\"danger\"\n >\n <span> Please enter expiry year. </span>\n </div>\n }\n </div>\n </div>\n @if (cardDetails) {\n <div class=\"col-12 mt-2\"\n >\n <a aria-label=\"Navigate to Target\"\n (click)=\"showNewCard = false; onDiscardToggle()\">Disregard and pay with current registered card</a>\n </div>\n }\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Purchase Summary -->\n @if (product) {\n <div class=\"col-md-6\"\n >\n <div class=\"purchase-summary card p-3 payment-right\">\n <div class=\"card-body\">\n <h4 class=\"title\">{{ 'Label.PurchaseSummary' | transloco }}</h4>\n <div class=\"summary-row d-flex mb-2\">\n <div class=\"summary-left\">{{ 'Label.Plan' | transloco }}:</div>\n <div class=\"summary-right\">{{ product.name }}</div>\n </div>\n <div class=\"summary-row d-flex mb-2\">\n <div class=\"summary-left\">{{ 'Label.Price' | transloco }}:</div>\n <div class=\"summary-right\">\n {{ product.currency }}\n {{ (product.price_per_unit / 100) | number:'1.2-2' }}\n </div>\n </div>\n <div class=\"summary-row d-flex mb-2\">\n <div class=\"summary-left\">{{ 'Label.Seats' | transloco }}:</div>\n <div class=\"summary-right\">{{ form.get('units').value }}</div>\n </div>\n <div class=\"summary-row d-flex mb-2\">\n <div class=\"summary-left\">{{ 'Label.Total' | transloco }}:</div>\n <div class=\"summary-right\">\n {{ product.currency }} {{ totalAmount | number:'1.2-2' }}\n </div>\n </div>\n <div class=\"summary-row d-flex mb-2\">\n <div class=\"summary-left\">\n {{ 'Label.Recurrency' | transloco }}:\n </div>\n <div class=\"summary-right\">{{ product.billing_frequency }}</div>\n </div>\n </div>\n <div class=\"text-center\">\n <hr />\n <p>\n By subscribing you acknowledge and accept our terms of service and\n privacy policy\n </p>\n </div>\n </div>\n </div>\n }\n </div>\n <div class=\"row\">\n <div class=\"col-12 text-center mt-3\">\n <img src=\"/assets/img/icons/powered_by_stripe_v2.png\"\n class=\"payment-provider\"\n alt=\"\" />\n </div>\n </div>\n <div class=\"row\">\n <div class=\"col-12\">\n <div class=\"form-actions text-end\">\n <button type=\"button\"\n class=\"btn btn-raised btn-outline-default me-1\"\n [disabled]=\"isPurchaseAttempted\"\n routerLink=\"/account/subscriptions\">\n <i class=\"ft-x\" aria-hidden=\"true\"></i>{{ 'Button.Back' | transloco }}\n </button>\n <button type=\"submit\"\n class=\"btn btn-raised btn-primary\"\n [disabled]=\"isPurchaseAttempted\"\n [buttonBusy]=\"busy\">\n <i class=\"ft-check\" aria-hidden=\"true\"></i>\n {{ 'Button.Purchase' | transloco }}\n </button>\n </div>\n </div>\n </div>\n </form>\n </ng-container>\n</div>\n\n<pw-password-validation #passwordValidationModal\n (successEvent)=\"onValidatePassword($event)\">\n <div class=\"row\">\n <div class=\"col-12\">\n <p>\n If you proceed, your credit card will be charged\n @if (totalAmount) {\n <strong>{{ product.currency }} {{ totalAmount | number:'1.2-2' }}</strong>\n }\n </p>\n </div>\n </div>\n</pw-password-validation>\n", styles: [".payment-left,.payment-right{border:1px solid rgb(204,204,204);height:100%}.payment-left h4,.payment-right h4{border-bottom:1px solid rgb(0,0,0);font-size:1rem;font-weight:600;margin:0 0 20px;padding:0 0 5px;text-transform:uppercase}.payment-left .summary-row.total,.payment-right .summary-row.total{padding:10px 0 0 10px}.payment-left .summary-row .summary-left,.payment-right .summary-row .summary-left{font-weight:600}.payment-provider{width:20%}@media(max-width:800px){.payment-provider{width:60%}}.summary-left{-webkit-box-flex:1;color:#555;flex-grow:1;-ms-flex-positive:1;font-weight:200;text-align:left}.summary-left.plan{color:#c93f00;font-size:14px;margin:5px 0}.summary-right{-webkit-box-flex:1;-webkit-box-pack:end;color:#000;flex-grow:1;-ms-flex-pack:end;-ms-flex-positive:1;justify-content:flex-end;text-align:right}\n"], dependencies: [{ kind: "directive", type: i4.ButtonBusyDirective, selector: "[buttonBusy]", inputs: ["buttonBusy", "busyText"] }, { kind: "directive", type: i4.LazyImgDirective, selector: "img" }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i5.PasswordValidationComponent, selector: "pw-password-validation", inputs: ["confirmMessage"], outputs: ["successEvent"] }, { kind: "component", type: i6$2.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i5.NumberPickerComponent, selector: "pw-number-picker", inputs: ["min", "showTooltip", "tooltipText", "max", "step", "value", "pickStartAfter", "pickTimer", "prefix", "postfix", "placeholder", "buttonsOrientation", "size", "customClass", "mouseWheel", "arrowKeys", "inputReadOnly", "showUpButton", "showDownButton", "inputId"], outputs: ["valueChange", "minReached", "maxReached", "pickStarted", "pickStopped", "pickUpStarted", "pickUpStopped", "pickDownStarted", "pickDownStopped"] }, { kind: "component", type: SavedCardDetailsComponent, selector: "pw-saved-card-details", inputs: ["data", "isChangePayment", "showNewCard"], outputs: ["changeEvent"] }, { kind: "pipe", type: i6.DecimalPipe, name: "number" }, { kind: "pipe", type: i8.TranslocoPipe, name: "transloco" }] }); }
|
|
1412
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: UpgradeSubscriptionComponent, deps: [{ token: i0.Injector }, { token: i1$2.ProductService }, { token: i2.UntypedFormBuilder }, { token: i1$1.NgbModal }, { token: i1$2.SubscriptionService }, { token: i4$1.Store }, { token: i1$2.ScriptLoaderService }, { token: i0.ChangeDetectorRef }, { token: i5.ConfirmDialogService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1413
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: UpgradeSubscriptionComponent, isStandalone: false, selector: "pw-upgrade-subscription", viewQueries: [{ propertyName: "passwordValidationModal", first: true, predicate: ["passwordValidationModal"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<h4 class=\"form-section m-3\">\n <i class=\"ft-check-circle\" aria-hidden=\"true\"></i> {{ 'Button.Payment' | transloco }}\n</h4>\n<div class=\"card-block\">\n <!-- Show Payment Page when there is user.has_stripe_account===false -->\n <ng-container>\n <form class=\"form\"\n (ngSubmit)=\"attemptPurchase()\"\n [formGroup]=\"form\">\n <div class=\"row\">\n <div class=\"col-md-6\">\n <div class=\"form-body p-3 payment-left card pb-0\">\n <div class=\"card-body\">\n @if (product?.max_units > 1) {\n <div class=\"row\"\n >\n <div class=\"col-12\">\n <div class=\"mb-3\">\n <h4 class=\"title\">\n {{ 'User.Subscriptions.LicensesRequired' | transloco }}\n </h4>\n <div class=\"row btns-row\">\n <div class=\"col-md-4 col-8\">\n <pw-number-picker name=\"number-picker\"\n [(value)]=\"units\"\n [min]=\"subscription.min_units || product.min_units\"\n [max]=\"product.max_units\"\n step=\"1\"\n postfix=\"Units\"\n placeholder=\"Total Licenses\"\n [inputReadOnly]=\"false\"\n size=\"small\"\n pickStartAfter=\"500\"\n pickTimer=\"100\"\n [arrowKeys]=\"true\"\n (minReached)=\"onMinReached($event)\"\n (maxReached)=\"onMaxReached($event)\"\n (valueChange)=\"onUnitChange($event)\">\n </pw-number-picker>\n </div>\n </div>\n <div class=\"text-center\">\n <small class=\"form-text text-muted danger\">\n {{ unitError }}\n </small>\n </div>\n </div>\n <p>\n If you proceed, your credit card will be charged\n <strong>{{ product.currency }}\n {{ totalAmount | number:'1.2-2' }}</strong>\n </p>\n </div>\n </div>\n }\n <!-- Shows Saved Card: Shows when user has card details and not trying to update the card details -->\n @if (cardDetails) {\n <pw-saved-card-details [data]=\"cardDetails\"\n (changeEvent)=\"showNewCard = $event\"\n [showNewCard]=\"showNewCard\">\n </pw-saved-card-details>\n }\n <!-- Add New Payment Starts, opens up when user doesn't have stripe account or tries to change the\n card details -->\n @if ((user && !cardDetails) || (cardDetails && showNewCard)) {\n <h4 class=\"title\">\n {{ 'User.Subscriptions.NewCard' | transloco }}?\n </h4>\n <div class=\"row\">\n <div class=\"col-md-9\">\n <div class=\"mb-3\">\n <label for=\"upgrade-subscription-card_number\">{{\n 'User.Subscriptions.CardNumber' | transloco\n }}</label>\n <input type=\"text\"\n id=\"upgrade-subscription-card_number\"\n class=\"form-control\"\n formControlName=\"card_number\"\n placeholder=\"Card Number\"\n name=\"card_number\" />\n @if (\n form.get('card_number').touched &&\n form.get('card_number').errors?.required\n ) {\n <div class=\"danger\"\n >\n <span> Please enter card number. </span>\n </div>\n }\n </div>\n </div>\n <div class=\"col-md-3\">\n <div class=\"mb-3\">\n <label for=\"upgrade-subscription-cvc\">{{\n 'User.Subscriptions.CVC' | transloco\n }}</label>\n <input type=\"text\"\n id=\"upgrade-subscription-cvc\"\n class=\"form-control\"\n formControlName=\"cvc\"\n placeholder=\"CVC\"\n name=\"cvc\" />\n @if (\n form.get('cvc').touched &&\n form.get('cvc').errors?.required\n ) {\n <div class=\"danger\"\n >\n <span> Please enter cvc. </span>\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"row\">\n <div class=\"col-md-6\">\n <div class=\"mb-3\">\n <span class=\"sr-only pw-label-style\" id=\"upgrade-subscription-exp_month-label\">Exp. Month</span>\n <p-select\n [attr.aria-labelledby]=\"'upgrade-subscription-exp_month-label'\"\n [options]=\"months\"\n formControlName=\"exp_month\"\n [placeholder]=\"'Exp. Month'\"\n optionValue=\"value\"\n [appendTo]=\"'body'\"\n optionLabel=\"value\">\n </p-select>\n @if (\n form.get('exp_month').touched &&\n form.get('exp_month').errors?.required\n ) {\n <div class=\"danger\"\n >\n <span> Please enter expiry month. </span>\n </div>\n }\n </div>\n </div>\n <div class=\"col-md-6\">\n <div class=\"mb-3\">\n <span class=\"sr-only\" id=\"upgrade-subscription-exp_year-label\">Exp. Year</span>\n <p-select\n [attr.aria-labelledby]=\"'upgrade-subscription-exp_year-label'\"\n [options]=\"years\"\n formControlName=\"exp_year\"\n [placeholder]=\"'Exp. Year'\"\n [appendTo]=\"'body'\"\n optionValue=\"value\"\n optionLabel=\"value\">\n </p-select>\n @if (\n form.get('exp_year').touched &&\n form.get('exp_year').errors?.required\n ) {\n <div class=\"danger\"\n >\n <span> Please enter expiry year. </span>\n </div>\n }\n </div>\n </div>\n @if (cardDetails) {\n <div class=\"col-12 mt-2\"\n >\n <a aria-label=\"Navigate to Target\"\n (click)=\"showNewCard = false; onDiscardToggle()\">Disregard and pay with current registered card</a>\n </div>\n }\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Purchase Summary -->\n @if (product) {\n <div class=\"col-md-6\"\n >\n <div class=\"purchase-summary card p-3 payment-right\">\n <div class=\"card-body\">\n <h4 class=\"title\">{{ 'Label.PurchaseSummary' | transloco }}</h4>\n <div class=\"summary-row d-flex mb-2\">\n <div class=\"summary-left\">{{ 'Label.Plan' | transloco }}:</div>\n <div class=\"summary-right\">{{ product.name }}</div>\n </div>\n <div class=\"summary-row d-flex mb-2\">\n <div class=\"summary-left\">{{ 'Label.Price' | transloco }}:</div>\n <div class=\"summary-right\">\n {{ product.currency }}\n {{ (product.price_per_unit / 100) | number:'1.2-2' }}\n </div>\n </div>\n <div class=\"summary-row d-flex mb-2\">\n <div class=\"summary-left\">{{ 'Label.Seats' | transloco }}:</div>\n <div class=\"summary-right\">{{ form.get('units').value }}</div>\n </div>\n <div class=\"summary-row d-flex mb-2\">\n <div class=\"summary-left\">{{ 'Label.Total' | transloco }}:</div>\n <div class=\"summary-right\">\n {{ product.currency }} {{ totalAmount | number:'1.2-2' }}\n </div>\n </div>\n <div class=\"summary-row d-flex mb-2\">\n <div class=\"summary-left\">\n {{ 'Label.Recurrency' | transloco }}:\n </div>\n <div class=\"summary-right\">{{ product.billing_frequency }}</div>\n </div>\n </div>\n <div class=\"text-center\">\n <hr />\n <p>\n By subscribing you acknowledge and accept our terms of service and\n privacy policy\n </p>\n </div>\n </div>\n </div>\n }\n </div>\n <div class=\"row\">\n <div class=\"col-12 text-center mt-3\">\n <img src=\"/assets/img/icons/powered_by_stripe_v2.png\"\n class=\"payment-provider\"\n alt=\"\" />\n </div>\n </div>\n <div class=\"row\">\n <div class=\"col-12\">\n <div class=\"form-actions text-end\">\n <button type=\"button\"\n class=\"btn btn-raised btn-outline-default me-1\"\n [disabled]=\"isPurchaseAttempted\"\n routerLink=\"/account/subscriptions\">\n <i class=\"ft-x\" aria-hidden=\"true\"></i>{{ 'Button.Back' | transloco }}\n </button>\n <button type=\"submit\"\n class=\"btn btn-raised btn-primary\"\n [disabled]=\"isPurchaseAttempted\"\n [buttonBusy]=\"busy\">\n <i class=\"ft-check\" aria-hidden=\"true\"></i>\n {{ 'Button.Purchase' | transloco }}\n </button>\n </div>\n </div>\n </div>\n </form>\n </ng-container>\n</div>\n\n<pw-password-validation #passwordValidationModal\n (successEvent)=\"onValidatePassword($event)\">\n <div class=\"row\">\n <div class=\"col-12\">\n <p>\n If you proceed, your credit card will be charged\n @if (totalAmount) {\n <strong>{{ product.currency }} {{ totalAmount | number:'1.2-2' }}</strong>\n }\n </p>\n </div>\n </div>\n</pw-password-validation>\n", styles: [".payment-left,.payment-right{border:1px solid rgb(204,204,204);height:100%}.payment-left h4,.payment-right h4{border-bottom:1px solid rgb(0,0,0);font-size:1rem;font-weight:600;margin:0 0 20px;padding:0 0 5px;text-transform:uppercase}.payment-left .summary-row.total,.payment-right .summary-row.total{padding:10px 0 0 10px}.payment-left .summary-row .summary-left,.payment-right .summary-row .summary-left{font-weight:600}.payment-provider{width:20%}@media(max-width:800px){.payment-provider{width:60%}}.summary-left{-webkit-box-flex:1;color:#555;flex-grow:1;-ms-flex-positive:1;font-weight:200;text-align:left}.summary-left.plan{color:#c93f00;font-size:14px;margin:5px 0}.summary-right{-webkit-box-flex:1;-webkit-box-pack:end;color:#000;flex-grow:1;-ms-flex-pack:end;-ms-flex-positive:1;justify-content:flex-end;text-align:right}\n"], dependencies: [{ kind: "directive", type: i3.ButtonBusyDirective, selector: "[buttonBusy]", inputs: ["buttonBusy", "busyText"] }, { kind: "directive", type: i3.LazyImgDirective, selector: "img" }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i5.PasswordValidationComponent, selector: "pw-password-validation", inputs: ["confirmMessage", "destructive"], outputs: ["successEvent"] }, { kind: "component", type: i8$1.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i5.NumberPickerComponent, selector: "pw-number-picker", inputs: ["min", "showTooltip", "tooltipText", "max", "step", "value", "pickStartAfter", "pickTimer", "prefix", "postfix", "placeholder", "buttonsOrientation", "size", "customClass", "mouseWheel", "arrowKeys", "inputReadOnly", "showUpButton", "showDownButton", "inputId"], outputs: ["valueChange", "minReached", "maxReached", "pickStarted", "pickStopped", "pickUpStarted", "pickUpStopped", "pickDownStarted", "pickDownStopped"] }, { kind: "component", type: SavedCardDetailsComponent, selector: "pw-saved-card-details", inputs: ["data", "isChangePayment", "showNewCard"], outputs: ["changeEvent"] }, { kind: "pipe", type: i8.DecimalPipe, name: "number" }, { kind: "pipe", type: i8$2.TranslocoPipe, name: "transloco" }] }); }
|
|
1318
1414
|
}
|
|
1319
1415
|
__decorate([
|
|
1320
1416
|
ValidateForm('form'),
|
|
@@ -1325,7 +1421,7 @@ __decorate([
|
|
|
1325
1421
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: UpgradeSubscriptionComponent, decorators: [{
|
|
1326
1422
|
type: Component,
|
|
1327
1423
|
args: [{ selector: 'pw-upgrade-subscription', standalone: false, template: "<h4 class=\"form-section m-3\">\n <i class=\"ft-check-circle\" aria-hidden=\"true\"></i> {{ 'Button.Payment' | transloco }}\n</h4>\n<div class=\"card-block\">\n <!-- Show Payment Page when there is user.has_stripe_account===false -->\n <ng-container>\n <form class=\"form\"\n (ngSubmit)=\"attemptPurchase()\"\n [formGroup]=\"form\">\n <div class=\"row\">\n <div class=\"col-md-6\">\n <div class=\"form-body p-3 payment-left card pb-0\">\n <div class=\"card-body\">\n @if (product?.max_units > 1) {\n <div class=\"row\"\n >\n <div class=\"col-12\">\n <div class=\"mb-3\">\n <h4 class=\"title\">\n {{ 'User.Subscriptions.LicensesRequired' | transloco }}\n </h4>\n <div class=\"row btns-row\">\n <div class=\"col-md-4 col-8\">\n <pw-number-picker name=\"number-picker\"\n [(value)]=\"units\"\n [min]=\"subscription.min_units || product.min_units\"\n [max]=\"product.max_units\"\n step=\"1\"\n postfix=\"Units\"\n placeholder=\"Total Licenses\"\n [inputReadOnly]=\"false\"\n size=\"small\"\n pickStartAfter=\"500\"\n pickTimer=\"100\"\n [arrowKeys]=\"true\"\n (minReached)=\"onMinReached($event)\"\n (maxReached)=\"onMaxReached($event)\"\n (valueChange)=\"onUnitChange($event)\">\n </pw-number-picker>\n </div>\n </div>\n <div class=\"text-center\">\n <small class=\"form-text text-muted danger\">\n {{ unitError }}\n </small>\n </div>\n </div>\n <p>\n If you proceed, your credit card will be charged\n <strong>{{ product.currency }}\n {{ totalAmount | number:'1.2-2' }}</strong>\n </p>\n </div>\n </div>\n }\n <!-- Shows Saved Card: Shows when user has card details and not trying to update the card details -->\n @if (cardDetails) {\n <pw-saved-card-details [data]=\"cardDetails\"\n (changeEvent)=\"showNewCard = $event\"\n [showNewCard]=\"showNewCard\">\n </pw-saved-card-details>\n }\n <!-- Add New Payment Starts, opens up when user doesn't have stripe account or tries to change the\n card details -->\n @if ((user && !cardDetails) || (cardDetails && showNewCard)) {\n <h4 class=\"title\">\n {{ 'User.Subscriptions.NewCard' | transloco }}?\n </h4>\n <div class=\"row\">\n <div class=\"col-md-9\">\n <div class=\"mb-3\">\n <label for=\"upgrade-subscription-card_number\">{{\n 'User.Subscriptions.CardNumber' | transloco\n }}</label>\n <input type=\"text\"\n id=\"upgrade-subscription-card_number\"\n class=\"form-control\"\n formControlName=\"card_number\"\n placeholder=\"Card Number\"\n name=\"card_number\" />\n @if (\n form.get('card_number').touched &&\n form.get('card_number').errors?.required\n ) {\n <div class=\"danger\"\n >\n <span> Please enter card number. </span>\n </div>\n }\n </div>\n </div>\n <div class=\"col-md-3\">\n <div class=\"mb-3\">\n <label for=\"upgrade-subscription-cvc\">{{\n 'User.Subscriptions.CVC' | transloco\n }}</label>\n <input type=\"text\"\n id=\"upgrade-subscription-cvc\"\n class=\"form-control\"\n formControlName=\"cvc\"\n placeholder=\"CVC\"\n name=\"cvc\" />\n @if (\n form.get('cvc').touched &&\n form.get('cvc').errors?.required\n ) {\n <div class=\"danger\"\n >\n <span> Please enter cvc. </span>\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"row\">\n <div class=\"col-md-6\">\n <div class=\"mb-3\">\n <span class=\"sr-only pw-label-style\" id=\"upgrade-subscription-exp_month-label\">Exp. Month</span>\n <p-select\n [attr.aria-labelledby]=\"'upgrade-subscription-exp_month-label'\"\n [options]=\"months\"\n formControlName=\"exp_month\"\n [placeholder]=\"'Exp. Month'\"\n optionValue=\"value\"\n [appendTo]=\"'body'\"\n optionLabel=\"value\">\n </p-select>\n @if (\n form.get('exp_month').touched &&\n form.get('exp_month').errors?.required\n ) {\n <div class=\"danger\"\n >\n <span> Please enter expiry month. </span>\n </div>\n }\n </div>\n </div>\n <div class=\"col-md-6\">\n <div class=\"mb-3\">\n <span class=\"sr-only\" id=\"upgrade-subscription-exp_year-label\">Exp. Year</span>\n <p-select\n [attr.aria-labelledby]=\"'upgrade-subscription-exp_year-label'\"\n [options]=\"years\"\n formControlName=\"exp_year\"\n [placeholder]=\"'Exp. Year'\"\n [appendTo]=\"'body'\"\n optionValue=\"value\"\n optionLabel=\"value\">\n </p-select>\n @if (\n form.get('exp_year').touched &&\n form.get('exp_year').errors?.required\n ) {\n <div class=\"danger\"\n >\n <span> Please enter expiry year. </span>\n </div>\n }\n </div>\n </div>\n @if (cardDetails) {\n <div class=\"col-12 mt-2\"\n >\n <a aria-label=\"Navigate to Target\"\n (click)=\"showNewCard = false; onDiscardToggle()\">Disregard and pay with current registered card</a>\n </div>\n }\n </div>\n }\n </div>\n </div>\n </div>\n <!-- Purchase Summary -->\n @if (product) {\n <div class=\"col-md-6\"\n >\n <div class=\"purchase-summary card p-3 payment-right\">\n <div class=\"card-body\">\n <h4 class=\"title\">{{ 'Label.PurchaseSummary' | transloco }}</h4>\n <div class=\"summary-row d-flex mb-2\">\n <div class=\"summary-left\">{{ 'Label.Plan' | transloco }}:</div>\n <div class=\"summary-right\">{{ product.name }}</div>\n </div>\n <div class=\"summary-row d-flex mb-2\">\n <div class=\"summary-left\">{{ 'Label.Price' | transloco }}:</div>\n <div class=\"summary-right\">\n {{ product.currency }}\n {{ (product.price_per_unit / 100) | number:'1.2-2' }}\n </div>\n </div>\n <div class=\"summary-row d-flex mb-2\">\n <div class=\"summary-left\">{{ 'Label.Seats' | transloco }}:</div>\n <div class=\"summary-right\">{{ form.get('units').value }}</div>\n </div>\n <div class=\"summary-row d-flex mb-2\">\n <div class=\"summary-left\">{{ 'Label.Total' | transloco }}:</div>\n <div class=\"summary-right\">\n {{ product.currency }} {{ totalAmount | number:'1.2-2' }}\n </div>\n </div>\n <div class=\"summary-row d-flex mb-2\">\n <div class=\"summary-left\">\n {{ 'Label.Recurrency' | transloco }}:\n </div>\n <div class=\"summary-right\">{{ product.billing_frequency }}</div>\n </div>\n </div>\n <div class=\"text-center\">\n <hr />\n <p>\n By subscribing you acknowledge and accept our terms of service and\n privacy policy\n </p>\n </div>\n </div>\n </div>\n }\n </div>\n <div class=\"row\">\n <div class=\"col-12 text-center mt-3\">\n <img src=\"/assets/img/icons/powered_by_stripe_v2.png\"\n class=\"payment-provider\"\n alt=\"\" />\n </div>\n </div>\n <div class=\"row\">\n <div class=\"col-12\">\n <div class=\"form-actions text-end\">\n <button type=\"button\"\n class=\"btn btn-raised btn-outline-default me-1\"\n [disabled]=\"isPurchaseAttempted\"\n routerLink=\"/account/subscriptions\">\n <i class=\"ft-x\" aria-hidden=\"true\"></i>{{ 'Button.Back' | transloco }}\n </button>\n <button type=\"submit\"\n class=\"btn btn-raised btn-primary\"\n [disabled]=\"isPurchaseAttempted\"\n [buttonBusy]=\"busy\">\n <i class=\"ft-check\" aria-hidden=\"true\"></i>\n {{ 'Button.Purchase' | transloco }}\n </button>\n </div>\n </div>\n </div>\n </form>\n </ng-container>\n</div>\n\n<pw-password-validation #passwordValidationModal\n (successEvent)=\"onValidatePassword($event)\">\n <div class=\"row\">\n <div class=\"col-12\">\n <p>\n If you proceed, your credit card will be charged\n @if (totalAmount) {\n <strong>{{ product.currency }} {{ totalAmount | number:'1.2-2' }}</strong>\n }\n </p>\n </div>\n </div>\n</pw-password-validation>\n", styles: [".payment-left,.payment-right{border:1px solid rgb(204,204,204);height:100%}.payment-left h4,.payment-right h4{border-bottom:1px solid rgb(0,0,0);font-size:1rem;font-weight:600;margin:0 0 20px;padding:0 0 5px;text-transform:uppercase}.payment-left .summary-row.total,.payment-right .summary-row.total{padding:10px 0 0 10px}.payment-left .summary-row .summary-left,.payment-right .summary-row .summary-left{font-weight:600}.payment-provider{width:20%}@media(max-width:800px){.payment-provider{width:60%}}.summary-left{-webkit-box-flex:1;color:#555;flex-grow:1;-ms-flex-positive:1;font-weight:200;text-align:left}.summary-left.plan{color:#c93f00;font-size:14px;margin:5px 0}.summary-right{-webkit-box-flex:1;-webkit-box-pack:end;color:#000;flex-grow:1;-ms-flex-pack:end;-ms-flex-positive:1;justify-content:flex-end;text-align:right}\n"] }]
|
|
1328
|
-
}], ctorParameters: () => [{ type: i0.Injector }, { type: i1$2.ProductService }, { type: i2.UntypedFormBuilder }, { type: i1$1.NgbModal }, { type: i1$2.SubscriptionService }, { type: i4$
|
|
1424
|
+
}], ctorParameters: () => [{ type: i0.Injector }, { type: i1$2.ProductService }, { type: i2.UntypedFormBuilder }, { type: i1$1.NgbModal }, { type: i1$2.SubscriptionService }, { type: i4$1.Store }, { type: i1$2.ScriptLoaderService }, { type: i0.ChangeDetectorRef }, { type: i5.ConfirmDialogService }], propDecorators: { passwordValidationModal: [{
|
|
1329
1425
|
type: ViewChild,
|
|
1330
1426
|
args: ['passwordValidationModal', { static: true }]
|
|
1331
1427
|
}], updateCardDetails: [] } });
|
|
@@ -1335,7 +1431,7 @@ class UserSubscriptionDetailsComponent extends AppBaseComponent {
|
|
|
1335
1431
|
const allProductsPrice = this.subscription.products.map(x => x.price_per_unit * this.units);
|
|
1336
1432
|
return allProductsPrice.reduce((a, b) => a + b, 0) / 100;
|
|
1337
1433
|
}
|
|
1338
|
-
constructor(fb, geoService, modalService, subscriptionService, store, injector, cdr) {
|
|
1434
|
+
constructor(fb, geoService, modalService, subscriptionService, store, injector, cdr, confirmDialog) {
|
|
1339
1435
|
super(injector);
|
|
1340
1436
|
this.fb = fb;
|
|
1341
1437
|
this.geoService = geoService;
|
|
@@ -1343,6 +1439,7 @@ class UserSubscriptionDetailsComponent extends AppBaseComponent {
|
|
|
1343
1439
|
this.subscriptionService = subscriptionService;
|
|
1344
1440
|
this.store = store;
|
|
1345
1441
|
this.cdr = cdr;
|
|
1442
|
+
this.confirmDialog = confirmDialog;
|
|
1346
1443
|
this.busyButton = false;
|
|
1347
1444
|
this.units = 1;
|
|
1348
1445
|
this.fullLogoBroken = false;
|
|
@@ -1542,16 +1639,15 @@ class UserSubscriptionDetailsComponent extends AppBaseComponent {
|
|
|
1542
1639
|
this.showApiClientId = !this.showApiClientId;
|
|
1543
1640
|
}
|
|
1544
1641
|
refreshApiTokens() {
|
|
1545
|
-
|
|
1642
|
+
this.confirmDialog
|
|
1643
|
+
.open({
|
|
1546
1644
|
title: 'Are you sure?',
|
|
1547
1645
|
text: 'This will expire the current tokens.',
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
}).then(result => {
|
|
1554
|
-
if (result.isConfirmed) {
|
|
1646
|
+
destructive: true,
|
|
1647
|
+
confirmLabel: 'Yes, refresh tokens!'
|
|
1648
|
+
})
|
|
1649
|
+
.then(ok => {
|
|
1650
|
+
if (ok) {
|
|
1555
1651
|
this.performTokenRefresh();
|
|
1556
1652
|
}
|
|
1557
1653
|
});
|
|
@@ -1586,8 +1682,8 @@ class UserSubscriptionDetailsComponent extends AppBaseComponent {
|
|
|
1586
1682
|
super.ngOnDestroy();
|
|
1587
1683
|
this.allowUpdate = false;
|
|
1588
1684
|
}
|
|
1589
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: UserSubscriptionDetailsComponent, deps: [{ token: i2.UntypedFormBuilder }, { token: i1$2.GeoService }, { token: i1$1.NgbModal }, { token: i1$2.SubscriptionService }, { token: i4$
|
|
1590
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: UserSubscriptionDetailsComponent, isStandalone: false, selector: "ng-component", viewQueries: [{ propertyName: "modal", first: true, predicate: ["modal"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<!-- edit Subscription details page -->\n<div class=\"row\">\n <div class=\"col-12\">\n <h3 class=\"my-3\">{{ subscription?.organisation || subscription?.contact_name }}</h3>\n </div>\n</div>\n\n@if (subscription) {\n <form [formGroup]=\"form\"\n (ngSubmit)=\"onSaveDetails()\"\n class=\"row mt-4\"\n >\n <!-- 1. Contact details -->\n <div class=\"col-12\">\n <h3>Contact details</h3>\n </div>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.ContactName' | transloco\"\n class=\"col-md-6\"\n label=\"Contact Name\"\n name=\"contact_name\"\n controlId=\"user-subscription-contact_name\"\n errorMsg=\"Please enter Contact Name\">\n <input type=\"text\"\n id=\"user-subscription-contact_name\"\n class=\"form-control\"\n formControlName=\"contact_name\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.ContactEmail' | transloco\"\n class=\"col-md-6\"\n label=\"Contact Email\"\n name=\"contact_email\"\n controlId=\"user-subscription-contact_email\"\n errorMsg=\"Please enter Contact Email\">\n <input type=\"text\"\n id=\"user-subscription-contact_email\"\n class=\"form-control\"\n formControlName=\"contact_email\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Organization' | transloco\"\n class=\"col-md-6\"\n label=\"Organisation\"\n name=\"organisation\"\n controlId=\"user-subscription-organisation\"\n errorMsg=\"Please enter organisation\">\n <input type=\"text\"\n id=\"user-subscription-organisation\"\n class=\"form-control\"\n formControlName=\"organisation\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Phone' | transloco\"\n class=\"col-md-6\"\n label=\"Contact Tel\"\n name=\"contact_tel\"\n controlId=\"user-subscription-contact_tel\"\n errorMsg=\"Please enter Contact Telephone Number\">\n <input type=\"text\"\n id=\"user-subscription-contact_tel\"\n class=\"form-control\"\n formControlName=\"contact_tel\" />\n </pw-input-container>\n @if (countries$ | async; as countries) {\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Country' | transloco\"\n class=\"col-md-6\"\n label=\"Country\"\n name=\"country_code\"\n controlId=\"user-subscription-country_code\"\n [useAriaLabelledbyOnly]=\"true\"\n [isLeftTooltip]=\"true\"\n errorMsg=\"Please select a country\">\n <p-select\n [attr.aria-labelledby]=\"'user-subscription-country_code-label'\"\n [options]=\"countries\"\n optionLabel=\"name\"\n optionValue=\"code\"\n formControlName=\"country_code\"\n placeholder=\"Select Country\">\n </p-select>\n </pw-input-container>\n }\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Address' | transloco\"\n class=\"col-md-6\"\n label=\"Address\"\n name=\"address\"\n controlId=\"user-subscription-address\"\n [useAriaLabelledbyOnly]=\"true\"\n errorMsg=\"Please enter address\">\n <input ngx-gp-autocomplete\n id=\"user-subscription-address\"\n name=\"address\"\n class=\"form-control\"\n [attr.aria-labelledby]=\"'user-subscription-address-label'\"\n #places=\"ngx-places\"\n formControlName=\"address\"\n (onAddressChange)=\"handleAddressChange($event)\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.VatNumber' | transloco\"\n class=\"col-md-6\"\n label=\"GST/VAT Number\"\n name=\"tax_id\"\n controlId=\"user-subscription-tax_id\"\n errorMsg=\"Please enter GST/VAT Number\">\n <input type=\"text\"\n id=\"user-subscription-tax_id\"\n class=\"form-control\"\n formControlName=\"tax_id\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.CompanyUrl' | transloco\"\n class=\"col-md-6\"\n label=\"Company URL\"\n name=\"company_url\"\n controlId=\"user-subscription-company_url\"\n errorMsg=\"Please enter company url\">\n <input type=\"text\"\n id=\"user-subscription-company_url\"\n class=\"form-control\"\n formControlName=\"company_url\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.InvoiceRecipientEmails' | transloco\"\n class=\"col-md-6\"\n label=\"Invoice Recipient Emails\"\n name=\"invoice_recipient_emails\"\n controlId=\"user-subscription-invoice_recipient_emails\"\n errorMsg=\"Please enter valid email addresses separated by commas\">\n <input type=\"text\"\n id=\"user-subscription-invoice_recipient_emails\"\n class=\"form-control\"\n formControlName=\"invoice_recipient_emails\"\n placeholder=\"email1@example.com,email2@example.com\" />\n </pw-input-container>\n\n <!-- 2. Branding / Logos -->\n <div class=\"col-12\">\n <div class=\"row branding-section\">\n <div class=\"col-12\">\n <h3>Branding</h3>\n </div>\n </div>\n <div class=\"row\">\n <div class=\"col-md-6\">\n <div class=\"text-center mt-5\">\n <div class=\"image-container\">\n <h4 class=\"mb-2\">{{ 'User.Subscriptions.FullLogo' | transloco }}\n <span class=\"tooltip-wrap ms-1\"\n [pTooltip]=\"'User.Subscriptions.Tooltip.FullLogo'|transloco\"\n [appendTo]=\"'body'\"\n [tooltipPosition]=\"'top'\">\n <i class=\"far fa-info-circle text-muted\"></i>\n </span>\n </h4>\n @if (fullLogo && !fullLogo.includes('no_image_uploaded') && !fullLogoBroken) {\n <img [src]=\"fullLogo\"\n alt=\"full logo\"\n class=\"image full-logo\"\n role=\"presentation\"\n (error)=\"fullLogoBroken = true\" />\n <div class=\"overlay mt-2\"\n (keydown.enter)=\"openModal(content)\"\n (click)=\"openModal(content)\">\n <div class=\"overlay-text\">\n <a aria-label=\"Navigate to Target\">{{ 'User.Profile.Change' | transloco }}</a>\n </div>\n </div>\n } @else {\n <div class=\"logo-dropzone full-dropzone\"\n role=\"button\"\n tabindex=\"0\"\n aria-label=\"Upload full logo\"\n (keydown.enter)=\"openModal(content)\"\n (click)=\"openModal(content)\">\n <i class=\"fas fa-upload\"></i>\n <span class=\"dropzone-title\">Upload a logo</span>\n <span class=\"dropzone-hint\">PNG or JPG</span>\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"col-md-6\">\n <div class=\"text-center mt-5\">\n <div class=\"image-container\">\n <h4 class=\"mb-2\">Squared Logo\n <span class=\"tooltip-wrap ms-1\"\n [pTooltip]=\"'User.Subscriptions.Tooltip.SquaredLogo'|transloco\"\n [appendTo]=\"'body'\"\n [tooltipPosition]=\"'top'\">\n <i class=\"far fa-info-circle text-muted\"></i>\n </span>\n </h4>\n @if (squaredLogo && !squaredLogo.includes('no_image_uploaded') && !squaredLogoBroken) {\n <img [src]=\"squaredLogo\"\n alt=\"Squared Presentation\"\n class=\"squared_logo\"\n role=\"presentation\"\n (error)=\"squaredLogoBroken = true\" />\n <div class=\"overlay mt-2\"\n (keydown.enter)=\"openModal(squaredLogoContent)\"\n (click)=\"openModal(squaredLogoContent)\">\n <div class=\"overlay-text\">\n <a aria-label=\"Navigate to Target\">{{ 'User.Profile.Change' | transloco }}</a>\n </div>\n </div>\n } @else {\n <div class=\"logo-dropzone squared-dropzone\"\n role=\"button\"\n tabindex=\"0\"\n aria-label=\"Upload squared logo\"\n (keydown.enter)=\"openModal(squaredLogoContent)\"\n (click)=\"openModal(squaredLogoContent)\">\n <i class=\"fas fa-upload\"></i>\n <span class=\"dropzone-title\">Upload a logo</span>\n <span class=\"dropzone-hint\">PNG or JPG</span>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- 3. Social Media -->\n <ng-container *rbacAllow=\"'SubscriptionSuperAdmin'\">\n <div class=\"col-12\">\n <h3>Social Media</h3>\n <p>\n Any of the social media handles that you set here will appear in the footer of emails going out to your child subscriptions.\n </p>\n </div>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.FacebookHandle' | transloco\"\n class=\"col-md-6\"\n label=\"Facebook handle\"\n name=\"facebook_handle\"\n controlId=\"user-subscription-facebook_handle\"\n errorMsg=\"Please enter facebook id\">\n <input type=\"text\"\n id=\"user-subscription-facebook_handle\"\n class=\"form-control\"\n formControlName=\"facebook_handle\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.TwitterHandle' | transloco\"\n class=\"col-md-6\"\n label=\"Twitter handle\"\n name=\"twitter_handle\"\n controlId=\"user-subscription-twitter_handle\"\n errorMsg=\"Please enter twitter id\">\n <input type=\"text\"\n id=\"user-subscription-twitter_handle\"\n class=\"form-control\"\n formControlName=\"twitter_handle\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.LinkedinHandle' | transloco\"\n class=\"col-md-6\"\n label=\"Linkedin handle\"\n name=\"linkedin_handle\"\n controlId=\"user-subscription-linkedin_handle\"\n errorMsg=\"Please enter linkedin id\">\n <input type=\"text\"\n id=\"user-subscription-linkedin_handle\"\n class=\"form-control\"\n formControlName=\"linkedin_handle\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.RedditHandle' | transloco\"\n class=\"col-md-6\"\n label=\"Reddit handle\"\n name=\"reddit_handle\"\n controlId=\"user-subscription-reddit_handle\"\n errorMsg=\"Please enter reddit id\">\n <input type=\"text\"\n id=\"user-subscription-reddit_handle\"\n class=\"form-control\"\n formControlName=\"reddit_handle\" />\n </pw-input-container>\n </ng-container>\n\n <!-- 4. Seats -->\n <div class=\"col-12\">\n <div class=\"row seats-section\">\n <div class=\"col-12\">\n <h3>Seats</h3>\n <p>Changing the number of seats updates your subscription cost.</p>\n </div>\n </div>\n <div class=\"row\">\n <div class=\"col-12\">\n @if (subscription?.trial_subscription && subscription?.calculated_price) {\n <small\n class=\"text-danger\">Upgrade to be able to update your purchased seats</small>\n }\n </div>\n </div>\n <div class=\"row btns-row align-items-center\">\n @if (subscription) {\n <div class=\"col-md-3 col-8\"\n >\n <label for=\"user-subscription-seats\" class=\"visually-hidden\">{{ 'User.Subscriptions.Tooltip.Seats' | transloco }}</label>\n <pw-number-picker [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Seats'|transloco\"\n inputId=\"user-subscription-seats\"\n name=\"number-picker\"\n [(value)]=\"units\"\n [min]=\"subscription?.min_units||subscription?.products[0].min_units\"\n [max]=\"subscription?.products[0].max_units\"\n step=\"1\"\n postfix=\"seats\"\n placeholder=\"Total Licences\"\n [inputReadOnly]=\"subscription?.products[0].trial_subscription\"\n [showUpButton]=\"!subscription?.products[0].trial_subscription\"\n [showDownButton]=\"!subscription?.products[0].trial_subscription\"\n size=\"small\"\n pickStartAfter=\"500\"\n pickTimer=\"100\"\n [arrowKeys]=\"true\"\n (minReached)=\"onMinReached($event)\"\n (maxReached)=\"onMaxReached($event)\"\n (valueChange)=\"onUnitChange($event)\">\n </pw-number-picker>\n </div>\n }\n\n @if (subscription) {\n <div class=\"col-md-3 col-4 p-1\"\n >\n @if (!subscription?.products[0].trial_subscription && allowUpdate) {\n <button type=\"button\"\n class=\"btn btn-primary\"\n (click)=\"updateUnits()\">\n {{ 'User.Subscriptions.UpdateUnits' | transloco }}\n </button>\n } @else {\n <div>\n @if (subscription?.products[0].trial_subscription) {\n <small class=\"text-muted\"\n >Update seats is available only to paid subscriptions</small>\n }\n </div>\n }\n </div>\n }\n\n @if (hasUnitChanged) {\n <div class=\"col-12 col-md-6\"\n >\n <table class=\"table table-borderless table-sm\"\n aria-describedby=\"Product details\">\n <thead>\n <tr>\n <th scope=\"true\">Product</th>\n <th scope=\"true\">Price per seat <span>({{subscription?.products[0]?.currency|currencySymbol}})</span></th>\n <th scope=\"true\">Seats</th>\n </tr>\n </thead>\n <tbody>\n @for (product of subscription.products; track trackByProduct($index, product)) {\n <tr>\n <td>{{ product.name }}</td>\n <td>{{ product.price_per_unit / 100 }}</td>\n <td>{{ units }}</td>\n </tr>\n }\n </tbody>\n </table>\n <p>\n If you proceed, the new cost for your subscription will be\n <strong>{{ totalAmount()| currency: subscription?.products[0]?.currency:'symbol-narrow'}}</strong>\n </p>\n </div>\n }\n </div>\n </div>\n\n <!-- 5. API & MCP Credentials -->\n @if (subscription?.api_hits_max > 0) {\n <div class=\"col-12\">\n <h3>{{ 'User.Subscriptions.APICredentials.Title' | transloco }}</h3>\n <p>\n These credentials authenticate both REST API and MCP (Model Context Protocol) requests, and must be used together with the user tokens defined on your Account page.\n </p>\n </div>\n <div class=\"col-md-6\">\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"user-subscription-api-token\">\n {{ 'User.Subscriptions.APICredentials.AccessToken' | transloco }}\n <span class=\"tooltip-wrap ms-1\"\n pTooltip=\"The subscription token has been discontinued in favour of the user token defined on your Account page.\"\n [appendTo]=\"'body'\"\n [tooltipPosition]=\"'top'\">\n <i class=\"far fa-info-circle text-muted\"></i>\n </span>\n </label>\n <div class=\"input-group\">\n <input type=\"text\"\n id=\"user-subscription-api-token\"\n name=\"api_token\"\n class=\"form-control\"\n [value]=\"showApiToken ? subscription?.api_access_token || ('User.Subscriptions.APICredentials.NoTokenAvailable' | transloco) : '*************************'\"\n readonly />\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"toggleApiTokenVisibility()\">\n {{ showApiToken ? ('User.Subscriptions.APICredentials.Hide' | transloco) : ('User.Subscriptions.APICredentials.View' | transloco) }}\n </button>\n </div>\n </div>\n </div>\n <div class=\"col-md-6\">\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"user-subscription-api-client-id\">{{ 'User.Subscriptions.APICredentials.ClientId' | transloco }}</label>\n <div class=\"input-group\">\n <input type=\"text\"\n id=\"user-subscription-api-client-id\"\n name=\"api_client_id\"\n class=\"form-control\"\n [value]=\"showApiClientId ? subscription?.api_client_id || ('User.Subscriptions.APICredentials.NoClientIdAvailable' | transloco) : '*************************'\"\n readonly />\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"toggleApiClientIdVisibility()\">\n {{ showApiClientId ? ('User.Subscriptions.APICredentials.Hide' | transloco) : ('User.Subscriptions.APICredentials.View' | transloco) }}\n </button>\n </div>\n </div>\n </div>\n <div class=\"col-12 mt-3\">\n <div class=\"d-flex align-items-center gap-3\">\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"refreshApiTokens()\"\n [disabled]=\"refreshingTokens\">\n <i class=\"fas fa-sync-alt me-2\" [class.fa-spin]=\"refreshingTokens\"></i>\n {{ refreshingTokens ? ('User.Subscriptions.APICredentials.Refreshing' | transloco) : ('User.Subscriptions.APICredentials.RefreshTokens' | transloco) }}\n </button>\n <div class=\"d-flex align-items-center gap-2\">\n @if (subscription?.api_hits !== null) {\n <span class=\"text-muted\">{{ 'User.Subscriptions.APICredentials.ApiHits' | transloco }}:</span>\n <span class=\"fw-bold\">{{ subscription.api_hits | number }}</span>\n }\n @if (subscription?.api_hits_max !== null) {\n <span class=\"text-muted\">{{ 'User.Subscriptions.APICredentials.ApiHitsMax' | transloco }}:</span>\n <span class=\"fw-bold\">{{ subscription.api_hits_max | number }}</span>\n }\n <!-- Show utilization percentage when both values exist -->\n @if (subscription?.api_hits !== null || subscription?.api_hits_max !== null) {\n <span class=\"text-muted ms-2\">(</span>\n <span class=\"fw-bold\" [ngClass]=\"{\n 'text-success': (subscription.api_hits / subscription.api_hits_max) <= 0.8,\n 'text-warning': (subscription.api_hits / subscription.api_hits_max) > 0.8 && (subscription.api_hits / subscription.api_hits_max) <= 0.9,\n 'text-danger': (subscription.api_hits / subscription.api_hits_max) > 0.9\n }\">\n {{ (subscription.api_hits / subscription.api_hits_max * 100) | number:'1.0-0' }}% consumed\n </span>\n <span class=\"text-muted\">)</span>\n }\n </div>\n </div>\n </div>\n }\n\n <!-- 6. Security -->\n <div class=\"col-12 mt-5\">\n <h3>Security</h3>\n <p>\n While we'll add more security options in the future, please start by enforcing 2FA for all your subscription members.\n </p>\n </div>\n <div class=\"col-12 col-sm-3\">\n <pw-input-container label=\"Enforce 2FA\"\n [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Enforce2fa' | transloco\"\n name=\"enforce_2fa\"\n controlId=\"user-subscription-enforce_2fa\"\n [useAriaLabelledbyOnly]=\"true\">\n <ui-switch formControlName=\"enforce_2fa\"\n name=\"enforce_2fa\"\n [attr.aria-labelledby]=\"'user-subscription-enforce_2fa-label'\"> </ui-switch>\n </pw-input-container>\n </div>\n <div class=\"mb-3 col-12 text-end mt-3\">\n <button type=\"button\"\n class=\"btn btn-outline-default me-2\"\n routerLink=\"/account/subscriptions\">\n {{ 'Button.Cancel' | transloco }}\n </button>\n <button name=\"submit\"\n type=\"submit\"\n [buttonBusy]=\"busyButton\"\n class=\"btn btn-primary\">\n {{ 'Button.Submit' | transloco }}\n </button>\n </div>\n </form>\n}\n\n<ng-template #content\n let-modal>\n <div class=\"modal-header\">\n <h3 class=\"modal-title mb-0 p-0\">{{ 'User.Subscriptions.FullLogo' | transloco }}</h3>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n <small> {{ 'User.Profile.PictureMessage' | transloco }}</small>\n <pw-image-cropper #profile\n (imageSelectionEvent)=\"onImageSelection($event)\"\n aspectRatio=\"fullLogo\"\n (closeEvent)=\"onClose()\">\n </pw-image-cropper>\n </div>\n</ng-template>\n<ng-template #squaredLogoContent\n let-modal>\n <div class=\"modal-header\">\n <h3 class=\"modal-title mb-0 p-0\">{{ 'User.Subscriptions.SquaredLogo' | transloco }}</h3>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n <small> {{ 'User.Profile.PictureMessage' | transloco }}</small>\n <pw-image-cropper #profile\n (imageSelectionEvent)=\"uploadSquaredLogo($event)\"\n aspectRatio=\"auto\"\n (closeEvent)=\"onClose()\">\n </pw-image-cropper>\n </div>\n</ng-template>\n<pw-password-validation #modal\n(successEvent)=\"onPasswordValidation($event)\"> </pw-password-validation>\n", styles: [":host{display:block}:host>.row:first-of-type h3{color:var(--titles, #222);font-size:24px;font-weight:700;letter-spacing:-.01em;line-height:1.18}:host form .col-12>h3,:host .seats-section>.col-12>h3,:host .branding-section>.col-12>h3{border-top:1px solid #e2e5ea;color:var(--titles, #222);display:block;font-size:18px;font-weight:600;margin-top:32px;padding-top:24px}:host form>.col-12:first-child>h3{border-top:0;margin-top:0;padding-top:0}:host form .col-12>p,:host .seats-section>.col-12>p{color:#5a6473;font-size:15px;margin-bottom:16px}:host .row .text-center.mt-5{margin-top:16px!important;text-align:left!important}:host .image-container>h4{color:var(--titles, #222);font-size:14px;font-weight:600}:host .full-logo,:host .squared_logo{background:#f7f8fa;border:1px solid #e2e5ea;border-radius:8px;object-fit:contain;padding:12px}:host .full-logo{height:120px;width:280px}:host .squared_logo{height:150px;width:150px}:host .overlay{cursor:pointer;margin-top:8px}:host .overlay-text a{color:var(--first, #1769e1);cursor:pointer;font-weight:600}:host .overlay-text a:hover{text-decoration:underline}.sub-header{color:gray;font-size:20px;font-weight:600}@media only screen and (max-width:767px){.btns-row>[class*=col-]{flex:0 0 100%;max-width:100%}.btns-row .btn-primary{font-size:.8rem;margin-top:5px;padding:.375rem .5rem}}\n"], dependencies: [{ kind: "directive", type: i4.ButtonBusyDirective, selector: "[buttonBusy]", inputs: ["buttonBusy", "busyText"] }, { kind: "directive", type: i4.LazyImgDirective, selector: "img" }, { kind: "directive", type: i4.RbacAllowDirective, selector: "[rbacAllow]", inputs: ["rbacAllow"] }, { kind: "directive", type: i6.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i6$1.NgxGpAutocompleteDirective, selector: "[ngx-gp-autocomplete]", inputs: ["options"], outputs: ["onAddressChange"], exportAs: ["ngx-places"] }, { kind: "component", type: i5.PasswordValidationComponent, selector: "pw-password-validation", inputs: ["confirmMessage"], outputs: ["successEvent"] }, { kind: "component", type: i6$2.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i11$1.UiSwitchComponent, selector: "ui-switch", inputs: ["size", "color", "switchOffColor", "switchColor", "defaultBgColor", "defaultBoColor", "checkedLabel", "uncheckedLabel", "checkedTextColor", "uncheckedTextColor", "beforeChange", "ariaLabel", "checked", "disabled", "reverse", "loading"], outputs: ["change", "changeEvent", "valueChange"] }, { kind: "component", type: i5.NumberPickerComponent, selector: "pw-number-picker", inputs: ["min", "showTooltip", "tooltipText", "max", "step", "value", "pickStartAfter", "pickTimer", "prefix", "postfix", "placeholder", "buttonsOrientation", "size", "customClass", "mouseWheel", "arrowKeys", "inputReadOnly", "showUpButton", "showDownButton", "inputId"], outputs: ["valueChange", "minReached", "maxReached", "pickStarted", "pickStopped", "pickUpStarted", "pickUpStopped", "pickDownStarted", "pickDownStopped"] }, { kind: "component", type: i9.ProfileImageCropperComponent, selector: "pw-image-cropper", inputs: ["aspectRatio", "dynamicData"], outputs: ["imageSelectionEvent", "closeEvent", "fileChangeEvent"] }, { kind: "component", type: i5.InputContainerComponent, selector: "pw-input-container", inputs: ["name", "controlId", "useAriaLabelledbyOnly", "label", "labelClass", "tooltipPosition", "required", "errorMsg", "isReadOnly", "showTooltip", "tooltipText", "showTriangle", "afterLabel", "showAfterLabel", "showTriangleText", "isLeftTooltip"] }, { kind: "directive", type: i11.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "pipe", type: i6.AsyncPipe, name: "async" }, { kind: "pipe", type: i6.DecimalPipe, name: "number" }, { kind: "pipe", type: i6.CurrencyPipe, name: "currency" }, { kind: "pipe", type: i8.TranslocoPipe, name: "transloco" }, { kind: "pipe", type: i6$3.CurrencySymbolPipe, name: "currencySymbol" }] }); }
|
|
1685
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: UserSubscriptionDetailsComponent, deps: [{ token: i2.UntypedFormBuilder }, { token: i1$2.GeoService }, { token: i1$1.NgbModal }, { token: i1$2.SubscriptionService }, { token: i4$1.Store }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }, { token: i5.ConfirmDialogService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1686
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: UserSubscriptionDetailsComponent, isStandalone: false, selector: "ng-component", viewQueries: [{ propertyName: "modal", first: true, predicate: ["modal"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<!-- edit Subscription details page -->\n<div class=\"row\">\n <div class=\"col-12\">\n <h3 class=\"my-3\">{{ subscription?.organisation || subscription?.contact_name }}</h3>\n </div>\n</div>\n\n@if (subscription) {\n <form [formGroup]=\"form\"\n (ngSubmit)=\"onSaveDetails()\"\n class=\"row mt-4\"\n >\n <!-- 1. Contact details -->\n <div class=\"col-12\">\n <h3>Contact details</h3>\n </div>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.ContactName' | transloco\"\n class=\"col-md-6\"\n label=\"Contact Name\"\n name=\"contact_name\"\n controlId=\"user-subscription-contact_name\"\n errorMsg=\"Please enter Contact Name\">\n <input type=\"text\"\n id=\"user-subscription-contact_name\"\n class=\"form-control\"\n formControlName=\"contact_name\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.ContactEmail' | transloco\"\n class=\"col-md-6\"\n label=\"Contact Email\"\n name=\"contact_email\"\n controlId=\"user-subscription-contact_email\"\n errorMsg=\"Please enter Contact Email\">\n <input type=\"text\"\n id=\"user-subscription-contact_email\"\n class=\"form-control\"\n formControlName=\"contact_email\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Organization' | transloco\"\n class=\"col-md-6\"\n label=\"Organisation\"\n name=\"organisation\"\n controlId=\"user-subscription-organisation\"\n errorMsg=\"Please enter organisation\">\n <input type=\"text\"\n id=\"user-subscription-organisation\"\n class=\"form-control\"\n formControlName=\"organisation\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Phone' | transloco\"\n class=\"col-md-6\"\n label=\"Contact Tel\"\n name=\"contact_tel\"\n controlId=\"user-subscription-contact_tel\"\n errorMsg=\"Please enter Contact Telephone Number\">\n <input type=\"text\"\n id=\"user-subscription-contact_tel\"\n class=\"form-control\"\n formControlName=\"contact_tel\" />\n </pw-input-container>\n @if (countries$ | async; as countries) {\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Country' | transloco\"\n class=\"col-md-6\"\n label=\"Country\"\n name=\"country_code\"\n controlId=\"user-subscription-country_code\"\n [useAriaLabelledbyOnly]=\"true\"\n [isLeftTooltip]=\"true\"\n errorMsg=\"Please select a country\">\n <p-select\n [attr.aria-labelledby]=\"'user-subscription-country_code-label'\"\n [options]=\"countries\"\n optionLabel=\"name\"\n optionValue=\"code\"\n formControlName=\"country_code\"\n placeholder=\"Select Country\">\n </p-select>\n </pw-input-container>\n }\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Address' | transloco\"\n class=\"col-md-6\"\n label=\"Address\"\n name=\"address\"\n controlId=\"user-subscription-address\"\n [useAriaLabelledbyOnly]=\"true\"\n errorMsg=\"Please enter address\">\n <input ngx-gp-autocomplete\n id=\"user-subscription-address\"\n name=\"address\"\n class=\"form-control\"\n [attr.aria-labelledby]=\"'user-subscription-address-label'\"\n #places=\"ngx-places\"\n formControlName=\"address\"\n (onAddressChange)=\"handleAddressChange($event)\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.VatNumber' | transloco\"\n class=\"col-md-6\"\n label=\"GST/VAT Number\"\n name=\"tax_id\"\n controlId=\"user-subscription-tax_id\"\n errorMsg=\"Please enter GST/VAT Number\">\n <input type=\"text\"\n id=\"user-subscription-tax_id\"\n class=\"form-control\"\n formControlName=\"tax_id\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.CompanyUrl' | transloco\"\n class=\"col-md-6\"\n label=\"Company URL\"\n name=\"company_url\"\n controlId=\"user-subscription-company_url\"\n errorMsg=\"Please enter company url\">\n <input type=\"text\"\n id=\"user-subscription-company_url\"\n class=\"form-control\"\n formControlName=\"company_url\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.InvoiceRecipientEmails' | transloco\"\n class=\"col-md-6\"\n label=\"Invoice Recipient Emails\"\n name=\"invoice_recipient_emails\"\n controlId=\"user-subscription-invoice_recipient_emails\"\n errorMsg=\"Please enter valid email addresses separated by commas\">\n <input type=\"text\"\n id=\"user-subscription-invoice_recipient_emails\"\n class=\"form-control\"\n formControlName=\"invoice_recipient_emails\"\n placeholder=\"email1@example.com,email2@example.com\" />\n </pw-input-container>\n\n <!-- 2. Branding / Logos -->\n <div class=\"col-12\">\n <div class=\"row branding-section\">\n <div class=\"col-12\">\n <h3>Branding</h3>\n </div>\n </div>\n <div class=\"row\">\n <div class=\"col-md-6\">\n <div class=\"text-center mt-5\">\n <div class=\"image-container\">\n <h4 class=\"mb-2\">{{ 'User.Subscriptions.FullLogo' | transloco }}\n <span class=\"tooltip-wrap ms-1\"\n [pTooltip]=\"'User.Subscriptions.Tooltip.FullLogo'|transloco\"\n [appendTo]=\"'body'\"\n [tooltipPosition]=\"'top'\">\n <i class=\"far fa-info-circle text-muted\"></i>\n </span>\n </h4>\n @if (fullLogo && !fullLogo.includes('no_image_uploaded') && !fullLogoBroken) {\n <img [src]=\"fullLogo\"\n alt=\"full logo\"\n class=\"image full-logo\"\n role=\"presentation\"\n (error)=\"fullLogoBroken = true\" />\n <div class=\"overlay mt-2\"\n (keydown.enter)=\"openModal(content)\"\n (click)=\"openModal(content)\">\n <div class=\"overlay-text\">\n <a aria-label=\"Navigate to Target\">{{ 'User.Profile.Change' | transloco }}</a>\n </div>\n </div>\n } @else {\n <div class=\"logo-dropzone full-dropzone\"\n role=\"button\"\n tabindex=\"0\"\n aria-label=\"Upload full logo\"\n (keydown.enter)=\"openModal(content)\"\n (click)=\"openModal(content)\">\n <i class=\"fas fa-upload\"></i>\n <span class=\"dropzone-title\">Upload a logo</span>\n <span class=\"dropzone-hint\">PNG or JPG</span>\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"col-md-6\">\n <div class=\"text-center mt-5\">\n <div class=\"image-container\">\n <h4 class=\"mb-2\">Squared Logo\n <span class=\"tooltip-wrap ms-1\"\n [pTooltip]=\"'User.Subscriptions.Tooltip.SquaredLogo'|transloco\"\n [appendTo]=\"'body'\"\n [tooltipPosition]=\"'top'\">\n <i class=\"far fa-info-circle text-muted\"></i>\n </span>\n </h4>\n @if (squaredLogo && !squaredLogo.includes('no_image_uploaded') && !squaredLogoBroken) {\n <img [src]=\"squaredLogo\"\n alt=\"Squared Presentation\"\n class=\"squared_logo\"\n role=\"presentation\"\n (error)=\"squaredLogoBroken = true\" />\n <div class=\"overlay mt-2\"\n (keydown.enter)=\"openModal(squaredLogoContent)\"\n (click)=\"openModal(squaredLogoContent)\">\n <div class=\"overlay-text\">\n <a aria-label=\"Navigate to Target\">{{ 'User.Profile.Change' | transloco }}</a>\n </div>\n </div>\n } @else {\n <div class=\"logo-dropzone squared-dropzone\"\n role=\"button\"\n tabindex=\"0\"\n aria-label=\"Upload squared logo\"\n (keydown.enter)=\"openModal(squaredLogoContent)\"\n (click)=\"openModal(squaredLogoContent)\">\n <i class=\"fas fa-upload\"></i>\n <span class=\"dropzone-title\">Upload a logo</span>\n <span class=\"dropzone-hint\">PNG or JPG</span>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- 3. Social Media -->\n <ng-container *rbacAllow=\"'SubscriptionSuperAdmin'\">\n <div class=\"col-12\">\n <h3>Social Media</h3>\n <p>\n Any of the social media handles that you set here will appear in the footer of emails going out to your child subscriptions.\n </p>\n </div>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.FacebookHandle' | transloco\"\n class=\"col-md-6\"\n label=\"Facebook handle\"\n name=\"facebook_handle\"\n controlId=\"user-subscription-facebook_handle\"\n errorMsg=\"Please enter facebook id\">\n <input type=\"text\"\n id=\"user-subscription-facebook_handle\"\n class=\"form-control\"\n formControlName=\"facebook_handle\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.TwitterHandle' | transloco\"\n class=\"col-md-6\"\n label=\"Twitter handle\"\n name=\"twitter_handle\"\n controlId=\"user-subscription-twitter_handle\"\n errorMsg=\"Please enter twitter id\">\n <input type=\"text\"\n id=\"user-subscription-twitter_handle\"\n class=\"form-control\"\n formControlName=\"twitter_handle\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.LinkedinHandle' | transloco\"\n class=\"col-md-6\"\n label=\"Linkedin handle\"\n name=\"linkedin_handle\"\n controlId=\"user-subscription-linkedin_handle\"\n errorMsg=\"Please enter linkedin id\">\n <input type=\"text\"\n id=\"user-subscription-linkedin_handle\"\n class=\"form-control\"\n formControlName=\"linkedin_handle\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.RedditHandle' | transloco\"\n class=\"col-md-6\"\n label=\"Reddit handle\"\n name=\"reddit_handle\"\n controlId=\"user-subscription-reddit_handle\"\n errorMsg=\"Please enter reddit id\">\n <input type=\"text\"\n id=\"user-subscription-reddit_handle\"\n class=\"form-control\"\n formControlName=\"reddit_handle\" />\n </pw-input-container>\n </ng-container>\n\n <!-- 4. Seats -->\n <div class=\"col-12\">\n <div class=\"row seats-section\">\n <div class=\"col-12\">\n <h3>Seats</h3>\n <p>Changing the number of seats updates your subscription cost.</p>\n </div>\n </div>\n <div class=\"row\">\n <div class=\"col-12\">\n @if (subscription?.trial_subscription && subscription?.calculated_price) {\n <small\n class=\"text-danger\">Upgrade to be able to update your purchased seats</small>\n }\n </div>\n </div>\n <div class=\"row btns-row align-items-center\">\n @if (subscription) {\n <div class=\"col-md-3 col-8\"\n >\n <label for=\"user-subscription-seats\" class=\"visually-hidden\">{{ 'User.Subscriptions.Tooltip.Seats' | transloco }}</label>\n <pw-number-picker [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Seats'|transloco\"\n inputId=\"user-subscription-seats\"\n name=\"number-picker\"\n [(value)]=\"units\"\n [min]=\"subscription?.min_units||subscription?.products[0].min_units\"\n [max]=\"subscription?.products[0].max_units\"\n step=\"1\"\n postfix=\"seats\"\n placeholder=\"Total Licences\"\n [inputReadOnly]=\"subscription?.products[0].trial_subscription\"\n [showUpButton]=\"!subscription?.products[0].trial_subscription\"\n [showDownButton]=\"!subscription?.products[0].trial_subscription\"\n size=\"small\"\n pickStartAfter=\"500\"\n pickTimer=\"100\"\n [arrowKeys]=\"true\"\n (minReached)=\"onMinReached($event)\"\n (maxReached)=\"onMaxReached($event)\"\n (valueChange)=\"onUnitChange($event)\">\n </pw-number-picker>\n </div>\n }\n\n @if (subscription) {\n <div class=\"col-md-3 col-4 p-1\"\n >\n @if (!subscription?.products[0].trial_subscription && allowUpdate) {\n <button type=\"button\"\n class=\"btn btn-primary\"\n (click)=\"updateUnits()\">\n {{ 'User.Subscriptions.UpdateUnits' | transloco }}\n </button>\n } @else {\n <div>\n @if (subscription?.products[0].trial_subscription) {\n <small class=\"text-muted\"\n >Update seats is available only to paid subscriptions</small>\n }\n </div>\n }\n </div>\n }\n\n @if (hasUnitChanged) {\n <div class=\"col-12 col-md-6\"\n >\n <table class=\"table table-borderless table-sm\"\n aria-describedby=\"Product details\">\n <thead>\n <tr>\n <th scope=\"true\">Product</th>\n <th scope=\"true\">Price per seat <span>({{subscription?.products[0]?.currency|currencySymbol}})</span></th>\n <th scope=\"true\">Seats</th>\n </tr>\n </thead>\n <tbody>\n @for (product of subscription.products; track trackByProduct($index, product)) {\n <tr>\n <td>{{ product.name }}</td>\n <td>{{ product.price_per_unit / 100 }}</td>\n <td>{{ units }}</td>\n </tr>\n }\n </tbody>\n </table>\n <p>\n If you proceed, the new cost for your subscription will be\n <strong>{{ totalAmount()| currency: subscription?.products[0]?.currency:'symbol-narrow'}}</strong>\n </p>\n </div>\n }\n </div>\n </div>\n\n <!-- 5. API & MCP Credentials -->\n @if (subscription?.api_hits_max > 0) {\n <div class=\"col-12\">\n <h3>{{ 'User.Subscriptions.APICredentials.Title' | transloco }}</h3>\n <p>\n These credentials authenticate both REST API and MCP (Model Context Protocol) requests, and must be used together with the user tokens defined on your Account page.\n </p>\n </div>\n <div class=\"col-md-6\">\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"user-subscription-api-token\">\n {{ 'User.Subscriptions.APICredentials.AccessToken' | transloco }}\n <span class=\"tooltip-wrap ms-1\"\n pTooltip=\"The subscription token has been discontinued in favour of the user token defined on your Account page.\"\n [appendTo]=\"'body'\"\n [tooltipPosition]=\"'top'\">\n <i class=\"far fa-info-circle text-muted\"></i>\n </span>\n </label>\n <div class=\"input-group\">\n <input type=\"text\"\n id=\"user-subscription-api-token\"\n name=\"api_token\"\n class=\"form-control\"\n [value]=\"showApiToken ? subscription?.api_access_token || ('User.Subscriptions.APICredentials.NoTokenAvailable' | transloco) : '*************************'\"\n readonly />\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"toggleApiTokenVisibility()\">\n {{ showApiToken ? ('User.Subscriptions.APICredentials.Hide' | transloco) : ('User.Subscriptions.APICredentials.View' | transloco) }}\n </button>\n </div>\n </div>\n </div>\n <div class=\"col-md-6\">\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"user-subscription-api-client-id\">{{ 'User.Subscriptions.APICredentials.ClientId' | transloco }}</label>\n <div class=\"input-group\">\n <input type=\"text\"\n id=\"user-subscription-api-client-id\"\n name=\"api_client_id\"\n class=\"form-control\"\n [value]=\"showApiClientId ? subscription?.api_client_id || ('User.Subscriptions.APICredentials.NoClientIdAvailable' | transloco) : '*************************'\"\n readonly />\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"toggleApiClientIdVisibility()\">\n {{ showApiClientId ? ('User.Subscriptions.APICredentials.Hide' | transloco) : ('User.Subscriptions.APICredentials.View' | transloco) }}\n </button>\n </div>\n </div>\n </div>\n <div class=\"col-12 mt-3\">\n <div class=\"d-flex align-items-center gap-3\">\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"refreshApiTokens()\"\n [disabled]=\"refreshingTokens\">\n <i class=\"fas fa-sync-alt me-2\" [class.fa-spin]=\"refreshingTokens\"></i>\n {{ refreshingTokens ? ('User.Subscriptions.APICredentials.Refreshing' | transloco) : ('User.Subscriptions.APICredentials.RefreshTokens' | transloco) }}\n </button>\n <div class=\"d-flex align-items-center gap-2\">\n @if (subscription?.api_hits !== null) {\n <span class=\"text-muted\">{{ 'User.Subscriptions.APICredentials.ApiHits' | transloco }}:</span>\n <span class=\"fw-bold\">{{ subscription.api_hits | number }}</span>\n }\n @if (subscription?.api_hits_max !== null) {\n <span class=\"text-muted\">{{ 'User.Subscriptions.APICredentials.ApiHitsMax' | transloco }}:</span>\n <span class=\"fw-bold\">{{ subscription.api_hits_max | number }}</span>\n }\n <!-- Show utilization percentage when both values exist -->\n @if (subscription?.api_hits !== null || subscription?.api_hits_max !== null) {\n <span class=\"text-muted ms-2\">(</span>\n <span class=\"fw-bold\" [ngClass]=\"{\n 'text-success-muted': (subscription.api_hits / subscription.api_hits_max) <= 0.8,\n 'text-warning': (subscription.api_hits / subscription.api_hits_max) > 0.8 && (subscription.api_hits / subscription.api_hits_max) <= 0.9,\n 'text-danger': (subscription.api_hits / subscription.api_hits_max) > 0.9\n }\">\n {{ (subscription.api_hits / subscription.api_hits_max * 100) | number:'1.0-0' }}% consumed\n </span>\n <span class=\"text-muted\">)</span>\n }\n </div>\n </div>\n </div>\n }\n\n <!-- 6. Security -->\n <div class=\"col-12 mt-5\">\n <h3>Security</h3>\n <p>\n While we'll add more security options in the future, please start by enforcing 2FA for all your subscription members.\n </p>\n </div>\n <div class=\"col-12 col-sm-3\">\n <pw-input-container label=\"Enforce 2FA\"\n [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Enforce2fa' | transloco\"\n name=\"enforce_2fa\"\n controlId=\"user-subscription-enforce_2fa\"\n [useAriaLabelledbyOnly]=\"true\">\n <ui-switch formControlName=\"enforce_2fa\"\n name=\"enforce_2fa\"\n [attr.aria-labelledby]=\"'user-subscription-enforce_2fa-label'\"> </ui-switch>\n </pw-input-container>\n </div>\n <div class=\"mb-3 col-12 text-end mt-3\">\n <button type=\"button\"\n class=\"btn btn-outline-default me-2\"\n routerLink=\"/account/subscriptions\">\n {{ 'Button.Cancel' | transloco }}\n </button>\n <button name=\"submit\"\n type=\"submit\"\n [buttonBusy]=\"busyButton\"\n class=\"btn btn-primary\">\n {{ 'Button.Submit' | transloco }}\n </button>\n </div>\n </form>\n}\n\n<ng-template #content\n let-modal>\n <div class=\"modal-header\">\n <h3 class=\"modal-title mb-0 p-0\">{{ 'User.Subscriptions.FullLogo' | transloco }}</h3>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n <small> {{ 'User.Profile.PictureMessage' | transloco }}</small>\n <pw-image-cropper #profile\n (imageSelectionEvent)=\"onImageSelection($event)\"\n aspectRatio=\"fullLogo\"\n (closeEvent)=\"onClose()\">\n </pw-image-cropper>\n </div>\n</ng-template>\n<ng-template #squaredLogoContent\n let-modal>\n <div class=\"modal-header\">\n <h3 class=\"modal-title mb-0 p-0\">{{ 'User.Subscriptions.SquaredLogo' | transloco }}</h3>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n <small> {{ 'User.Profile.PictureMessage' | transloco }}</small>\n <pw-image-cropper #profile\n (imageSelectionEvent)=\"uploadSquaredLogo($event)\"\n aspectRatio=\"auto\"\n (closeEvent)=\"onClose()\">\n </pw-image-cropper>\n </div>\n</ng-template>\n<pw-password-validation #modal\n(successEvent)=\"onPasswordValidation($event)\"> </pw-password-validation>\n", styles: [":host{display:block}:host>.row:first-of-type h3{color:var(--titles, #222);font-size:24px;font-weight:700;letter-spacing:-.01em;line-height:1.18}:host form .col-12>h3,:host .seats-section>.col-12>h3,:host .branding-section>.col-12>h3{border-top:1px solid #e2e5ea;color:var(--titles, #222);display:block;font-size:18px;font-weight:600;margin-top:32px;padding-top:24px}:host form>.col-12:first-child>h3{border-top:0;margin-top:0;padding-top:0}:host form .col-12>p,:host .seats-section>.col-12>p{color:#5a6473;font-size:15px;margin-bottom:16px}:host .row .text-center.mt-5{margin-top:16px!important;text-align:left!important}:host .image-container>h4{color:var(--titles, #222);font-size:14px;font-weight:600}:host .full-logo,:host .squared_logo{background:#f7f8fa;border:1px solid #e2e5ea;border-radius:8px;object-fit:contain;padding:12px}:host .full-logo{height:120px;width:280px}:host .squared_logo{height:150px;width:150px}:host .overlay{cursor:pointer;margin-top:8px}:host .overlay-text a{color:var(--first, #1769e1);cursor:pointer;font-weight:600}:host .overlay-text a:hover{text-decoration:underline}.sub-header{color:gray;font-size:20px;font-weight:600}@media only screen and (max-width:767px){.btns-row>[class*=col-]{flex:0 0 100%;max-width:100%}.btns-row .btn-primary{font-size:.8rem;margin-top:5px;padding:.375rem .5rem}}\n"], dependencies: [{ kind: "directive", type: i3.ButtonBusyDirective, selector: "[buttonBusy]", inputs: ["buttonBusy", "busyText"] }, { kind: "directive", type: i3.LazyImgDirective, selector: "img" }, { kind: "directive", type: i3.RbacAllowDirective, selector: "[rbacAllow]", inputs: ["rbacAllow"] }, { kind: "directive", type: i8.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i7.NgxGpAutocompleteDirective, selector: "[ngx-gp-autocomplete]", inputs: ["options"], outputs: ["onAddressChange"], exportAs: ["ngx-places"] }, { kind: "component", type: i5.PasswordValidationComponent, selector: "pw-password-validation", inputs: ["confirmMessage", "destructive"], outputs: ["successEvent"] }, { kind: "component", type: i8$1.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i11$1.UiSwitchComponent, selector: "ui-switch", inputs: ["size", "color", "switchOffColor", "switchColor", "defaultBgColor", "defaultBoColor", "checkedLabel", "uncheckedLabel", "checkedTextColor", "uncheckedTextColor", "beforeChange", "ariaLabel", "checked", "disabled", "reverse", "loading"], outputs: ["change", "changeEvent", "valueChange"] }, { kind: "component", type: i5.NumberPickerComponent, selector: "pw-number-picker", inputs: ["min", "showTooltip", "tooltipText", "max", "step", "value", "pickStartAfter", "pickTimer", "prefix", "postfix", "placeholder", "buttonsOrientation", "size", "customClass", "mouseWheel", "arrowKeys", "inputReadOnly", "showUpButton", "showDownButton", "inputId"], outputs: ["valueChange", "minReached", "maxReached", "pickStarted", "pickStopped", "pickUpStarted", "pickUpStopped", "pickDownStarted", "pickDownStopped"] }, { kind: "component", type: i10.ProfileImageCropperComponent, selector: "pw-image-cropper", inputs: ["aspectRatio", "dynamicData"], outputs: ["imageSelectionEvent", "closeEvent", "fileChangeEvent"] }, { kind: "component", type: i5.InputContainerComponent, selector: "pw-input-container", inputs: ["name", "controlId", "useAriaLabelledbyOnly", "label", "labelClass", "tooltipPosition", "required", "errorMsg", "isReadOnly", "showTooltip", "tooltipText", "showTriangle", "afterLabel", "showAfterLabel", "showTriangleText", "isLeftTooltip"] }, { kind: "directive", type: i11.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "pipe", type: i8.AsyncPipe, name: "async" }, { kind: "pipe", type: i8.DecimalPipe, name: "number" }, { kind: "pipe", type: i8.CurrencyPipe, name: "currency" }, { kind: "pipe", type: i8$2.TranslocoPipe, name: "transloco" }, { kind: "pipe", type: i6.CurrencySymbolPipe, name: "currencySymbol" }] }); }
|
|
1591
1687
|
}
|
|
1592
1688
|
__decorate([
|
|
1593
1689
|
ValidateForm('form'),
|
|
@@ -1597,8 +1693,8 @@ __decorate([
|
|
|
1597
1693
|
], UserSubscriptionDetailsComponent.prototype, "onSaveDetails", null);
|
|
1598
1694
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: UserSubscriptionDetailsComponent, decorators: [{
|
|
1599
1695
|
type: Component,
|
|
1600
|
-
args: [{ standalone: false, template: "<!-- edit Subscription details page -->\n<div class=\"row\">\n <div class=\"col-12\">\n <h3 class=\"my-3\">{{ subscription?.organisation || subscription?.contact_name }}</h3>\n </div>\n</div>\n\n@if (subscription) {\n <form [formGroup]=\"form\"\n (ngSubmit)=\"onSaveDetails()\"\n class=\"row mt-4\"\n >\n <!-- 1. Contact details -->\n <div class=\"col-12\">\n <h3>Contact details</h3>\n </div>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.ContactName' | transloco\"\n class=\"col-md-6\"\n label=\"Contact Name\"\n name=\"contact_name\"\n controlId=\"user-subscription-contact_name\"\n errorMsg=\"Please enter Contact Name\">\n <input type=\"text\"\n id=\"user-subscription-contact_name\"\n class=\"form-control\"\n formControlName=\"contact_name\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.ContactEmail' | transloco\"\n class=\"col-md-6\"\n label=\"Contact Email\"\n name=\"contact_email\"\n controlId=\"user-subscription-contact_email\"\n errorMsg=\"Please enter Contact Email\">\n <input type=\"text\"\n id=\"user-subscription-contact_email\"\n class=\"form-control\"\n formControlName=\"contact_email\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Organization' | transloco\"\n class=\"col-md-6\"\n label=\"Organisation\"\n name=\"organisation\"\n controlId=\"user-subscription-organisation\"\n errorMsg=\"Please enter organisation\">\n <input type=\"text\"\n id=\"user-subscription-organisation\"\n class=\"form-control\"\n formControlName=\"organisation\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Phone' | transloco\"\n class=\"col-md-6\"\n label=\"Contact Tel\"\n name=\"contact_tel\"\n controlId=\"user-subscription-contact_tel\"\n errorMsg=\"Please enter Contact Telephone Number\">\n <input type=\"text\"\n id=\"user-subscription-contact_tel\"\n class=\"form-control\"\n formControlName=\"contact_tel\" />\n </pw-input-container>\n @if (countries$ | async; as countries) {\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Country' | transloco\"\n class=\"col-md-6\"\n label=\"Country\"\n name=\"country_code\"\n controlId=\"user-subscription-country_code\"\n [useAriaLabelledbyOnly]=\"true\"\n [isLeftTooltip]=\"true\"\n errorMsg=\"Please select a country\">\n <p-select\n [attr.aria-labelledby]=\"'user-subscription-country_code-label'\"\n [options]=\"countries\"\n optionLabel=\"name\"\n optionValue=\"code\"\n formControlName=\"country_code\"\n placeholder=\"Select Country\">\n </p-select>\n </pw-input-container>\n }\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Address' | transloco\"\n class=\"col-md-6\"\n label=\"Address\"\n name=\"address\"\n controlId=\"user-subscription-address\"\n [useAriaLabelledbyOnly]=\"true\"\n errorMsg=\"Please enter address\">\n <input ngx-gp-autocomplete\n id=\"user-subscription-address\"\n name=\"address\"\n class=\"form-control\"\n [attr.aria-labelledby]=\"'user-subscription-address-label'\"\n #places=\"ngx-places\"\n formControlName=\"address\"\n (onAddressChange)=\"handleAddressChange($event)\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.VatNumber' | transloco\"\n class=\"col-md-6\"\n label=\"GST/VAT Number\"\n name=\"tax_id\"\n controlId=\"user-subscription-tax_id\"\n errorMsg=\"Please enter GST/VAT Number\">\n <input type=\"text\"\n id=\"user-subscription-tax_id\"\n class=\"form-control\"\n formControlName=\"tax_id\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.CompanyUrl' | transloco\"\n class=\"col-md-6\"\n label=\"Company URL\"\n name=\"company_url\"\n controlId=\"user-subscription-company_url\"\n errorMsg=\"Please enter company url\">\n <input type=\"text\"\n id=\"user-subscription-company_url\"\n class=\"form-control\"\n formControlName=\"company_url\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.InvoiceRecipientEmails' | transloco\"\n class=\"col-md-6\"\n label=\"Invoice Recipient Emails\"\n name=\"invoice_recipient_emails\"\n controlId=\"user-subscription-invoice_recipient_emails\"\n errorMsg=\"Please enter valid email addresses separated by commas\">\n <input type=\"text\"\n id=\"user-subscription-invoice_recipient_emails\"\n class=\"form-control\"\n formControlName=\"invoice_recipient_emails\"\n placeholder=\"email1@example.com,email2@example.com\" />\n </pw-input-container>\n\n <!-- 2. Branding / Logos -->\n <div class=\"col-12\">\n <div class=\"row branding-section\">\n <div class=\"col-12\">\n <h3>Branding</h3>\n </div>\n </div>\n <div class=\"row\">\n <div class=\"col-md-6\">\n <div class=\"text-center mt-5\">\n <div class=\"image-container\">\n <h4 class=\"mb-2\">{{ 'User.Subscriptions.FullLogo' | transloco }}\n <span class=\"tooltip-wrap ms-1\"\n [pTooltip]=\"'User.Subscriptions.Tooltip.FullLogo'|transloco\"\n [appendTo]=\"'body'\"\n [tooltipPosition]=\"'top'\">\n <i class=\"far fa-info-circle text-muted\"></i>\n </span>\n </h4>\n @if (fullLogo && !fullLogo.includes('no_image_uploaded') && !fullLogoBroken) {\n <img [src]=\"fullLogo\"\n alt=\"full logo\"\n class=\"image full-logo\"\n role=\"presentation\"\n (error)=\"fullLogoBroken = true\" />\n <div class=\"overlay mt-2\"\n (keydown.enter)=\"openModal(content)\"\n (click)=\"openModal(content)\">\n <div class=\"overlay-text\">\n <a aria-label=\"Navigate to Target\">{{ 'User.Profile.Change' | transloco }}</a>\n </div>\n </div>\n } @else {\n <div class=\"logo-dropzone full-dropzone\"\n role=\"button\"\n tabindex=\"0\"\n aria-label=\"Upload full logo\"\n (keydown.enter)=\"openModal(content)\"\n (click)=\"openModal(content)\">\n <i class=\"fas fa-upload\"></i>\n <span class=\"dropzone-title\">Upload a logo</span>\n <span class=\"dropzone-hint\">PNG or JPG</span>\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"col-md-6\">\n <div class=\"text-center mt-5\">\n <div class=\"image-container\">\n <h4 class=\"mb-2\">Squared Logo\n <span class=\"tooltip-wrap ms-1\"\n [pTooltip]=\"'User.Subscriptions.Tooltip.SquaredLogo'|transloco\"\n [appendTo]=\"'body'\"\n [tooltipPosition]=\"'top'\">\n <i class=\"far fa-info-circle text-muted\"></i>\n </span>\n </h4>\n @if (squaredLogo && !squaredLogo.includes('no_image_uploaded') && !squaredLogoBroken) {\n <img [src]=\"squaredLogo\"\n alt=\"Squared Presentation\"\n class=\"squared_logo\"\n role=\"presentation\"\n (error)=\"squaredLogoBroken = true\" />\n <div class=\"overlay mt-2\"\n (keydown.enter)=\"openModal(squaredLogoContent)\"\n (click)=\"openModal(squaredLogoContent)\">\n <div class=\"overlay-text\">\n <a aria-label=\"Navigate to Target\">{{ 'User.Profile.Change' | transloco }}</a>\n </div>\n </div>\n } @else {\n <div class=\"logo-dropzone squared-dropzone\"\n role=\"button\"\n tabindex=\"0\"\n aria-label=\"Upload squared logo\"\n (keydown.enter)=\"openModal(squaredLogoContent)\"\n (click)=\"openModal(squaredLogoContent)\">\n <i class=\"fas fa-upload\"></i>\n <span class=\"dropzone-title\">Upload a logo</span>\n <span class=\"dropzone-hint\">PNG or JPG</span>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- 3. Social Media -->\n <ng-container *rbacAllow=\"'SubscriptionSuperAdmin'\">\n <div class=\"col-12\">\n <h3>Social Media</h3>\n <p>\n Any of the social media handles that you set here will appear in the footer of emails going out to your child subscriptions.\n </p>\n </div>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.FacebookHandle' | transloco\"\n class=\"col-md-6\"\n label=\"Facebook handle\"\n name=\"facebook_handle\"\n controlId=\"user-subscription-facebook_handle\"\n errorMsg=\"Please enter facebook id\">\n <input type=\"text\"\n id=\"user-subscription-facebook_handle\"\n class=\"form-control\"\n formControlName=\"facebook_handle\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.TwitterHandle' | transloco\"\n class=\"col-md-6\"\n label=\"Twitter handle\"\n name=\"twitter_handle\"\n controlId=\"user-subscription-twitter_handle\"\n errorMsg=\"Please enter twitter id\">\n <input type=\"text\"\n id=\"user-subscription-twitter_handle\"\n class=\"form-control\"\n formControlName=\"twitter_handle\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.LinkedinHandle' | transloco\"\n class=\"col-md-6\"\n label=\"Linkedin handle\"\n name=\"linkedin_handle\"\n controlId=\"user-subscription-linkedin_handle\"\n errorMsg=\"Please enter linkedin id\">\n <input type=\"text\"\n id=\"user-subscription-linkedin_handle\"\n class=\"form-control\"\n formControlName=\"linkedin_handle\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.RedditHandle' | transloco\"\n class=\"col-md-6\"\n label=\"Reddit handle\"\n name=\"reddit_handle\"\n controlId=\"user-subscription-reddit_handle\"\n errorMsg=\"Please enter reddit id\">\n <input type=\"text\"\n id=\"user-subscription-reddit_handle\"\n class=\"form-control\"\n formControlName=\"reddit_handle\" />\n </pw-input-container>\n </ng-container>\n\n <!-- 4. Seats -->\n <div class=\"col-12\">\n <div class=\"row seats-section\">\n <div class=\"col-12\">\n <h3>Seats</h3>\n <p>Changing the number of seats updates your subscription cost.</p>\n </div>\n </div>\n <div class=\"row\">\n <div class=\"col-12\">\n @if (subscription?.trial_subscription && subscription?.calculated_price) {\n <small\n class=\"text-danger\">Upgrade to be able to update your purchased seats</small>\n }\n </div>\n </div>\n <div class=\"row btns-row align-items-center\">\n @if (subscription) {\n <div class=\"col-md-3 col-8\"\n >\n <label for=\"user-subscription-seats\" class=\"visually-hidden\">{{ 'User.Subscriptions.Tooltip.Seats' | transloco }}</label>\n <pw-number-picker [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Seats'|transloco\"\n inputId=\"user-subscription-seats\"\n name=\"number-picker\"\n [(value)]=\"units\"\n [min]=\"subscription?.min_units||subscription?.products[0].min_units\"\n [max]=\"subscription?.products[0].max_units\"\n step=\"1\"\n postfix=\"seats\"\n placeholder=\"Total Licences\"\n [inputReadOnly]=\"subscription?.products[0].trial_subscription\"\n [showUpButton]=\"!subscription?.products[0].trial_subscription\"\n [showDownButton]=\"!subscription?.products[0].trial_subscription\"\n size=\"small\"\n pickStartAfter=\"500\"\n pickTimer=\"100\"\n [arrowKeys]=\"true\"\n (minReached)=\"onMinReached($event)\"\n (maxReached)=\"onMaxReached($event)\"\n (valueChange)=\"onUnitChange($event)\">\n </pw-number-picker>\n </div>\n }\n\n @if (subscription) {\n <div class=\"col-md-3 col-4 p-1\"\n >\n @if (!subscription?.products[0].trial_subscription && allowUpdate) {\n <button type=\"button\"\n class=\"btn btn-primary\"\n (click)=\"updateUnits()\">\n {{ 'User.Subscriptions.UpdateUnits' | transloco }}\n </button>\n } @else {\n <div>\n @if (subscription?.products[0].trial_subscription) {\n <small class=\"text-muted\"\n >Update seats is available only to paid subscriptions</small>\n }\n </div>\n }\n </div>\n }\n\n @if (hasUnitChanged) {\n <div class=\"col-12 col-md-6\"\n >\n <table class=\"table table-borderless table-sm\"\n aria-describedby=\"Product details\">\n <thead>\n <tr>\n <th scope=\"true\">Product</th>\n <th scope=\"true\">Price per seat <span>({{subscription?.products[0]?.currency|currencySymbol}})</span></th>\n <th scope=\"true\">Seats</th>\n </tr>\n </thead>\n <tbody>\n @for (product of subscription.products; track trackByProduct($index, product)) {\n <tr>\n <td>{{ product.name }}</td>\n <td>{{ product.price_per_unit / 100 }}</td>\n <td>{{ units }}</td>\n </tr>\n }\n </tbody>\n </table>\n <p>\n If you proceed, the new cost for your subscription will be\n <strong>{{ totalAmount()| currency: subscription?.products[0]?.currency:'symbol-narrow'}}</strong>\n </p>\n </div>\n }\n </div>\n </div>\n\n <!-- 5. API & MCP Credentials -->\n @if (subscription?.api_hits_max > 0) {\n <div class=\"col-12\">\n <h3>{{ 'User.Subscriptions.APICredentials.Title' | transloco }}</h3>\n <p>\n These credentials authenticate both REST API and MCP (Model Context Protocol) requests, and must be used together with the user tokens defined on your Account page.\n </p>\n </div>\n <div class=\"col-md-6\">\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"user-subscription-api-token\">\n {{ 'User.Subscriptions.APICredentials.AccessToken' | transloco }}\n <span class=\"tooltip-wrap ms-1\"\n pTooltip=\"The subscription token has been discontinued in favour of the user token defined on your Account page.\"\n [appendTo]=\"'body'\"\n [tooltipPosition]=\"'top'\">\n <i class=\"far fa-info-circle text-muted\"></i>\n </span>\n </label>\n <div class=\"input-group\">\n <input type=\"text\"\n id=\"user-subscription-api-token\"\n name=\"api_token\"\n class=\"form-control\"\n [value]=\"showApiToken ? subscription?.api_access_token || ('User.Subscriptions.APICredentials.NoTokenAvailable' | transloco) : '*************************'\"\n readonly />\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"toggleApiTokenVisibility()\">\n {{ showApiToken ? ('User.Subscriptions.APICredentials.Hide' | transloco) : ('User.Subscriptions.APICredentials.View' | transloco) }}\n </button>\n </div>\n </div>\n </div>\n <div class=\"col-md-6\">\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"user-subscription-api-client-id\">{{ 'User.Subscriptions.APICredentials.ClientId' | transloco }}</label>\n <div class=\"input-group\">\n <input type=\"text\"\n id=\"user-subscription-api-client-id\"\n name=\"api_client_id\"\n class=\"form-control\"\n [value]=\"showApiClientId ? subscription?.api_client_id || ('User.Subscriptions.APICredentials.NoClientIdAvailable' | transloco) : '*************************'\"\n readonly />\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"toggleApiClientIdVisibility()\">\n {{ showApiClientId ? ('User.Subscriptions.APICredentials.Hide' | transloco) : ('User.Subscriptions.APICredentials.View' | transloco) }}\n </button>\n </div>\n </div>\n </div>\n <div class=\"col-12 mt-3\">\n <div class=\"d-flex align-items-center gap-3\">\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"refreshApiTokens()\"\n [disabled]=\"refreshingTokens\">\n <i class=\"fas fa-sync-alt me-2\" [class.fa-spin]=\"refreshingTokens\"></i>\n {{ refreshingTokens ? ('User.Subscriptions.APICredentials.Refreshing' | transloco) : ('User.Subscriptions.APICredentials.RefreshTokens' | transloco) }}\n </button>\n <div class=\"d-flex align-items-center gap-2\">\n @if (subscription?.api_hits !== null) {\n <span class=\"text-muted\">{{ 'User.Subscriptions.APICredentials.ApiHits' | transloco }}:</span>\n <span class=\"fw-bold\">{{ subscription.api_hits | number }}</span>\n }\n @if (subscription?.api_hits_max !== null) {\n <span class=\"text-muted\">{{ 'User.Subscriptions.APICredentials.ApiHitsMax' | transloco }}:</span>\n <span class=\"fw-bold\">{{ subscription.api_hits_max | number }}</span>\n }\n <!-- Show utilization percentage when both values exist -->\n @if (subscription?.api_hits !== null || subscription?.api_hits_max !== null) {\n <span class=\"text-muted ms-2\">(</span>\n <span class=\"fw-bold\" [ngClass]=\"{\n 'text-success': (subscription.api_hits / subscription.api_hits_max) <= 0.8,\n 'text-warning': (subscription.api_hits / subscription.api_hits_max) > 0.8 && (subscription.api_hits / subscription.api_hits_max) <= 0.9,\n 'text-danger': (subscription.api_hits / subscription.api_hits_max) > 0.9\n }\">\n {{ (subscription.api_hits / subscription.api_hits_max * 100) | number:'1.0-0' }}% consumed\n </span>\n <span class=\"text-muted\">)</span>\n }\n </div>\n </div>\n </div>\n }\n\n <!-- 6. Security -->\n <div class=\"col-12 mt-5\">\n <h3>Security</h3>\n <p>\n While we'll add more security options in the future, please start by enforcing 2FA for all your subscription members.\n </p>\n </div>\n <div class=\"col-12 col-sm-3\">\n <pw-input-container label=\"Enforce 2FA\"\n [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Enforce2fa' | transloco\"\n name=\"enforce_2fa\"\n controlId=\"user-subscription-enforce_2fa\"\n [useAriaLabelledbyOnly]=\"true\">\n <ui-switch formControlName=\"enforce_2fa\"\n name=\"enforce_2fa\"\n [attr.aria-labelledby]=\"'user-subscription-enforce_2fa-label'\"> </ui-switch>\n </pw-input-container>\n </div>\n <div class=\"mb-3 col-12 text-end mt-3\">\n <button type=\"button\"\n class=\"btn btn-outline-default me-2\"\n routerLink=\"/account/subscriptions\">\n {{ 'Button.Cancel' | transloco }}\n </button>\n <button name=\"submit\"\n type=\"submit\"\n [buttonBusy]=\"busyButton\"\n class=\"btn btn-primary\">\n {{ 'Button.Submit' | transloco }}\n </button>\n </div>\n </form>\n}\n\n<ng-template #content\n let-modal>\n <div class=\"modal-header\">\n <h3 class=\"modal-title mb-0 p-0\">{{ 'User.Subscriptions.FullLogo' | transloco }}</h3>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n <small> {{ 'User.Profile.PictureMessage' | transloco }}</small>\n <pw-image-cropper #profile\n (imageSelectionEvent)=\"onImageSelection($event)\"\n aspectRatio=\"fullLogo\"\n (closeEvent)=\"onClose()\">\n </pw-image-cropper>\n </div>\n</ng-template>\n<ng-template #squaredLogoContent\n let-modal>\n <div class=\"modal-header\">\n <h3 class=\"modal-title mb-0 p-0\">{{ 'User.Subscriptions.SquaredLogo' | transloco }}</h3>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n <small> {{ 'User.Profile.PictureMessage' | transloco }}</small>\n <pw-image-cropper #profile\n (imageSelectionEvent)=\"uploadSquaredLogo($event)\"\n aspectRatio=\"auto\"\n (closeEvent)=\"onClose()\">\n </pw-image-cropper>\n </div>\n</ng-template>\n<pw-password-validation #modal\n(successEvent)=\"onPasswordValidation($event)\"> </pw-password-validation>\n", styles: [":host{display:block}:host>.row:first-of-type h3{color:var(--titles, #222);font-size:24px;font-weight:700;letter-spacing:-.01em;line-height:1.18}:host form .col-12>h3,:host .seats-section>.col-12>h3,:host .branding-section>.col-12>h3{border-top:1px solid #e2e5ea;color:var(--titles, #222);display:block;font-size:18px;font-weight:600;margin-top:32px;padding-top:24px}:host form>.col-12:first-child>h3{border-top:0;margin-top:0;padding-top:0}:host form .col-12>p,:host .seats-section>.col-12>p{color:#5a6473;font-size:15px;margin-bottom:16px}:host .row .text-center.mt-5{margin-top:16px!important;text-align:left!important}:host .image-container>h4{color:var(--titles, #222);font-size:14px;font-weight:600}:host .full-logo,:host .squared_logo{background:#f7f8fa;border:1px solid #e2e5ea;border-radius:8px;object-fit:contain;padding:12px}:host .full-logo{height:120px;width:280px}:host .squared_logo{height:150px;width:150px}:host .overlay{cursor:pointer;margin-top:8px}:host .overlay-text a{color:var(--first, #1769e1);cursor:pointer;font-weight:600}:host .overlay-text a:hover{text-decoration:underline}.sub-header{color:gray;font-size:20px;font-weight:600}@media only screen and (max-width:767px){.btns-row>[class*=col-]{flex:0 0 100%;max-width:100%}.btns-row .btn-primary{font-size:.8rem;margin-top:5px;padding:.375rem .5rem}}\n"] }]
|
|
1601
|
-
}], ctorParameters: () => [{ type: i2.UntypedFormBuilder }, { type: i1$2.GeoService }, { type: i1$1.NgbModal }, { type: i1$2.SubscriptionService }, { type: i4$
|
|
1696
|
+
args: [{ standalone: false, template: "<!-- edit Subscription details page -->\n<div class=\"row\">\n <div class=\"col-12\">\n <h3 class=\"my-3\">{{ subscription?.organisation || subscription?.contact_name }}</h3>\n </div>\n</div>\n\n@if (subscription) {\n <form [formGroup]=\"form\"\n (ngSubmit)=\"onSaveDetails()\"\n class=\"row mt-4\"\n >\n <!-- 1. Contact details -->\n <div class=\"col-12\">\n <h3>Contact details</h3>\n </div>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.ContactName' | transloco\"\n class=\"col-md-6\"\n label=\"Contact Name\"\n name=\"contact_name\"\n controlId=\"user-subscription-contact_name\"\n errorMsg=\"Please enter Contact Name\">\n <input type=\"text\"\n id=\"user-subscription-contact_name\"\n class=\"form-control\"\n formControlName=\"contact_name\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.ContactEmail' | transloco\"\n class=\"col-md-6\"\n label=\"Contact Email\"\n name=\"contact_email\"\n controlId=\"user-subscription-contact_email\"\n errorMsg=\"Please enter Contact Email\">\n <input type=\"text\"\n id=\"user-subscription-contact_email\"\n class=\"form-control\"\n formControlName=\"contact_email\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Organization' | transloco\"\n class=\"col-md-6\"\n label=\"Organisation\"\n name=\"organisation\"\n controlId=\"user-subscription-organisation\"\n errorMsg=\"Please enter organisation\">\n <input type=\"text\"\n id=\"user-subscription-organisation\"\n class=\"form-control\"\n formControlName=\"organisation\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Phone' | transloco\"\n class=\"col-md-6\"\n label=\"Contact Tel\"\n name=\"contact_tel\"\n controlId=\"user-subscription-contact_tel\"\n errorMsg=\"Please enter Contact Telephone Number\">\n <input type=\"text\"\n id=\"user-subscription-contact_tel\"\n class=\"form-control\"\n formControlName=\"contact_tel\" />\n </pw-input-container>\n @if (countries$ | async; as countries) {\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Country' | transloco\"\n class=\"col-md-6\"\n label=\"Country\"\n name=\"country_code\"\n controlId=\"user-subscription-country_code\"\n [useAriaLabelledbyOnly]=\"true\"\n [isLeftTooltip]=\"true\"\n errorMsg=\"Please select a country\">\n <p-select\n [attr.aria-labelledby]=\"'user-subscription-country_code-label'\"\n [options]=\"countries\"\n optionLabel=\"name\"\n optionValue=\"code\"\n formControlName=\"country_code\"\n placeholder=\"Select Country\">\n </p-select>\n </pw-input-container>\n }\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Address' | transloco\"\n class=\"col-md-6\"\n label=\"Address\"\n name=\"address\"\n controlId=\"user-subscription-address\"\n [useAriaLabelledbyOnly]=\"true\"\n errorMsg=\"Please enter address\">\n <input ngx-gp-autocomplete\n id=\"user-subscription-address\"\n name=\"address\"\n class=\"form-control\"\n [attr.aria-labelledby]=\"'user-subscription-address-label'\"\n #places=\"ngx-places\"\n formControlName=\"address\"\n (onAddressChange)=\"handleAddressChange($event)\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.VatNumber' | transloco\"\n class=\"col-md-6\"\n label=\"GST/VAT Number\"\n name=\"tax_id\"\n controlId=\"user-subscription-tax_id\"\n errorMsg=\"Please enter GST/VAT Number\">\n <input type=\"text\"\n id=\"user-subscription-tax_id\"\n class=\"form-control\"\n formControlName=\"tax_id\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.CompanyUrl' | transloco\"\n class=\"col-md-6\"\n label=\"Company URL\"\n name=\"company_url\"\n controlId=\"user-subscription-company_url\"\n errorMsg=\"Please enter company url\">\n <input type=\"text\"\n id=\"user-subscription-company_url\"\n class=\"form-control\"\n formControlName=\"company_url\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.InvoiceRecipientEmails' | transloco\"\n class=\"col-md-6\"\n label=\"Invoice Recipient Emails\"\n name=\"invoice_recipient_emails\"\n controlId=\"user-subscription-invoice_recipient_emails\"\n errorMsg=\"Please enter valid email addresses separated by commas\">\n <input type=\"text\"\n id=\"user-subscription-invoice_recipient_emails\"\n class=\"form-control\"\n formControlName=\"invoice_recipient_emails\"\n placeholder=\"email1@example.com,email2@example.com\" />\n </pw-input-container>\n\n <!-- 2. Branding / Logos -->\n <div class=\"col-12\">\n <div class=\"row branding-section\">\n <div class=\"col-12\">\n <h3>Branding</h3>\n </div>\n </div>\n <div class=\"row\">\n <div class=\"col-md-6\">\n <div class=\"text-center mt-5\">\n <div class=\"image-container\">\n <h4 class=\"mb-2\">{{ 'User.Subscriptions.FullLogo' | transloco }}\n <span class=\"tooltip-wrap ms-1\"\n [pTooltip]=\"'User.Subscriptions.Tooltip.FullLogo'|transloco\"\n [appendTo]=\"'body'\"\n [tooltipPosition]=\"'top'\">\n <i class=\"far fa-info-circle text-muted\"></i>\n </span>\n </h4>\n @if (fullLogo && !fullLogo.includes('no_image_uploaded') && !fullLogoBroken) {\n <img [src]=\"fullLogo\"\n alt=\"full logo\"\n class=\"image full-logo\"\n role=\"presentation\"\n (error)=\"fullLogoBroken = true\" />\n <div class=\"overlay mt-2\"\n (keydown.enter)=\"openModal(content)\"\n (click)=\"openModal(content)\">\n <div class=\"overlay-text\">\n <a aria-label=\"Navigate to Target\">{{ 'User.Profile.Change' | transloco }}</a>\n </div>\n </div>\n } @else {\n <div class=\"logo-dropzone full-dropzone\"\n role=\"button\"\n tabindex=\"0\"\n aria-label=\"Upload full logo\"\n (keydown.enter)=\"openModal(content)\"\n (click)=\"openModal(content)\">\n <i class=\"fas fa-upload\"></i>\n <span class=\"dropzone-title\">Upload a logo</span>\n <span class=\"dropzone-hint\">PNG or JPG</span>\n </div>\n }\n </div>\n </div>\n </div>\n <div class=\"col-md-6\">\n <div class=\"text-center mt-5\">\n <div class=\"image-container\">\n <h4 class=\"mb-2\">Squared Logo\n <span class=\"tooltip-wrap ms-1\"\n [pTooltip]=\"'User.Subscriptions.Tooltip.SquaredLogo'|transloco\"\n [appendTo]=\"'body'\"\n [tooltipPosition]=\"'top'\">\n <i class=\"far fa-info-circle text-muted\"></i>\n </span>\n </h4>\n @if (squaredLogo && !squaredLogo.includes('no_image_uploaded') && !squaredLogoBroken) {\n <img [src]=\"squaredLogo\"\n alt=\"Squared Presentation\"\n class=\"squared_logo\"\n role=\"presentation\"\n (error)=\"squaredLogoBroken = true\" />\n <div class=\"overlay mt-2\"\n (keydown.enter)=\"openModal(squaredLogoContent)\"\n (click)=\"openModal(squaredLogoContent)\">\n <div class=\"overlay-text\">\n <a aria-label=\"Navigate to Target\">{{ 'User.Profile.Change' | transloco }}</a>\n </div>\n </div>\n } @else {\n <div class=\"logo-dropzone squared-dropzone\"\n role=\"button\"\n tabindex=\"0\"\n aria-label=\"Upload squared logo\"\n (keydown.enter)=\"openModal(squaredLogoContent)\"\n (click)=\"openModal(squaredLogoContent)\">\n <i class=\"fas fa-upload\"></i>\n <span class=\"dropzone-title\">Upload a logo</span>\n <span class=\"dropzone-hint\">PNG or JPG</span>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n\n <!-- 3. Social Media -->\n <ng-container *rbacAllow=\"'SubscriptionSuperAdmin'\">\n <div class=\"col-12\">\n <h3>Social Media</h3>\n <p>\n Any of the social media handles that you set here will appear in the footer of emails going out to your child subscriptions.\n </p>\n </div>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.FacebookHandle' | transloco\"\n class=\"col-md-6\"\n label=\"Facebook handle\"\n name=\"facebook_handle\"\n controlId=\"user-subscription-facebook_handle\"\n errorMsg=\"Please enter facebook id\">\n <input type=\"text\"\n id=\"user-subscription-facebook_handle\"\n class=\"form-control\"\n formControlName=\"facebook_handle\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.TwitterHandle' | transloco\"\n class=\"col-md-6\"\n label=\"Twitter handle\"\n name=\"twitter_handle\"\n controlId=\"user-subscription-twitter_handle\"\n errorMsg=\"Please enter twitter id\">\n <input type=\"text\"\n id=\"user-subscription-twitter_handle\"\n class=\"form-control\"\n formControlName=\"twitter_handle\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.LinkedinHandle' | transloco\"\n class=\"col-md-6\"\n label=\"Linkedin handle\"\n name=\"linkedin_handle\"\n controlId=\"user-subscription-linkedin_handle\"\n errorMsg=\"Please enter linkedin id\">\n <input type=\"text\"\n id=\"user-subscription-linkedin_handle\"\n class=\"form-control\"\n formControlName=\"linkedin_handle\" />\n </pw-input-container>\n <pw-input-container [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.RedditHandle' | transloco\"\n class=\"col-md-6\"\n label=\"Reddit handle\"\n name=\"reddit_handle\"\n controlId=\"user-subscription-reddit_handle\"\n errorMsg=\"Please enter reddit id\">\n <input type=\"text\"\n id=\"user-subscription-reddit_handle\"\n class=\"form-control\"\n formControlName=\"reddit_handle\" />\n </pw-input-container>\n </ng-container>\n\n <!-- 4. Seats -->\n <div class=\"col-12\">\n <div class=\"row seats-section\">\n <div class=\"col-12\">\n <h3>Seats</h3>\n <p>Changing the number of seats updates your subscription cost.</p>\n </div>\n </div>\n <div class=\"row\">\n <div class=\"col-12\">\n @if (subscription?.trial_subscription && subscription?.calculated_price) {\n <small\n class=\"text-danger\">Upgrade to be able to update your purchased seats</small>\n }\n </div>\n </div>\n <div class=\"row btns-row align-items-center\">\n @if (subscription) {\n <div class=\"col-md-3 col-8\"\n >\n <label for=\"user-subscription-seats\" class=\"visually-hidden\">{{ 'User.Subscriptions.Tooltip.Seats' | transloco }}</label>\n <pw-number-picker [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Seats'|transloco\"\n inputId=\"user-subscription-seats\"\n name=\"number-picker\"\n [(value)]=\"units\"\n [min]=\"subscription?.min_units||subscription?.products[0].min_units\"\n [max]=\"subscription?.products[0].max_units\"\n step=\"1\"\n postfix=\"seats\"\n placeholder=\"Total Licences\"\n [inputReadOnly]=\"subscription?.products[0].trial_subscription\"\n [showUpButton]=\"!subscription?.products[0].trial_subscription\"\n [showDownButton]=\"!subscription?.products[0].trial_subscription\"\n size=\"small\"\n pickStartAfter=\"500\"\n pickTimer=\"100\"\n [arrowKeys]=\"true\"\n (minReached)=\"onMinReached($event)\"\n (maxReached)=\"onMaxReached($event)\"\n (valueChange)=\"onUnitChange($event)\">\n </pw-number-picker>\n </div>\n }\n\n @if (subscription) {\n <div class=\"col-md-3 col-4 p-1\"\n >\n @if (!subscription?.products[0].trial_subscription && allowUpdate) {\n <button type=\"button\"\n class=\"btn btn-primary\"\n (click)=\"updateUnits()\">\n {{ 'User.Subscriptions.UpdateUnits' | transloco }}\n </button>\n } @else {\n <div>\n @if (subscription?.products[0].trial_subscription) {\n <small class=\"text-muted\"\n >Update seats is available only to paid subscriptions</small>\n }\n </div>\n }\n </div>\n }\n\n @if (hasUnitChanged) {\n <div class=\"col-12 col-md-6\"\n >\n <table class=\"table table-borderless table-sm\"\n aria-describedby=\"Product details\">\n <thead>\n <tr>\n <th scope=\"true\">Product</th>\n <th scope=\"true\">Price per seat <span>({{subscription?.products[0]?.currency|currencySymbol}})</span></th>\n <th scope=\"true\">Seats</th>\n </tr>\n </thead>\n <tbody>\n @for (product of subscription.products; track trackByProduct($index, product)) {\n <tr>\n <td>{{ product.name }}</td>\n <td>{{ product.price_per_unit / 100 }}</td>\n <td>{{ units }}</td>\n </tr>\n }\n </tbody>\n </table>\n <p>\n If you proceed, the new cost for your subscription will be\n <strong>{{ totalAmount()| currency: subscription?.products[0]?.currency:'symbol-narrow'}}</strong>\n </p>\n </div>\n }\n </div>\n </div>\n\n <!-- 5. API & MCP Credentials -->\n @if (subscription?.api_hits_max > 0) {\n <div class=\"col-12\">\n <h3>{{ 'User.Subscriptions.APICredentials.Title' | transloco }}</h3>\n <p>\n These credentials authenticate both REST API and MCP (Model Context Protocol) requests, and must be used together with the user tokens defined on your Account page.\n </p>\n </div>\n <div class=\"col-md-6\">\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"user-subscription-api-token\">\n {{ 'User.Subscriptions.APICredentials.AccessToken' | transloco }}\n <span class=\"tooltip-wrap ms-1\"\n pTooltip=\"The subscription token has been discontinued in favour of the user token defined on your Account page.\"\n [appendTo]=\"'body'\"\n [tooltipPosition]=\"'top'\">\n <i class=\"far fa-info-circle text-muted\"></i>\n </span>\n </label>\n <div class=\"input-group\">\n <input type=\"text\"\n id=\"user-subscription-api-token\"\n name=\"api_token\"\n class=\"form-control\"\n [value]=\"showApiToken ? subscription?.api_access_token || ('User.Subscriptions.APICredentials.NoTokenAvailable' | transloco) : '*************************'\"\n readonly />\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"toggleApiTokenVisibility()\">\n {{ showApiToken ? ('User.Subscriptions.APICredentials.Hide' | transloco) : ('User.Subscriptions.APICredentials.View' | transloco) }}\n </button>\n </div>\n </div>\n </div>\n <div class=\"col-md-6\">\n <div class=\"form-group\">\n <label class=\"form-label\" for=\"user-subscription-api-client-id\">{{ 'User.Subscriptions.APICredentials.ClientId' | transloco }}</label>\n <div class=\"input-group\">\n <input type=\"text\"\n id=\"user-subscription-api-client-id\"\n name=\"api_client_id\"\n class=\"form-control\"\n [value]=\"showApiClientId ? subscription?.api_client_id || ('User.Subscriptions.APICredentials.NoClientIdAvailable' | transloco) : '*************************'\"\n readonly />\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"toggleApiClientIdVisibility()\">\n {{ showApiClientId ? ('User.Subscriptions.APICredentials.Hide' | transloco) : ('User.Subscriptions.APICredentials.View' | transloco) }}\n </button>\n </div>\n </div>\n </div>\n <div class=\"col-12 mt-3\">\n <div class=\"d-flex align-items-center gap-3\">\n <button type=\"button\"\n class=\"btn btn-outline-secondary\"\n (click)=\"refreshApiTokens()\"\n [disabled]=\"refreshingTokens\">\n <i class=\"fas fa-sync-alt me-2\" [class.fa-spin]=\"refreshingTokens\"></i>\n {{ refreshingTokens ? ('User.Subscriptions.APICredentials.Refreshing' | transloco) : ('User.Subscriptions.APICredentials.RefreshTokens' | transloco) }}\n </button>\n <div class=\"d-flex align-items-center gap-2\">\n @if (subscription?.api_hits !== null) {\n <span class=\"text-muted\">{{ 'User.Subscriptions.APICredentials.ApiHits' | transloco }}:</span>\n <span class=\"fw-bold\">{{ subscription.api_hits | number }}</span>\n }\n @if (subscription?.api_hits_max !== null) {\n <span class=\"text-muted\">{{ 'User.Subscriptions.APICredentials.ApiHitsMax' | transloco }}:</span>\n <span class=\"fw-bold\">{{ subscription.api_hits_max | number }}</span>\n }\n <!-- Show utilization percentage when both values exist -->\n @if (subscription?.api_hits !== null || subscription?.api_hits_max !== null) {\n <span class=\"text-muted ms-2\">(</span>\n <span class=\"fw-bold\" [ngClass]=\"{\n 'text-success-muted': (subscription.api_hits / subscription.api_hits_max) <= 0.8,\n 'text-warning': (subscription.api_hits / subscription.api_hits_max) > 0.8 && (subscription.api_hits / subscription.api_hits_max) <= 0.9,\n 'text-danger': (subscription.api_hits / subscription.api_hits_max) > 0.9\n }\">\n {{ (subscription.api_hits / subscription.api_hits_max * 100) | number:'1.0-0' }}% consumed\n </span>\n <span class=\"text-muted\">)</span>\n }\n </div>\n </div>\n </div>\n }\n\n <!-- 6. Security -->\n <div class=\"col-12 mt-5\">\n <h3>Security</h3>\n <p>\n While we'll add more security options in the future, please start by enforcing 2FA for all your subscription members.\n </p>\n </div>\n <div class=\"col-12 col-sm-3\">\n <pw-input-container label=\"Enforce 2FA\"\n [showTooltip]=\"true\"\n [tooltipText]=\"'User.Subscriptions.Tooltip.Enforce2fa' | transloco\"\n name=\"enforce_2fa\"\n controlId=\"user-subscription-enforce_2fa\"\n [useAriaLabelledbyOnly]=\"true\">\n <ui-switch formControlName=\"enforce_2fa\"\n name=\"enforce_2fa\"\n [attr.aria-labelledby]=\"'user-subscription-enforce_2fa-label'\"> </ui-switch>\n </pw-input-container>\n </div>\n <div class=\"mb-3 col-12 text-end mt-3\">\n <button type=\"button\"\n class=\"btn btn-outline-default me-2\"\n routerLink=\"/account/subscriptions\">\n {{ 'Button.Cancel' | transloco }}\n </button>\n <button name=\"submit\"\n type=\"submit\"\n [buttonBusy]=\"busyButton\"\n class=\"btn btn-primary\">\n {{ 'Button.Submit' | transloco }}\n </button>\n </div>\n </form>\n}\n\n<ng-template #content\n let-modal>\n <div class=\"modal-header\">\n <h3 class=\"modal-title mb-0 p-0\">{{ 'User.Subscriptions.FullLogo' | transloco }}</h3>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n <small> {{ 'User.Profile.PictureMessage' | transloco }}</small>\n <pw-image-cropper #profile\n (imageSelectionEvent)=\"onImageSelection($event)\"\n aspectRatio=\"fullLogo\"\n (closeEvent)=\"onClose()\">\n </pw-image-cropper>\n </div>\n</ng-template>\n<ng-template #squaredLogoContent\n let-modal>\n <div class=\"modal-header\">\n <h3 class=\"modal-title mb-0 p-0\">{{ 'User.Subscriptions.SquaredLogo' | transloco }}</h3>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n <small> {{ 'User.Profile.PictureMessage' | transloco }}</small>\n <pw-image-cropper #profile\n (imageSelectionEvent)=\"uploadSquaredLogo($event)\"\n aspectRatio=\"auto\"\n (closeEvent)=\"onClose()\">\n </pw-image-cropper>\n </div>\n</ng-template>\n<pw-password-validation #modal\n(successEvent)=\"onPasswordValidation($event)\"> </pw-password-validation>\n", styles: [":host{display:block}:host>.row:first-of-type h3{color:var(--titles, #222);font-size:24px;font-weight:700;letter-spacing:-.01em;line-height:1.18}:host form .col-12>h3,:host .seats-section>.col-12>h3,:host .branding-section>.col-12>h3{border-top:1px solid #e2e5ea;color:var(--titles, #222);display:block;font-size:18px;font-weight:600;margin-top:32px;padding-top:24px}:host form>.col-12:first-child>h3{border-top:0;margin-top:0;padding-top:0}:host form .col-12>p,:host .seats-section>.col-12>p{color:#5a6473;font-size:15px;margin-bottom:16px}:host .row .text-center.mt-5{margin-top:16px!important;text-align:left!important}:host .image-container>h4{color:var(--titles, #222);font-size:14px;font-weight:600}:host .full-logo,:host .squared_logo{background:#f7f8fa;border:1px solid #e2e5ea;border-radius:8px;object-fit:contain;padding:12px}:host .full-logo{height:120px;width:280px}:host .squared_logo{height:150px;width:150px}:host .overlay{cursor:pointer;margin-top:8px}:host .overlay-text a{color:var(--first, #1769e1);cursor:pointer;font-weight:600}:host .overlay-text a:hover{text-decoration:underline}.sub-header{color:gray;font-size:20px;font-weight:600}@media only screen and (max-width:767px){.btns-row>[class*=col-]{flex:0 0 100%;max-width:100%}.btns-row .btn-primary{font-size:.8rem;margin-top:5px;padding:.375rem .5rem}}\n"] }]
|
|
1697
|
+
}], ctorParameters: () => [{ type: i2.UntypedFormBuilder }, { type: i1$2.GeoService }, { type: i1$1.NgbModal }, { type: i1$2.SubscriptionService }, { type: i4$1.Store }, { type: i0.Injector }, { type: i0.ChangeDetectorRef }, { type: i5.ConfirmDialogService }], propDecorators: { modal: [{
|
|
1602
1698
|
type: ViewChild,
|
|
1603
1699
|
args: ['modal', { static: true }]
|
|
1604
1700
|
}], onSaveDetails: [] } });
|
|
@@ -1609,7 +1705,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
|
|
|
1609
1705
|
* Account => Subscription
|
|
1610
1706
|
*/
|
|
1611
1707
|
class UserSubscriptionListComponent extends AppBaseComponent {
|
|
1612
|
-
constructor(subscriptionService, adminService, modalService, store, clipboard, injector, cdr) {
|
|
1708
|
+
constructor(subscriptionService, adminService, modalService, store, clipboard, injector, cdr, confirmDialog) {
|
|
1613
1709
|
super(injector);
|
|
1614
1710
|
this.subscriptionService = subscriptionService;
|
|
1615
1711
|
this.adminService = adminService;
|
|
@@ -1617,6 +1713,7 @@ class UserSubscriptionListComponent extends AppBaseComponent {
|
|
|
1617
1713
|
this.store = store;
|
|
1618
1714
|
this.clipboard = clipboard;
|
|
1619
1715
|
this.cdr = cdr;
|
|
1716
|
+
this.confirmDialog = confirmDialog;
|
|
1620
1717
|
this.showApiKey = true;
|
|
1621
1718
|
this.subscribedSubscriptions = [];
|
|
1622
1719
|
this.isLoaded = false;
|
|
@@ -1762,21 +1859,15 @@ class UserSubscriptionListComponent extends AppBaseComponent {
|
|
|
1762
1859
|
}
|
|
1763
1860
|
}
|
|
1764
1861
|
noPasswordModal() {
|
|
1765
|
-
|
|
1862
|
+
this.confirmDialog.open({
|
|
1766
1863
|
title: 'Set Password',
|
|
1767
|
-
text:
|
|
1768
|
-
|
|
1864
|
+
text: 'Please set a password before changing the subscription in the account section.',
|
|
1865
|
+
confirmOnly: true
|
|
1769
1866
|
});
|
|
1770
1867
|
}
|
|
1771
1868
|
showModalForAccountDeletion() {
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
html: `Are you sure you want to delete?`,
|
|
1775
|
-
showCancelButton: true,
|
|
1776
|
-
reverseButtons: true,
|
|
1777
|
-
icon: 'warning'
|
|
1778
|
-
}).then(rep => {
|
|
1779
|
-
if (rep.value) {
|
|
1869
|
+
this.confirmDialog.confirmDelete().then(ok => {
|
|
1870
|
+
if (ok) {
|
|
1780
1871
|
this.passwordValidationModalForAccountDelete.open();
|
|
1781
1872
|
}
|
|
1782
1873
|
});
|
|
@@ -1805,13 +1896,13 @@ class UserSubscriptionListComponent extends AppBaseComponent {
|
|
|
1805
1896
|
ngOnDestroy() {
|
|
1806
1897
|
super.ngOnDestroy();
|
|
1807
1898
|
}
|
|
1808
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: UserSubscriptionListComponent, deps: [{ token: i1$2.SubscriptionService }, { token: i2$1.AdminService }, { token: i1$1.NgbModal }, { token: i4$
|
|
1809
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: UserSubscriptionListComponent, isStandalone: false, selector: "pw-user-subscriptions-list", viewQueries: [{ propertyName: "menu", first: true, predicate: ["menuItems"], descendants: true }, { propertyName: "changeSubscriptionRef", first: true, predicate: AddSubscriptionComponent, descendants: true }, { propertyName: "passwordValidationModalForAccountDelete", first: true, predicate: ["passwordValidationModalForAccountDelete"], descendants: true }, { propertyName: "passwordValidationModalForKey", first: true, predicate: ["passwordValidationModalForKey"], descendants: true }, { propertyName: "passwordValidationForUnsubscribe", first: true, predicate: ["passwordValidationForUnsubscribe"], descendants: true }, { propertyName: "cancelSubscriptionModal", first: true, predicate: ["cancelSubscriptionModal"], descendants: true }], usesInheritance: true, ngImport: i0, template: "@if (!showTos) {\n <!-- Subscriptions Tab Content -->\n @if (!editing && !isAddNew) {\n <div class=\"row\">\n <div class=\"col-12\">\n <h2>Your Subscriptions</h2>\n <p>You'll find in this section the summary of your subscriptions.</p>\n </div>\n </div>\n }\n <!-- Subscribed Product Cards -->\n @if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\"\n >\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n @if (\n !editing && !isAddNew && !isUpdatePayment && isLoaded && subscribedSubscriptions.length\n ) {\n <div class=\"row\"\n >\n @for (subscription of subscribedSubscriptions; track trackBySubscription($index, subscription)) {\n <div class=\"col-12 col-md-6 my-3\"\n >\n <div class=\"subscription-details mb-4\">\n <div class=\"subscription-summary d-flex flex-wrap justify-content-between align-items-start gap-2 mb-3\">\n <div class=\"subscription-summary__info\">\n <div>\n <strong>Organisation:</strong>\n {{ subscription.organisation ? subscription.organisation : subscription.contact_name }}\n </div>\n <div>\n <strong>{{ 'User.Subscriptions.TotalPriceExclTax' | transloco }}:</strong>\n @if (subscription.calculated_price) {\n {{ subscription.products[0]?.currency }} {{ subscription.calculated_price / 100 | number:'1.2-2' }}\n {{ subscription.products[0].trial_subscription ? '(After Trial)' : '' }}\n } @else {\n Free\n }\n </div>\n <div>\n <strong>{{ 'User.Subscriptions.SeatsInUse' | transloco }}:</strong>\n {{ subscription.units_in_use || 1 }} / {{ subscription.purchased_units }}\n @if (subscription.purchased_units) {\n <span class=\"seats-usage\"\n [style.--seats-pct]=\"(subscription.units_in_use || 1) / subscription.purchased_units\"></span>\n }\n </div>\n </div>\n <!-- Subscription-level actions (a subscription may hold multiple products) -->\n @if (\n (subscription.is_subscription_owner || subscription.is_subscription_admin) &&\n subscription.products?.length &&\n !subscription.products[0].deleted &&\n !subscription.products[0].dependency_products?.length\n ) {\n <div class=\"subscription-summary__actions d-flex flex-wrap align-items-center gap-2\">\n <a class=\"btn btn-outline-primary btn-sm\"\n aria-label=\"Navigate to Target\"\n [routerLink]=\"['../subscriptions', subscription.id]\">\n {{ 'Button.Edit' | transloco }}\n </a>\n @if (!subscription.products[0].expired && !subscription.products[0].trial_subscription) {\n <button [routerLink]=\"['../subscriptions', subscription.id, 'credential']\"\n class=\"btn btn-outline-secondary btn-sm\">\n {{ 'User.Subscriptions.Credentials' | transloco }}\n </button>\n }\n @if (!isUpdatePayment && subscription.stripe_customer_id) {\n <a class=\"btn btn-sm btn-outline-primary\"\n [routerLink]=\"['../subscriptions', subscription.id, 'product', subscription.products[0].id, 'update-payment']\">\n <i class=\"fa fa-edit me-1\" aria-hidden=\"true\"></i>{{ 'User.Subscriptions.UpdateCardDetails' | transloco }}</a>\n }\n <button class=\"btn btn-sm btn-outline-primary\"\n [routerLink]=\"'/account/subscriptions/add-new'\"\n [queryParams]=\"{ subscription_id: subscription.id }\"\n [pTooltip]=\"'User.Subscriptions.Tooltip.ManageAllProducts' | transloco\"\n tooltipPosition=\"bottom\">\n <i class=\"fa fa-plus me-1\"></i>{{ 'User.Subscriptions.SeeAllProducts' | transloco }}\n </button>\n </div>\n }\n </div>\n <!-- Products list -->\n @for (\n product of subscription.products; track trackByProduct($index,\n product); let first = $first) {\n <div class=\"mb-3\">\n <div class=\"card subscription-products-cards\">\n <div class=\"card-content\">\n <div class=\"card-header\">\n <div>\n <h4 class=\"mb-3 text-bold-500 primary\">{{ product?.name }}</h4>\n <!-- Frequency -->\n <div>\n <div>\n <strong class=\"d-inline-block w-50\">{{\n 'User.Subscriptions.Frequency' | transloco\n }}:</strong>\n {{ product?.billing_frequency | uppercase }}\n </div>\n </div>\n <!-- Expiration -->\n <div [ngClass]=\"{ 'text-danger': product.expired }\">\n <strong class=\"d-inline-block w-50\">{{\n product.expired ? 'Expired' : 'Expiry Date'\n }}:</strong>\n {{ product.expires_at | dateFormat }}\n </div>\n <!-- Estimated Price -->\n <div [ngClass]=\"{ 'text-danger': product.expired }\">\n <strong class=\"d-inline-block w-50\">{{\n 'User.Subscriptions.PriceExclTax' | transloco\n }}:</strong>\n {{ product.currency }}\n {{ (product.calculated_price / 100) | number:'1.2-2' }}\n </div>\n <!-- Product API Key (Alpha-only) -->\n <ng-container *rbacAllow=\"'Pages.Alpha'\">\n @if (\n (product.stripe_plan_id && product.max_hits > 0) ||\n product.max_hits_trial > 0\n ) {\n <div class=\"d-flex align-items-center\">\n <strong class=\"d-inline-block w-50\">\n {{ 'User.Subscriptions.ApiKey' | transloco }}:\n <i class=\"far fa-info-circle ms-1 text-muted\"\n aria-hidden=\"true\"\n [ngbTooltip]=\"'User.Subscriptions.ApiKey.NotUsedHint' | transloco\"></i>\n </strong>\n <code class=\"text-truncate me-2\">{{ product.masked }}</code>\n <span class=\"ms-auto d-flex align-items-center flex-shrink-0\">\n <!-- Show Access Key -->\n <button class=\"btn\"\n ngbTooltip=\"Show Access Key\"\n (click)=\"showKey(product)\">\n <i class=\"fas fa-eye\" aria-hidden=\"true\"></i>\n </button>\n <!-- Copy To Clipboard -->\n <button class=\"btn\"\n ngbTooltip=\"Copy Key\">\n <i class=\"fal fa-copy\"\n aria-hidden=\"true\"\n (click)=\"onClipboardCopy(product.api_access_token)\"\n (keydown.enter)=\"onClipboardCopy(product.api_access_token)\"></i>\n </button>\n <!-- Update API Key -->\n @if (!product.expired && !product.deleted) {\n <button class=\"btn\"\n ngbTooltip=\"Change Key\"\n (click)=\"updateApiKey(subscription, product)\">\n <i class=\"fal fa-sync-alt\" aria-hidden=\"true\"></i>\n </button>\n }\n </span>\n </div>\n }\n </ng-container>\n </div>\n </div>\n <div class=\"card-footer px-3 d-flex flex-column gap-2\">\n <div class=\"footer-status d-flex flex-wrap align-items-center gap-2\">\n @if (product.deleted && !product.expired) {\n <span class=\"footer-note\">\n <i class=\"fa fa-info-circle me-2\" aria-hidden=\"true\"></i>{{ 'User.Subscriptions.OutdatedMessage' | transloco }}\n </span>\n }\n @if (product.deleted) {\n <span class=\"badge bg-danger\">Deleted</span>\n }\n @if (\n product.trial_subscription &&\n product.calculated_price\n ) {\n <span class=\"badge bg-warning\">Trial</span>\n }\n @if (product?.pause_collection && objectKeys(product?.pause_collection)?.length) {\n <span class=\"badge bg-grey\"\n [pTooltip]=\"'User.Subscriptions.Tooltip.PausedCollection'|transloco\"\n tooltipPosition=\"top\">\n Paused collection\n </span>\n }\n @if (!product.calculated_price) {\n <span class=\"badge bg-success\">Free</span>\n }\n @if (!product?.deleted && !subscription.is_subscription_owner) {\n <span class=\"footer-note\">\n <i class=\"fa fa-info-circle me-2\" aria-hidden=\"true\"></i>Invited to use this product\n @if (subscription.is_subscription_admin) {\n <span class=\"badge bg-role-admin ms-1\">as an admin</span>\n }\n </span>\n }\n </div>\n @if (\n subscription.is_subscription_owner ||\n subscription.is_subscription_admin\n ) {\n <div class=\"footer-actions d-flex flex-wrap align-items-center justify-content-end gap-2\">\n <!-- Unsubscribe -->\n @if (\n subscription?.stripe_customer_id &&\n !product?.deleted &&\n !product?.trial_subscription\n ) {\n <button class=\"btn btn-outline-danger btn-sm\"\n (click)=\"attemptUnsubscribe(subscription, product.id)\">\n {{ 'User.Subscriptions.Unsubscribe' | transloco }}\n </button>\n }\n @if (product.stripe_plan_id && product.active) {\n <!-- Upgrade (single primary CTA) -->\n @if (product.trial_subscription && !product.deleted) {\n <button class=\"btn btn-primary btn-sm\"\n (click)=\"attemptUpgrade(subscription, product)\">\n {{ 'Button.Upgrade' | transloco }}\n </button>\n }\n <!-- Subscribe -->\n @if (subscription.expired && product.stripe_plan_id) {\n <button class=\"btn btn-primary btn-sm\"\n [routerLink]=\"'/account/subscriptions/add-new'\">\n {{ 'User.Subscriptions.Subscribe' | transloco }}\n </button>\n }\n }\n <!-- Privacy & Terms of Service (quiet link, not a button) -->\n @if (product?.product_privacy_service_id) {\n <button class=\"btn btn-link btn-sm p-0 footer-tos-link\"\n (click)=\"showPrivacyAndTos(product)\">\n {{\n 'User.Subscriptions.PrivacyAndTermsOfService'\n | transloco\n }}\n </button>\n }\n </div>\n }\n </div>\n </div>\n </div>\n @if (subscription.products.length === 0) {\n <div>\n <div class=\"card\">\n <div class=\"card-content\">\n <div class=\"card-header\">\n <p class=\"text-center\">\n No product available for this subscription\n </p>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n }\n @if (!editing && !isAddNew && !isUpdatePayment) {\n <div class=\"col-12\"\n >\n @if (subscribedSubscriptions.length === 0) {\n <pw-no-data [withImage]=\"true\" message=\"You don't have any subscription.\"\n >\n </pw-no-data>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n <!-- Danger zone (demoted account deletion) -->\n @if (!editing && !isAddNew && !isUpdatePayment && isLoaded) {\n <div class=\"row\">\n <div class=\"col-12\">\n <div class=\"danger-zone mt-4\">\n <button type=\"button\"\n class=\"btn btn-sm btn-outline-danger danger-zone__action\"\n (click)=\"showModalForAccountDeletion()\"\n [pTooltip]=\"'User.Account.Tooltip.DeleteAccount' | transloco\"\n tooltipPosition=\"top\">\n {{ 'User.Account.DeleteAccount' | transloco }}\n </button>\n </div>\n </div>\n </div>\n }\n <!--\n Add New Subscription\n -->\n <!-- <ng-template [ngIf]=\"isAddNew && !isUpdatePayment\">\n <pw-subscription-details></pw-subscription-details>\n</ng-template> -->\n<!--\nValidate Password For Account Delete\n-->\n<pw-password-validation #passwordValidationModalForAccountDelete\n (successEvent)=\"deleteUser($event)\">\n <div class=\"row\">\n <div class=\"col-12\">\n <p>{{ 'User.Account.Message.ActionCanNotUndone' | transloco }}</p>\n <p>{{ 'User.Account.Message.ConfirmPassword' | transloco }}</p>\n </div>\n </div>\n</pw-password-validation>\n<!--\nValidate Password For Display Key\n-->\n<pw-password-validation #passwordValidationModalForKey\n (successEvent)=\"displayApiKey()\">\n</pw-password-validation>\n<!--\nValidate Password For Unsubscribe\n-->\n<pw-password-validation #passwordValidationForUnsubscribe\n (successEvent)=\"onValidatePassword($event)\">\n <div class=\"row\">\n <div class=\"col-12\">\n <p>{{ 'User.Account.Message.ActionCanNotUndone' | transloco }}</p>\n <p>{{ 'User.Account.Message.ConfirmPassword' | transloco }}</p>\n </div>\n </div>\n</pw-password-validation>\n<!--\nCancel Subscription Modal\n-->\n<ng-template #cancelSubscriptionModal let-modal>\n <div class=\"modal-header\">\n <h4 class=\"modal-title\">{{ 'User.Subscriptions.CancelSubscription.Title' | transloco }}</h4>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss(); reasonToCancel = '';\">\n </button>\n </div>\n <div class=\"modal-body\">\n <p>{{ 'User.Subscriptions.CancelSubscription.Message' | transloco }}</p>\n <div class=\"mb-3\">\n <label for=\"reasonToCancel\" class=\"form-label\">\n {{ 'User.Subscriptions.CancelSubscription.ReasonLabel' | transloco }} <span class=\"text-danger\">*</span>\n </label>\n <textarea\n id=\"reasonToCancel\"\n class=\"form-control\"\n rows=\"4\"\n [(ngModel)]=\"reasonToCancel\"\n [ngClass]=\"{'is-invalid': reasonToCancel && reasonToCancel.trim() === ''}\"\n placeholder=\"{{ 'User.Subscriptions.CancelSubscription.ReasonPlaceholder' | transloco }}\"></textarea>\n @if (reasonToCancel && reasonToCancel.trim() === '') {\n <div class=\"invalid-feedback\">\n {{ 'User.Subscriptions.Validation.ReasonRequired' | transloco }}\n </div>\n }\n </div>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\"\n class=\"btn btn-outline-default\"\n (click)=\"modal.dismiss(); reasonToCancel = '';\">\n {{ 'User.Subscriptions.CancelSubscription.KeepItForNow' | transloco }}\n </button>\n <button type=\"button\"\n class=\"btn btn-danger\"\n [disabled]=\"!reasonToCancel || reasonToCancel.trim() === ''\"\n (click)=\"onConfirmCancel(); modal.close()\">\n {{ 'User.Subscriptions.CancelSubscription.ConfirmButton' | transloco }}\n </button>\n </div>\n</ng-template>\n}\n\n@if (showTos) {\n <pw-privacy-and-tos [productId]=\"productId\"></pw-privacy-and-tos>\n}\n\n<router-outlet></router-outlet>\n", styles: [".btn-list{bottom:24px;left:0;padding:0 38px;right:0}.shadow-md{padding-bottom:70px!important}.bg-dark{border:0}.subscription-details{background:#fff;border:1px solid #e2e5ea;border-radius:12px;padding:16px 16px 6px;font-size:14px;font-variant-numeric:tabular-nums}.subscription-summary{border-bottom:1px solid #eef0f3;padding-bottom:12px}.seats-usage{display:inline-block;width:120px;height:6px;margin-left:8px;border-radius:999px;vertical-align:middle;overflow:hidden;background:linear-gradient(#5a6473,#5a6473) left/calc(var(--seats-pct, 0) * 100%) 100% no-repeat,#e2e5ea}.subscription-products-cards{padding-bottom:0!important}.subscription-products-cards .card-footer{position:static!important}.subscription-products-cards.card{background:#f7f8fa;border:1px solid #eef0f3;border-radius:8px;box-shadow:none!important;font-size:14px}.card-footer{background:transparent;border-top:1px solid #eef0f3}.card-footer .footer-note{color:#5a6473;font-size:.875rem}.card-footer .footer-tos-link{color:#5a6473;font-weight:500;text-decoration:underline}.card-footer .footer-tos-link:hover{color:var(--first)}.badge{font-weight:600;border-radius:4px}.badge.bg-success{background-color:#e6f4ec!important;color:#0f6b3a!important}.badge.bg-danger{background-color:#fbeae8!important;color:#c0392b!important}.badge.bg-warning{background-color:#fbf1e3!important;color:#8a5a00!important}.badge.bg-grey,.badge.bg-role-admin{background-color:#eef0f3!important;color:#5a6473!important}code{color:var(--text);min-width:0}.danger-zone{border-top:1px solid #e2e5ea;padding-top:16px;text-align:right}\n"], dependencies: [{ kind: "directive", type: i4.RbacAllowDirective, selector: "[rbacAllow]", inputs: ["rbacAllow"] }, { kind: "directive", type: i6.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "component", type: i5.PasswordValidationComponent, selector: "pw-password-validation", inputs: ["confirmMessage"], outputs: ["successEvent"] }, { kind: "directive", type: i1$1.NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "component", type: i4$1.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i5.PrivacyAndTosComponent, selector: "pw-privacy-and-tos", inputs: ["productId"] }, { kind: "component", type: i5.NoDataComponent, selector: "pw-no-data", inputs: ["message", "description", "withImage"] }, { kind: "directive", type: i11.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "pipe", type: i6.UpperCasePipe, name: "uppercase" }, { kind: "pipe", type: i6.DecimalPipe, name: "number" }, { kind: "pipe", type: i8.TranslocoPipe, name: "transloco" }, { kind: "pipe", type: i6$3.DateFormatPipe, name: "dateFormat" }] }); }
|
|
1899
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: UserSubscriptionListComponent, deps: [{ token: i1$2.SubscriptionService }, { token: i2$1.AdminService }, { token: i1$1.NgbModal }, { token: i4$1.Store }, { token: i5$1.Clipboard }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }, { token: i5.ConfirmDialogService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1900
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: UserSubscriptionListComponent, isStandalone: false, selector: "pw-user-subscriptions-list", viewQueries: [{ propertyName: "menu", first: true, predicate: ["menuItems"], descendants: true }, { propertyName: "changeSubscriptionRef", first: true, predicate: AddSubscriptionComponent, descendants: true }, { propertyName: "passwordValidationModalForAccountDelete", first: true, predicate: ["passwordValidationModalForAccountDelete"], descendants: true }, { propertyName: "passwordValidationModalForKey", first: true, predicate: ["passwordValidationModalForKey"], descendants: true }, { propertyName: "passwordValidationForUnsubscribe", first: true, predicate: ["passwordValidationForUnsubscribe"], descendants: true }, { propertyName: "cancelSubscriptionModal", first: true, predicate: ["cancelSubscriptionModal"], descendants: true }], usesInheritance: true, ngImport: i0, template: "@if (!showTos) {\n <!-- Subscriptions Tab Content -->\n @if (!editing && !isAddNew) {\n <div class=\"row\">\n <div class=\"col-12\">\n <h2>Your Subscriptions</h2>\n <p>You'll find in this section the summary of your subscriptions.</p>\n </div>\n </div>\n }\n <!-- Subscribed Product Cards -->\n @if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\"\n >\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n @if (\n !editing && !isAddNew && !isUpdatePayment && isLoaded && subscribedSubscriptions.length\n ) {\n <div class=\"row\"\n >\n @for (subscription of subscribedSubscriptions; track trackBySubscription($index, subscription)) {\n <div class=\"col-12 col-md-6 my-3\"\n >\n <div class=\"subscription-details mb-4\">\n <div class=\"subscription-summary d-flex flex-wrap justify-content-between align-items-start gap-2 mb-3\">\n <div class=\"subscription-summary__info\">\n <div>\n <strong>Organisation:</strong>\n {{ subscription.organisation ? subscription.organisation : subscription.contact_name }}\n </div>\n <div>\n <strong>{{ 'User.Subscriptions.TotalPriceExclTax' | transloco }}:</strong>\n @if (subscription.calculated_price) {\n {{ subscription.products[0]?.currency }} {{ subscription.calculated_price / 100 | number:'1.2-2' }}\n {{ subscription.products[0].trial_subscription ? '(After Trial)' : '' }}\n } @else {\n Free\n }\n </div>\n <div>\n <strong>{{ 'User.Subscriptions.SeatsInUse' | transloco }}:</strong>\n {{ subscription.units_in_use || 1 }} / {{ subscription.purchased_units }}\n @if (subscription.purchased_units) {\n <span class=\"seats-usage\"\n [style.--seats-pct]=\"(subscription.units_in_use || 1) / subscription.purchased_units\"></span>\n }\n </div>\n </div>\n <!-- Subscription-level actions (a subscription may hold multiple products) -->\n @if (\n (subscription.is_subscription_owner || subscription.is_subscription_admin) &&\n subscription.products?.length &&\n !subscription.products[0].deleted &&\n !subscription.products[0].dependency_products?.length\n ) {\n <div class=\"subscription-summary__actions d-flex flex-wrap align-items-center gap-2\">\n <a class=\"btn btn-outline-primary btn-sm\"\n aria-label=\"Navigate to Target\"\n [routerLink]=\"['../subscriptions', subscription.id]\">\n {{ 'Button.Edit' | transloco }}\n </a>\n @if (!subscription.products[0].expired && !subscription.products[0].trial_subscription) {\n <button [routerLink]=\"['../subscriptions', subscription.id, 'credential']\"\n class=\"btn btn-outline-secondary btn-sm\">\n {{ 'User.Subscriptions.Credentials' | transloco }}\n </button>\n }\n @if (!isUpdatePayment && subscription.stripe_customer_id) {\n <a class=\"btn btn-sm btn-outline-primary\"\n [routerLink]=\"['../subscriptions', subscription.id, 'product', subscription.products[0].id, 'update-payment']\">\n <i class=\"fa fa-edit me-1\" aria-hidden=\"true\"></i>{{ 'User.Subscriptions.UpdateCardDetails' | transloco }}</a>\n }\n <button class=\"btn btn-sm btn-outline-primary\"\n [routerLink]=\"'/account/subscriptions/add-new'\"\n [queryParams]=\"{ subscription_id: subscription.id }\"\n [pTooltip]=\"'User.Subscriptions.Tooltip.ManageAllProducts' | transloco\"\n tooltipPosition=\"bottom\">\n <i class=\"fa fa-plus me-1\"></i>{{ 'User.Subscriptions.SeeAllProducts' | transloco }}\n </button>\n </div>\n }\n </div>\n <!-- Products list -->\n @for (\n product of subscription.products; track trackByProduct($index,\n product); let first = $first) {\n <div class=\"mb-3\">\n <div class=\"card subscription-products-cards\">\n <div class=\"card-content\">\n <div class=\"card-header\">\n <div>\n <h4 class=\"mb-3 text-bold-500 primary\">{{ product?.name }}</h4>\n <!-- Frequency -->\n <div>\n <div>\n <strong class=\"d-inline-block w-50\">{{\n 'User.Subscriptions.Frequency' | transloco\n }}:</strong>\n {{ product?.billing_frequency | uppercase }}\n </div>\n </div>\n <!-- Expiration -->\n <div [ngClass]=\"{ 'text-danger': product.expired }\">\n <strong class=\"d-inline-block w-50\">{{\n product.expired ? 'Expired' : 'Expiry Date'\n }}:</strong>\n {{ product.expires_at | dateFormat }}\n </div>\n <!-- Estimated Price -->\n <div [ngClass]=\"{ 'text-danger': product.expired }\">\n <strong class=\"d-inline-block w-50\">{{\n 'User.Subscriptions.PriceExclTax' | transloco\n }}:</strong>\n {{ product.currency }}\n {{ (product.calculated_price / 100) | number:'1.2-2' }}\n </div>\n <!-- Product API Key (Alpha-only) -->\n <ng-container *rbacAllow=\"'Pages.Alpha'\">\n @if (\n (product.stripe_plan_id && product.max_hits > 0) ||\n product.max_hits_trial > 0\n ) {\n <div class=\"d-flex align-items-center\">\n <strong class=\"d-inline-block w-50\">\n {{ 'User.Subscriptions.ApiKey' | transloco }}:\n <i class=\"far fa-info-circle ms-1 text-muted\"\n aria-hidden=\"true\"\n [ngbTooltip]=\"'User.Subscriptions.ApiKey.NotUsedHint' | transloco\"></i>\n </strong>\n <code class=\"text-truncate me-2\">{{ product.masked }}</code>\n <span class=\"ms-auto d-flex align-items-center flex-shrink-0\">\n <!-- Show Access Key -->\n <button class=\"btn\"\n ngbTooltip=\"Show Access Key\"\n (click)=\"showKey(product)\">\n <i class=\"fas fa-eye\" aria-hidden=\"true\"></i>\n </button>\n <!-- Copy To Clipboard -->\n <button class=\"btn\"\n ngbTooltip=\"Copy Key\">\n <i class=\"fal fa-copy\"\n aria-hidden=\"true\"\n (click)=\"onClipboardCopy(product.api_access_token)\"\n (keydown.enter)=\"onClipboardCopy(product.api_access_token)\"></i>\n </button>\n <!-- Update API Key -->\n @if (!product.expired && !product.deleted) {\n <button class=\"btn\"\n ngbTooltip=\"Change Key\"\n (click)=\"updateApiKey(subscription, product)\">\n <i class=\"fal fa-sync-alt\" aria-hidden=\"true\"></i>\n </button>\n }\n </span>\n </div>\n }\n </ng-container>\n </div>\n </div>\n <div class=\"card-footer px-3 d-flex flex-column gap-2\">\n <div class=\"footer-status d-flex flex-wrap align-items-center gap-2\">\n @if (product.deleted && !product.expired) {\n <span class=\"footer-note\">\n <i class=\"fa fa-info-circle me-2\" aria-hidden=\"true\"></i>{{ 'User.Subscriptions.OutdatedMessage' | transloco }}\n </span>\n }\n @if (product.deleted) {\n <span class=\"badge bg-danger\">Deleted</span>\n }\n @if (\n product.trial_subscription &&\n product.calculated_price\n ) {\n <span class=\"badge bg-warning\">Trial</span>\n }\n @if (product?.pause_collection && objectKeys(product?.pause_collection)?.length) {\n <span class=\"badge bg-grey\"\n [pTooltip]=\"'User.Subscriptions.Tooltip.PausedCollection'|transloco\"\n tooltipPosition=\"top\">\n Paused collection\n </span>\n }\n @if (!product.calculated_price) {\n <span class=\"badge bg-success\">Free</span>\n }\n @if (!product?.deleted && !subscription.is_subscription_owner) {\n <span class=\"footer-note\">\n <i class=\"fa fa-info-circle me-2\" aria-hidden=\"true\"></i>Invited to use this product\n @if (subscription.is_subscription_admin) {\n <span class=\"badge bg-role-admin ms-1\">as an admin</span>\n }\n </span>\n }\n </div>\n @if (\n subscription.is_subscription_owner ||\n subscription.is_subscription_admin\n ) {\n <div class=\"footer-actions d-flex flex-wrap align-items-center justify-content-end gap-2\">\n <!-- Unsubscribe -->\n @if (\n subscription?.stripe_customer_id &&\n !product?.deleted &&\n !product?.trial_subscription\n ) {\n <button class=\"btn btn-outline-danger btn-sm\"\n (click)=\"attemptUnsubscribe(subscription, product.id)\">\n {{ 'User.Subscriptions.Unsubscribe' | transloco }}\n </button>\n }\n @if (product.stripe_plan_id && product.active) {\n <!-- Upgrade (single primary CTA) -->\n @if (product.trial_subscription && !product.deleted) {\n <button class=\"btn btn-primary btn-sm\"\n (click)=\"attemptUpgrade(subscription, product)\">\n {{ 'Button.Upgrade' | transloco }}\n </button>\n }\n <!-- Subscribe -->\n @if (subscription.expired && product.stripe_plan_id) {\n <button class=\"btn btn-primary btn-sm\"\n [routerLink]=\"'/account/subscriptions/add-new'\">\n {{ 'User.Subscriptions.Subscribe' | transloco }}\n </button>\n }\n }\n <!-- Privacy & Terms of Service (quiet link, not a button) -->\n @if (product?.product_privacy_service_id) {\n <button class=\"btn btn-link btn-sm p-0 footer-tos-link\"\n (click)=\"showPrivacyAndTos(product)\">\n {{\n 'User.Subscriptions.PrivacyAndTermsOfService'\n | transloco\n }}\n </button>\n }\n </div>\n }\n </div>\n </div>\n </div>\n @if (subscription.products.length === 0) {\n <div>\n <div class=\"card\">\n <div class=\"card-content\">\n <div class=\"card-header\">\n <p class=\"text-center\">\n No product available for this subscription\n </p>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n }\n @if (!editing && !isAddNew && !isUpdatePayment) {\n <div class=\"col-12\"\n >\n @if (subscribedSubscriptions.length === 0) {\n <pw-no-data [withImage]=\"true\" message=\"You don't have any subscription.\"\n >\n </pw-no-data>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n <!-- Danger zone (demoted account deletion) -->\n @if (!editing && !isAddNew && !isUpdatePayment && isLoaded) {\n <div class=\"row\">\n <div class=\"col-12\">\n <div class=\"danger-zone mt-4\">\n <button type=\"button\"\n class=\"btn btn-sm btn-outline-danger danger-zone__action\"\n (click)=\"showModalForAccountDeletion()\"\n [pTooltip]=\"'User.Account.Tooltip.DeleteAccount' | transloco\"\n tooltipPosition=\"top\">\n {{ 'User.Account.DeleteAccount' | transloco }}\n </button>\n </div>\n </div>\n </div>\n }\n <!--\n Add New Subscription\n -->\n <!-- <ng-template [ngIf]=\"isAddNew && !isUpdatePayment\">\n <pw-subscription-details></pw-subscription-details>\n</ng-template> -->\n<!--\nValidate Password For Account Delete\n-->\n<pw-password-validation #passwordValidationModalForAccountDelete\n [destructive]=\"true\"\n (successEvent)=\"deleteUser($event)\">\n</pw-password-validation>\n<!--\nValidate Password For Display Key\n-->\n<pw-password-validation #passwordValidationModalForKey\n (successEvent)=\"displayApiKey()\">\n</pw-password-validation>\n<!--\nValidate Password For Unsubscribe\n-->\n<pw-password-validation #passwordValidationForUnsubscribe\n [destructive]=\"true\"\n (successEvent)=\"onValidatePassword($event)\">\n</pw-password-validation>\n<!--\nCancel Subscription Modal\n-->\n<ng-template #cancelSubscriptionModal let-modal>\n <div class=\"modal-header\">\n <h4 class=\"modal-title\">{{ 'User.Subscriptions.CancelSubscription.Title' | transloco }}</h4>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss(); reasonToCancel = '';\">\n </button>\n </div>\n <div class=\"modal-body\">\n <p>{{ 'User.Subscriptions.CancelSubscription.Message' | transloco }}</p>\n <div class=\"mb-3\">\n <label for=\"reasonToCancel\" class=\"form-label\">\n {{ 'User.Subscriptions.CancelSubscription.ReasonLabel' | transloco }} <span class=\"text-danger\">*</span>\n </label>\n <textarea\n id=\"reasonToCancel\"\n class=\"form-control\"\n rows=\"4\"\n [(ngModel)]=\"reasonToCancel\"\n [ngClass]=\"{'is-invalid': reasonToCancel && reasonToCancel.trim() === ''}\"\n placeholder=\"{{ 'User.Subscriptions.CancelSubscription.ReasonPlaceholder' | transloco }}\"></textarea>\n @if (reasonToCancel && reasonToCancel.trim() === '') {\n <div class=\"invalid-feedback\">\n {{ 'User.Subscriptions.Validation.ReasonRequired' | transloco }}\n </div>\n }\n </div>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\"\n class=\"btn btn-outline-default\"\n (click)=\"modal.dismiss(); reasonToCancel = '';\">\n {{ 'User.Subscriptions.CancelSubscription.KeepItForNow' | transloco }}\n </button>\n <button type=\"button\"\n class=\"btn btn-danger\"\n [disabled]=\"!reasonToCancel || reasonToCancel.trim() === ''\"\n (click)=\"onConfirmCancel(); modal.close()\">\n {{ 'User.Subscriptions.CancelSubscription.ConfirmButton' | transloco }}\n </button>\n </div>\n</ng-template>\n}\n\n@if (showTos) {\n <pw-privacy-and-tos [productId]=\"productId\"></pw-privacy-and-tos>\n}\n\n<router-outlet></router-outlet>\n", styles: [".btn-list{bottom:24px;left:0;padding:0 38px;right:0}.shadow-md{padding-bottom:70px!important}.bg-dark{border:0}.subscription-details{background:#fff;border:1px solid #e2e5ea;border-radius:12px;padding:16px 16px 6px;font-size:14px;font-variant-numeric:tabular-nums}.subscription-summary{border-bottom:1px solid #eef0f3;padding-bottom:12px}.seats-usage{display:inline-block;width:120px;height:6px;margin-left:8px;border-radius:999px;vertical-align:middle;overflow:hidden;background:linear-gradient(#5a6473,#5a6473) left/calc(var(--seats-pct, 0) * 100%) 100% no-repeat,#e2e5ea}.subscription-products-cards{padding-bottom:0!important}.subscription-products-cards .card-footer{position:static!important}.subscription-products-cards.card{background:#f7f8fa;border:1px solid #eef0f3;border-radius:8px;box-shadow:none!important;font-size:14px}.card-footer{background:transparent;border-top:1px solid #eef0f3}.card-footer .footer-note{color:#5a6473;font-size:.875rem}.card-footer .footer-tos-link{color:#5a6473;font-weight:500;text-decoration:underline}.card-footer .footer-tos-link:hover{color:var(--first)}.badge{font-weight:600;border-radius:4px}.badge.bg-success{background-color:#e6f4ec!important;color:#0f6b3a!important}.badge.bg-danger{background-color:#fbeae8!important;color:#c0392b!important}.badge.bg-warning{background-color:#fbf1e3!important;color:#8a5a00!important}.badge.bg-grey,.badge.bg-role-admin{background-color:#eef0f3!important;color:#5a6473!important}code{color:var(--text);min-width:0}.danger-zone{border-top:1px solid #e2e5ea;padding-top:16px;text-align:right}\n"], dependencies: [{ kind: "directive", type: i3.RbacAllowDirective, selector: "[rbacAllow]", inputs: ["rbacAllow"] }, { kind: "directive", type: i8.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "component", type: i5.PasswordValidationComponent, selector: "pw-password-validation", inputs: ["confirmMessage", "destructive"], outputs: ["successEvent"] }, { kind: "directive", type: i1$1.NgbTooltip, selector: "[ngbTooltip]", inputs: ["animation", "autoClose", "placement", "popperOptions", "triggers", "positionTarget", "container", "disableTooltip", "tooltipClass", "tooltipContext", "openDelay", "closeDelay", "ngbTooltip"], outputs: ["shown", "hidden"], exportAs: ["ngbTooltip"] }, { kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i5.PrivacyAndTosComponent, selector: "pw-privacy-and-tos", inputs: ["productId"] }, { kind: "component", type: i5.NoDataComponent, selector: "pw-no-data", inputs: ["message", "description", "withImage"] }, { kind: "directive", type: i11.Tooltip, selector: "[pTooltip]", inputs: ["tooltipPosition", "tooltipEvent", "positionStyle", "tooltipStyleClass", "tooltipZIndex", "escape", "showDelay", "hideDelay", "life", "positionTop", "positionLeft", "autoHide", "fitContent", "hideOnEscape", "pTooltip", "tooltipDisabled", "tooltipOptions", "appendTo", "ptTooltip", "pTooltipPT", "pTooltipUnstyled"] }, { kind: "pipe", type: i8.UpperCasePipe, name: "uppercase" }, { kind: "pipe", type: i8.DecimalPipe, name: "number" }, { kind: "pipe", type: i8$2.TranslocoPipe, name: "transloco" }, { kind: "pipe", type: i6.DateFormatPipe, name: "dateFormat" }] }); }
|
|
1810
1901
|
}
|
|
1811
1902
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: UserSubscriptionListComponent, decorators: [{
|
|
1812
1903
|
type: Component,
|
|
1813
|
-
args: [{ selector: 'pw-user-subscriptions-list', standalone: false, template: "@if (!showTos) {\n <!-- Subscriptions Tab Content -->\n @if (!editing && !isAddNew) {\n <div class=\"row\">\n <div class=\"col-12\">\n <h2>Your Subscriptions</h2>\n <p>You'll find in this section the summary of your subscriptions.</p>\n </div>\n </div>\n }\n <!-- Subscribed Product Cards -->\n @if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\"\n >\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n @if (\n !editing && !isAddNew && !isUpdatePayment && isLoaded && subscribedSubscriptions.length\n ) {\n <div class=\"row\"\n >\n @for (subscription of subscribedSubscriptions; track trackBySubscription($index, subscription)) {\n <div class=\"col-12 col-md-6 my-3\"\n >\n <div class=\"subscription-details mb-4\">\n <div class=\"subscription-summary d-flex flex-wrap justify-content-between align-items-start gap-2 mb-3\">\n <div class=\"subscription-summary__info\">\n <div>\n <strong>Organisation:</strong>\n {{ subscription.organisation ? subscription.organisation : subscription.contact_name }}\n </div>\n <div>\n <strong>{{ 'User.Subscriptions.TotalPriceExclTax' | transloco }}:</strong>\n @if (subscription.calculated_price) {\n {{ subscription.products[0]?.currency }} {{ subscription.calculated_price / 100 | number:'1.2-2' }}\n {{ subscription.products[0].trial_subscription ? '(After Trial)' : '' }}\n } @else {\n Free\n }\n </div>\n <div>\n <strong>{{ 'User.Subscriptions.SeatsInUse' | transloco }}:</strong>\n {{ subscription.units_in_use || 1 }} / {{ subscription.purchased_units }}\n @if (subscription.purchased_units) {\n <span class=\"seats-usage\"\n [style.--seats-pct]=\"(subscription.units_in_use || 1) / subscription.purchased_units\"></span>\n }\n </div>\n </div>\n <!-- Subscription-level actions (a subscription may hold multiple products) -->\n @if (\n (subscription.is_subscription_owner || subscription.is_subscription_admin) &&\n subscription.products?.length &&\n !subscription.products[0].deleted &&\n !subscription.products[0].dependency_products?.length\n ) {\n <div class=\"subscription-summary__actions d-flex flex-wrap align-items-center gap-2\">\n <a class=\"btn btn-outline-primary btn-sm\"\n aria-label=\"Navigate to Target\"\n [routerLink]=\"['../subscriptions', subscription.id]\">\n {{ 'Button.Edit' | transloco }}\n </a>\n @if (!subscription.products[0].expired && !subscription.products[0].trial_subscription) {\n <button [routerLink]=\"['../subscriptions', subscription.id, 'credential']\"\n class=\"btn btn-outline-secondary btn-sm\">\n {{ 'User.Subscriptions.Credentials' | transloco }}\n </button>\n }\n @if (!isUpdatePayment && subscription.stripe_customer_id) {\n <a class=\"btn btn-sm btn-outline-primary\"\n [routerLink]=\"['../subscriptions', subscription.id, 'product', subscription.products[0].id, 'update-payment']\">\n <i class=\"fa fa-edit me-1\" aria-hidden=\"true\"></i>{{ 'User.Subscriptions.UpdateCardDetails' | transloco }}</a>\n }\n <button class=\"btn btn-sm btn-outline-primary\"\n [routerLink]=\"'/account/subscriptions/add-new'\"\n [queryParams]=\"{ subscription_id: subscription.id }\"\n [pTooltip]=\"'User.Subscriptions.Tooltip.ManageAllProducts' | transloco\"\n tooltipPosition=\"bottom\">\n <i class=\"fa fa-plus me-1\"></i>{{ 'User.Subscriptions.SeeAllProducts' | transloco }}\n </button>\n </div>\n }\n </div>\n <!-- Products list -->\n @for (\n product of subscription.products; track trackByProduct($index,\n product); let first = $first) {\n <div class=\"mb-3\">\n <div class=\"card subscription-products-cards\">\n <div class=\"card-content\">\n <div class=\"card-header\">\n <div>\n <h4 class=\"mb-3 text-bold-500 primary\">{{ product?.name }}</h4>\n <!-- Frequency -->\n <div>\n <div>\n <strong class=\"d-inline-block w-50\">{{\n 'User.Subscriptions.Frequency' | transloco\n }}:</strong>\n {{ product?.billing_frequency | uppercase }}\n </div>\n </div>\n <!-- Expiration -->\n <div [ngClass]=\"{ 'text-danger': product.expired }\">\n <strong class=\"d-inline-block w-50\">{{\n product.expired ? 'Expired' : 'Expiry Date'\n }}:</strong>\n {{ product.expires_at | dateFormat }}\n </div>\n <!-- Estimated Price -->\n <div [ngClass]=\"{ 'text-danger': product.expired }\">\n <strong class=\"d-inline-block w-50\">{{\n 'User.Subscriptions.PriceExclTax' | transloco\n }}:</strong>\n {{ product.currency }}\n {{ (product.calculated_price / 100) | number:'1.2-2' }}\n </div>\n <!-- Product API Key (Alpha-only) -->\n <ng-container *rbacAllow=\"'Pages.Alpha'\">\n @if (\n (product.stripe_plan_id && product.max_hits > 0) ||\n product.max_hits_trial > 0\n ) {\n <div class=\"d-flex align-items-center\">\n <strong class=\"d-inline-block w-50\">\n {{ 'User.Subscriptions.ApiKey' | transloco }}:\n <i class=\"far fa-info-circle ms-1 text-muted\"\n aria-hidden=\"true\"\n [ngbTooltip]=\"'User.Subscriptions.ApiKey.NotUsedHint' | transloco\"></i>\n </strong>\n <code class=\"text-truncate me-2\">{{ product.masked }}</code>\n <span class=\"ms-auto d-flex align-items-center flex-shrink-0\">\n <!-- Show Access Key -->\n <button class=\"btn\"\n ngbTooltip=\"Show Access Key\"\n (click)=\"showKey(product)\">\n <i class=\"fas fa-eye\" aria-hidden=\"true\"></i>\n </button>\n <!-- Copy To Clipboard -->\n <button class=\"btn\"\n ngbTooltip=\"Copy Key\">\n <i class=\"fal fa-copy\"\n aria-hidden=\"true\"\n (click)=\"onClipboardCopy(product.api_access_token)\"\n (keydown.enter)=\"onClipboardCopy(product.api_access_token)\"></i>\n </button>\n <!-- Update API Key -->\n @if (!product.expired && !product.deleted) {\n <button class=\"btn\"\n ngbTooltip=\"Change Key\"\n (click)=\"updateApiKey(subscription, product)\">\n <i class=\"fal fa-sync-alt\" aria-hidden=\"true\"></i>\n </button>\n }\n </span>\n </div>\n }\n </ng-container>\n </div>\n </div>\n <div class=\"card-footer px-3 d-flex flex-column gap-2\">\n <div class=\"footer-status d-flex flex-wrap align-items-center gap-2\">\n @if (product.deleted && !product.expired) {\n <span class=\"footer-note\">\n <i class=\"fa fa-info-circle me-2\" aria-hidden=\"true\"></i>{{ 'User.Subscriptions.OutdatedMessage' | transloco }}\n </span>\n }\n @if (product.deleted) {\n <span class=\"badge bg-danger\">Deleted</span>\n }\n @if (\n product.trial_subscription &&\n product.calculated_price\n ) {\n <span class=\"badge bg-warning\">Trial</span>\n }\n @if (product?.pause_collection && objectKeys(product?.pause_collection)?.length) {\n <span class=\"badge bg-grey\"\n [pTooltip]=\"'User.Subscriptions.Tooltip.PausedCollection'|transloco\"\n tooltipPosition=\"top\">\n Paused collection\n </span>\n }\n @if (!product.calculated_price) {\n <span class=\"badge bg-success\">Free</span>\n }\n @if (!product?.deleted && !subscription.is_subscription_owner) {\n <span class=\"footer-note\">\n <i class=\"fa fa-info-circle me-2\" aria-hidden=\"true\"></i>Invited to use this product\n @if (subscription.is_subscription_admin) {\n <span class=\"badge bg-role-admin ms-1\">as an admin</span>\n }\n </span>\n }\n </div>\n @if (\n subscription.is_subscription_owner ||\n subscription.is_subscription_admin\n ) {\n <div class=\"footer-actions d-flex flex-wrap align-items-center justify-content-end gap-2\">\n <!-- Unsubscribe -->\n @if (\n subscription?.stripe_customer_id &&\n !product?.deleted &&\n !product?.trial_subscription\n ) {\n <button class=\"btn btn-outline-danger btn-sm\"\n (click)=\"attemptUnsubscribe(subscription, product.id)\">\n {{ 'User.Subscriptions.Unsubscribe' | transloco }}\n </button>\n }\n @if (product.stripe_plan_id && product.active) {\n <!-- Upgrade (single primary CTA) -->\n @if (product.trial_subscription && !product.deleted) {\n <button class=\"btn btn-primary btn-sm\"\n (click)=\"attemptUpgrade(subscription, product)\">\n {{ 'Button.Upgrade' | transloco }}\n </button>\n }\n <!-- Subscribe -->\n @if (subscription.expired && product.stripe_plan_id) {\n <button class=\"btn btn-primary btn-sm\"\n [routerLink]=\"'/account/subscriptions/add-new'\">\n {{ 'User.Subscriptions.Subscribe' | transloco }}\n </button>\n }\n }\n <!-- Privacy & Terms of Service (quiet link, not a button) -->\n @if (product?.product_privacy_service_id) {\n <button class=\"btn btn-link btn-sm p-0 footer-tos-link\"\n (click)=\"showPrivacyAndTos(product)\">\n {{\n 'User.Subscriptions.PrivacyAndTermsOfService'\n | transloco\n }}\n </button>\n }\n </div>\n }\n </div>\n </div>\n </div>\n @if (subscription.products.length === 0) {\n <div>\n <div class=\"card\">\n <div class=\"card-content\">\n <div class=\"card-header\">\n <p class=\"text-center\">\n No product available for this subscription\n </p>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n }\n @if (!editing && !isAddNew && !isUpdatePayment) {\n <div class=\"col-12\"\n >\n @if (subscribedSubscriptions.length === 0) {\n <pw-no-data [withImage]=\"true\" message=\"You don't have any subscription.\"\n >\n </pw-no-data>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n <!-- Danger zone (demoted account deletion) -->\n @if (!editing && !isAddNew && !isUpdatePayment && isLoaded) {\n <div class=\"row\">\n <div class=\"col-12\">\n <div class=\"danger-zone mt-4\">\n <button type=\"button\"\n class=\"btn btn-sm btn-outline-danger danger-zone__action\"\n (click)=\"showModalForAccountDeletion()\"\n [pTooltip]=\"'User.Account.Tooltip.DeleteAccount' | transloco\"\n tooltipPosition=\"top\">\n {{ 'User.Account.DeleteAccount' | transloco }}\n </button>\n </div>\n </div>\n </div>\n }\n <!--\n Add New Subscription\n -->\n <!-- <ng-template [ngIf]=\"isAddNew && !isUpdatePayment\">\n <pw-subscription-details></pw-subscription-details>\n</ng-template> -->\n<!--\nValidate Password For Account Delete\n-->\n<pw-password-validation #passwordValidationModalForAccountDelete\n (successEvent)=\"deleteUser($event)\">\n <div class=\"row\">\n <div class=\"col-12\">\n <p>{{ 'User.Account.Message.ActionCanNotUndone' | transloco }}</p>\n <p>{{ 'User.Account.Message.ConfirmPassword' | transloco }}</p>\n </div>\n </div>\n</pw-password-validation>\n<!--\nValidate Password For Display Key\n-->\n<pw-password-validation #passwordValidationModalForKey\n (successEvent)=\"displayApiKey()\">\n</pw-password-validation>\n<!--\nValidate Password For Unsubscribe\n-->\n<pw-password-validation #passwordValidationForUnsubscribe\n (successEvent)=\"onValidatePassword($event)\">\n <div class=\"row\">\n <div class=\"col-12\">\n <p>{{ 'User.Account.Message.ActionCanNotUndone' | transloco }}</p>\n <p>{{ 'User.Account.Message.ConfirmPassword' | transloco }}</p>\n </div>\n </div>\n</pw-password-validation>\n<!--\nCancel Subscription Modal\n-->\n<ng-template #cancelSubscriptionModal let-modal>\n <div class=\"modal-header\">\n <h4 class=\"modal-title\">{{ 'User.Subscriptions.CancelSubscription.Title' | transloco }}</h4>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss(); reasonToCancel = '';\">\n </button>\n </div>\n <div class=\"modal-body\">\n <p>{{ 'User.Subscriptions.CancelSubscription.Message' | transloco }}</p>\n <div class=\"mb-3\">\n <label for=\"reasonToCancel\" class=\"form-label\">\n {{ 'User.Subscriptions.CancelSubscription.ReasonLabel' | transloco }} <span class=\"text-danger\">*</span>\n </label>\n <textarea\n id=\"reasonToCancel\"\n class=\"form-control\"\n rows=\"4\"\n [(ngModel)]=\"reasonToCancel\"\n [ngClass]=\"{'is-invalid': reasonToCancel && reasonToCancel.trim() === ''}\"\n placeholder=\"{{ 'User.Subscriptions.CancelSubscription.ReasonPlaceholder' | transloco }}\"></textarea>\n @if (reasonToCancel && reasonToCancel.trim() === '') {\n <div class=\"invalid-feedback\">\n {{ 'User.Subscriptions.Validation.ReasonRequired' | transloco }}\n </div>\n }\n </div>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\"\n class=\"btn btn-outline-default\"\n (click)=\"modal.dismiss(); reasonToCancel = '';\">\n {{ 'User.Subscriptions.CancelSubscription.KeepItForNow' | transloco }}\n </button>\n <button type=\"button\"\n class=\"btn btn-danger\"\n [disabled]=\"!reasonToCancel || reasonToCancel.trim() === ''\"\n (click)=\"onConfirmCancel(); modal.close()\">\n {{ 'User.Subscriptions.CancelSubscription.ConfirmButton' | transloco }}\n </button>\n </div>\n</ng-template>\n}\n\n@if (showTos) {\n <pw-privacy-and-tos [productId]=\"productId\"></pw-privacy-and-tos>\n}\n\n<router-outlet></router-outlet>\n", styles: [".btn-list{bottom:24px;left:0;padding:0 38px;right:0}.shadow-md{padding-bottom:70px!important}.bg-dark{border:0}.subscription-details{background:#fff;border:1px solid #e2e5ea;border-radius:12px;padding:16px 16px 6px;font-size:14px;font-variant-numeric:tabular-nums}.subscription-summary{border-bottom:1px solid #eef0f3;padding-bottom:12px}.seats-usage{display:inline-block;width:120px;height:6px;margin-left:8px;border-radius:999px;vertical-align:middle;overflow:hidden;background:linear-gradient(#5a6473,#5a6473) left/calc(var(--seats-pct, 0) * 100%) 100% no-repeat,#e2e5ea}.subscription-products-cards{padding-bottom:0!important}.subscription-products-cards .card-footer{position:static!important}.subscription-products-cards.card{background:#f7f8fa;border:1px solid #eef0f3;border-radius:8px;box-shadow:none!important;font-size:14px}.card-footer{background:transparent;border-top:1px solid #eef0f3}.card-footer .footer-note{color:#5a6473;font-size:.875rem}.card-footer .footer-tos-link{color:#5a6473;font-weight:500;text-decoration:underline}.card-footer .footer-tos-link:hover{color:var(--first)}.badge{font-weight:600;border-radius:4px}.badge.bg-success{background-color:#e6f4ec!important;color:#0f6b3a!important}.badge.bg-danger{background-color:#fbeae8!important;color:#c0392b!important}.badge.bg-warning{background-color:#fbf1e3!important;color:#8a5a00!important}.badge.bg-grey,.badge.bg-role-admin{background-color:#eef0f3!important;color:#5a6473!important}code{color:var(--text);min-width:0}.danger-zone{border-top:1px solid #e2e5ea;padding-top:16px;text-align:right}\n"] }]
|
|
1814
|
-
}], ctorParameters: () => [{ type: i1$2.SubscriptionService }, { type: i2$1.AdminService }, { type: i1$1.NgbModal }, { type: i4$
|
|
1904
|
+
args: [{ selector: 'pw-user-subscriptions-list', standalone: false, template: "@if (!showTos) {\n <!-- Subscriptions Tab Content -->\n @if (!editing && !isAddNew) {\n <div class=\"row\">\n <div class=\"col-12\">\n <h2>Your Subscriptions</h2>\n <p>You'll find in this section the summary of your subscriptions.</p>\n </div>\n </div>\n }\n <!-- Subscribed Product Cards -->\n @if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\"\n >\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n @if (\n !editing && !isAddNew && !isUpdatePayment && isLoaded && subscribedSubscriptions.length\n ) {\n <div class=\"row\"\n >\n @for (subscription of subscribedSubscriptions; track trackBySubscription($index, subscription)) {\n <div class=\"col-12 col-md-6 my-3\"\n >\n <div class=\"subscription-details mb-4\">\n <div class=\"subscription-summary d-flex flex-wrap justify-content-between align-items-start gap-2 mb-3\">\n <div class=\"subscription-summary__info\">\n <div>\n <strong>Organisation:</strong>\n {{ subscription.organisation ? subscription.organisation : subscription.contact_name }}\n </div>\n <div>\n <strong>{{ 'User.Subscriptions.TotalPriceExclTax' | transloco }}:</strong>\n @if (subscription.calculated_price) {\n {{ subscription.products[0]?.currency }} {{ subscription.calculated_price / 100 | number:'1.2-2' }}\n {{ subscription.products[0].trial_subscription ? '(After Trial)' : '' }}\n } @else {\n Free\n }\n </div>\n <div>\n <strong>{{ 'User.Subscriptions.SeatsInUse' | transloco }}:</strong>\n {{ subscription.units_in_use || 1 }} / {{ subscription.purchased_units }}\n @if (subscription.purchased_units) {\n <span class=\"seats-usage\"\n [style.--seats-pct]=\"(subscription.units_in_use || 1) / subscription.purchased_units\"></span>\n }\n </div>\n </div>\n <!-- Subscription-level actions (a subscription may hold multiple products) -->\n @if (\n (subscription.is_subscription_owner || subscription.is_subscription_admin) &&\n subscription.products?.length &&\n !subscription.products[0].deleted &&\n !subscription.products[0].dependency_products?.length\n ) {\n <div class=\"subscription-summary__actions d-flex flex-wrap align-items-center gap-2\">\n <a class=\"btn btn-outline-primary btn-sm\"\n aria-label=\"Navigate to Target\"\n [routerLink]=\"['../subscriptions', subscription.id]\">\n {{ 'Button.Edit' | transloco }}\n </a>\n @if (!subscription.products[0].expired && !subscription.products[0].trial_subscription) {\n <button [routerLink]=\"['../subscriptions', subscription.id, 'credential']\"\n class=\"btn btn-outline-secondary btn-sm\">\n {{ 'User.Subscriptions.Credentials' | transloco }}\n </button>\n }\n @if (!isUpdatePayment && subscription.stripe_customer_id) {\n <a class=\"btn btn-sm btn-outline-primary\"\n [routerLink]=\"['../subscriptions', subscription.id, 'product', subscription.products[0].id, 'update-payment']\">\n <i class=\"fa fa-edit me-1\" aria-hidden=\"true\"></i>{{ 'User.Subscriptions.UpdateCardDetails' | transloco }}</a>\n }\n <button class=\"btn btn-sm btn-outline-primary\"\n [routerLink]=\"'/account/subscriptions/add-new'\"\n [queryParams]=\"{ subscription_id: subscription.id }\"\n [pTooltip]=\"'User.Subscriptions.Tooltip.ManageAllProducts' | transloco\"\n tooltipPosition=\"bottom\">\n <i class=\"fa fa-plus me-1\"></i>{{ 'User.Subscriptions.SeeAllProducts' | transloco }}\n </button>\n </div>\n }\n </div>\n <!-- Products list -->\n @for (\n product of subscription.products; track trackByProduct($index,\n product); let first = $first) {\n <div class=\"mb-3\">\n <div class=\"card subscription-products-cards\">\n <div class=\"card-content\">\n <div class=\"card-header\">\n <div>\n <h4 class=\"mb-3 text-bold-500 primary\">{{ product?.name }}</h4>\n <!-- Frequency -->\n <div>\n <div>\n <strong class=\"d-inline-block w-50\">{{\n 'User.Subscriptions.Frequency' | transloco\n }}:</strong>\n {{ product?.billing_frequency | uppercase }}\n </div>\n </div>\n <!-- Expiration -->\n <div [ngClass]=\"{ 'text-danger': product.expired }\">\n <strong class=\"d-inline-block w-50\">{{\n product.expired ? 'Expired' : 'Expiry Date'\n }}:</strong>\n {{ product.expires_at | dateFormat }}\n </div>\n <!-- Estimated Price -->\n <div [ngClass]=\"{ 'text-danger': product.expired }\">\n <strong class=\"d-inline-block w-50\">{{\n 'User.Subscriptions.PriceExclTax' | transloco\n }}:</strong>\n {{ product.currency }}\n {{ (product.calculated_price / 100) | number:'1.2-2' }}\n </div>\n <!-- Product API Key (Alpha-only) -->\n <ng-container *rbacAllow=\"'Pages.Alpha'\">\n @if (\n (product.stripe_plan_id && product.max_hits > 0) ||\n product.max_hits_trial > 0\n ) {\n <div class=\"d-flex align-items-center\">\n <strong class=\"d-inline-block w-50\">\n {{ 'User.Subscriptions.ApiKey' | transloco }}:\n <i class=\"far fa-info-circle ms-1 text-muted\"\n aria-hidden=\"true\"\n [ngbTooltip]=\"'User.Subscriptions.ApiKey.NotUsedHint' | transloco\"></i>\n </strong>\n <code class=\"text-truncate me-2\">{{ product.masked }}</code>\n <span class=\"ms-auto d-flex align-items-center flex-shrink-0\">\n <!-- Show Access Key -->\n <button class=\"btn\"\n ngbTooltip=\"Show Access Key\"\n (click)=\"showKey(product)\">\n <i class=\"fas fa-eye\" aria-hidden=\"true\"></i>\n </button>\n <!-- Copy To Clipboard -->\n <button class=\"btn\"\n ngbTooltip=\"Copy Key\">\n <i class=\"fal fa-copy\"\n aria-hidden=\"true\"\n (click)=\"onClipboardCopy(product.api_access_token)\"\n (keydown.enter)=\"onClipboardCopy(product.api_access_token)\"></i>\n </button>\n <!-- Update API Key -->\n @if (!product.expired && !product.deleted) {\n <button class=\"btn\"\n ngbTooltip=\"Change Key\"\n (click)=\"updateApiKey(subscription, product)\">\n <i class=\"fal fa-sync-alt\" aria-hidden=\"true\"></i>\n </button>\n }\n </span>\n </div>\n }\n </ng-container>\n </div>\n </div>\n <div class=\"card-footer px-3 d-flex flex-column gap-2\">\n <div class=\"footer-status d-flex flex-wrap align-items-center gap-2\">\n @if (product.deleted && !product.expired) {\n <span class=\"footer-note\">\n <i class=\"fa fa-info-circle me-2\" aria-hidden=\"true\"></i>{{ 'User.Subscriptions.OutdatedMessage' | transloco }}\n </span>\n }\n @if (product.deleted) {\n <span class=\"badge bg-danger\">Deleted</span>\n }\n @if (\n product.trial_subscription &&\n product.calculated_price\n ) {\n <span class=\"badge bg-warning\">Trial</span>\n }\n @if (product?.pause_collection && objectKeys(product?.pause_collection)?.length) {\n <span class=\"badge bg-grey\"\n [pTooltip]=\"'User.Subscriptions.Tooltip.PausedCollection'|transloco\"\n tooltipPosition=\"top\">\n Paused collection\n </span>\n }\n @if (!product.calculated_price) {\n <span class=\"badge bg-success\">Free</span>\n }\n @if (!product?.deleted && !subscription.is_subscription_owner) {\n <span class=\"footer-note\">\n <i class=\"fa fa-info-circle me-2\" aria-hidden=\"true\"></i>Invited to use this product\n @if (subscription.is_subscription_admin) {\n <span class=\"badge bg-role-admin ms-1\">as an admin</span>\n }\n </span>\n }\n </div>\n @if (\n subscription.is_subscription_owner ||\n subscription.is_subscription_admin\n ) {\n <div class=\"footer-actions d-flex flex-wrap align-items-center justify-content-end gap-2\">\n <!-- Unsubscribe -->\n @if (\n subscription?.stripe_customer_id &&\n !product?.deleted &&\n !product?.trial_subscription\n ) {\n <button class=\"btn btn-outline-danger btn-sm\"\n (click)=\"attemptUnsubscribe(subscription, product.id)\">\n {{ 'User.Subscriptions.Unsubscribe' | transloco }}\n </button>\n }\n @if (product.stripe_plan_id && product.active) {\n <!-- Upgrade (single primary CTA) -->\n @if (product.trial_subscription && !product.deleted) {\n <button class=\"btn btn-primary btn-sm\"\n (click)=\"attemptUpgrade(subscription, product)\">\n {{ 'Button.Upgrade' | transloco }}\n </button>\n }\n <!-- Subscribe -->\n @if (subscription.expired && product.stripe_plan_id) {\n <button class=\"btn btn-primary btn-sm\"\n [routerLink]=\"'/account/subscriptions/add-new'\">\n {{ 'User.Subscriptions.Subscribe' | transloco }}\n </button>\n }\n }\n <!-- Privacy & Terms of Service (quiet link, not a button) -->\n @if (product?.product_privacy_service_id) {\n <button class=\"btn btn-link btn-sm p-0 footer-tos-link\"\n (click)=\"showPrivacyAndTos(product)\">\n {{\n 'User.Subscriptions.PrivacyAndTermsOfService'\n | transloco\n }}\n </button>\n }\n </div>\n }\n </div>\n </div>\n </div>\n @if (subscription.products.length === 0) {\n <div>\n <div class=\"card\">\n <div class=\"card-content\">\n <div class=\"card-header\">\n <p class=\"text-center\">\n No product available for this subscription\n </p>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n }\n @if (!editing && !isAddNew && !isUpdatePayment) {\n <div class=\"col-12\"\n >\n @if (subscribedSubscriptions.length === 0) {\n <pw-no-data [withImage]=\"true\" message=\"You don't have any subscription.\"\n >\n </pw-no-data>\n }\n </div>\n }\n </div>\n </div>\n }\n </div>\n }\n <!-- Danger zone (demoted account deletion) -->\n @if (!editing && !isAddNew && !isUpdatePayment && isLoaded) {\n <div class=\"row\">\n <div class=\"col-12\">\n <div class=\"danger-zone mt-4\">\n <button type=\"button\"\n class=\"btn btn-sm btn-outline-danger danger-zone__action\"\n (click)=\"showModalForAccountDeletion()\"\n [pTooltip]=\"'User.Account.Tooltip.DeleteAccount' | transloco\"\n tooltipPosition=\"top\">\n {{ 'User.Account.DeleteAccount' | transloco }}\n </button>\n </div>\n </div>\n </div>\n }\n <!--\n Add New Subscription\n -->\n <!-- <ng-template [ngIf]=\"isAddNew && !isUpdatePayment\">\n <pw-subscription-details></pw-subscription-details>\n</ng-template> -->\n<!--\nValidate Password For Account Delete\n-->\n<pw-password-validation #passwordValidationModalForAccountDelete\n [destructive]=\"true\"\n (successEvent)=\"deleteUser($event)\">\n</pw-password-validation>\n<!--\nValidate Password For Display Key\n-->\n<pw-password-validation #passwordValidationModalForKey\n (successEvent)=\"displayApiKey()\">\n</pw-password-validation>\n<!--\nValidate Password For Unsubscribe\n-->\n<pw-password-validation #passwordValidationForUnsubscribe\n [destructive]=\"true\"\n (successEvent)=\"onValidatePassword($event)\">\n</pw-password-validation>\n<!--\nCancel Subscription Modal\n-->\n<ng-template #cancelSubscriptionModal let-modal>\n <div class=\"modal-header\">\n <h4 class=\"modal-title\">{{ 'User.Subscriptions.CancelSubscription.Title' | transloco }}</h4>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss(); reasonToCancel = '';\">\n </button>\n </div>\n <div class=\"modal-body\">\n <p>{{ 'User.Subscriptions.CancelSubscription.Message' | transloco }}</p>\n <div class=\"mb-3\">\n <label for=\"reasonToCancel\" class=\"form-label\">\n {{ 'User.Subscriptions.CancelSubscription.ReasonLabel' | transloco }} <span class=\"text-danger\">*</span>\n </label>\n <textarea\n id=\"reasonToCancel\"\n class=\"form-control\"\n rows=\"4\"\n [(ngModel)]=\"reasonToCancel\"\n [ngClass]=\"{'is-invalid': reasonToCancel && reasonToCancel.trim() === ''}\"\n placeholder=\"{{ 'User.Subscriptions.CancelSubscription.ReasonPlaceholder' | transloco }}\"></textarea>\n @if (reasonToCancel && reasonToCancel.trim() === '') {\n <div class=\"invalid-feedback\">\n {{ 'User.Subscriptions.Validation.ReasonRequired' | transloco }}\n </div>\n }\n </div>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\"\n class=\"btn btn-outline-default\"\n (click)=\"modal.dismiss(); reasonToCancel = '';\">\n {{ 'User.Subscriptions.CancelSubscription.KeepItForNow' | transloco }}\n </button>\n <button type=\"button\"\n class=\"btn btn-danger\"\n [disabled]=\"!reasonToCancel || reasonToCancel.trim() === ''\"\n (click)=\"onConfirmCancel(); modal.close()\">\n {{ 'User.Subscriptions.CancelSubscription.ConfirmButton' | transloco }}\n </button>\n </div>\n</ng-template>\n}\n\n@if (showTos) {\n <pw-privacy-and-tos [productId]=\"productId\"></pw-privacy-and-tos>\n}\n\n<router-outlet></router-outlet>\n", styles: [".btn-list{bottom:24px;left:0;padding:0 38px;right:0}.shadow-md{padding-bottom:70px!important}.bg-dark{border:0}.subscription-details{background:#fff;border:1px solid #e2e5ea;border-radius:12px;padding:16px 16px 6px;font-size:14px;font-variant-numeric:tabular-nums}.subscription-summary{border-bottom:1px solid #eef0f3;padding-bottom:12px}.seats-usage{display:inline-block;width:120px;height:6px;margin-left:8px;border-radius:999px;vertical-align:middle;overflow:hidden;background:linear-gradient(#5a6473,#5a6473) left/calc(var(--seats-pct, 0) * 100%) 100% no-repeat,#e2e5ea}.subscription-products-cards{padding-bottom:0!important}.subscription-products-cards .card-footer{position:static!important}.subscription-products-cards.card{background:#f7f8fa;border:1px solid #eef0f3;border-radius:8px;box-shadow:none!important;font-size:14px}.card-footer{background:transparent;border-top:1px solid #eef0f3}.card-footer .footer-note{color:#5a6473;font-size:.875rem}.card-footer .footer-tos-link{color:#5a6473;font-weight:500;text-decoration:underline}.card-footer .footer-tos-link:hover{color:var(--first)}.badge{font-weight:600;border-radius:4px}.badge.bg-success{background-color:#e6f4ec!important;color:#0f6b3a!important}.badge.bg-danger{background-color:#fbeae8!important;color:#c0392b!important}.badge.bg-warning{background-color:#fbf1e3!important;color:#8a5a00!important}.badge.bg-grey,.badge.bg-role-admin{background-color:#eef0f3!important;color:#5a6473!important}code{color:var(--text);min-width:0}.danger-zone{border-top:1px solid #e2e5ea;padding-top:16px;text-align:right}\n"] }]
|
|
1905
|
+
}], ctorParameters: () => [{ type: i1$2.SubscriptionService }, { type: i2$1.AdminService }, { type: i1$1.NgbModal }, { type: i4$1.Store }, { type: i5$1.Clipboard }, { type: i0.Injector }, { type: i0.ChangeDetectorRef }, { type: i5.ConfirmDialogService }], propDecorators: { menu: [{
|
|
1815
1906
|
type: ViewChild,
|
|
1816
1907
|
args: ['menuItems', { static: false }]
|
|
1817
1908
|
}], changeSubscriptionRef: [{
|
|
@@ -1888,11 +1979,11 @@ class UserInvoiceComponent extends AppBaseComponent {
|
|
|
1888
1979
|
}
|
|
1889
1980
|
}
|
|
1890
1981
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: UserInvoiceComponent, deps: [{ token: i0.Injector }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
1891
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: UserInvoiceComponent, isStandalone: false, selector: "pw-user-invoice", usesInheritance: true, ngImport: i0, template: "<div class=\"row\" [class.custom-disable-wrapper]=\"buttonBusy\">\n <div class=\"col-12 d-flex flex-wrap justify-content-between align-items-center\">\n <h2 class=\"card-title p-0 float-start\">Your Invoices</h2>\n </div>\n</div>\n\n@if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\">\n <p-progressSpinner strokeWidth=\"2\"></p-progressSpinner>\n </div>\n}\n<div class=\"row primeng-datatable-container actions-collapsed mt-0\" [class.custom-disable-wrapper]=\"buttonBusy\" [class.hideTable]=\"totalRecordsUnFiltered === 0\">\n <div class=\"col-12 px-0\">\n <p-table #tt\n [value]=\"invoices\"\n [paginator]=\"totalRecords !== 0\"\n [rows]=\"PAGE_SIZE\"\n [lazy]=\"true\"\n [totalRecords]=\"totalRecords\"\n (onLazyLoad)=\"onLazyLoad($event)\"\n >\n <ng-template pTemplate=\"caption\">\n <div class=\"search-filter justify-content-end\">\n <div class=\"text-end\">\n <label for=\"user-invoice-search\" class=\"visually-hidden\">Search Invoices</label>\n <p-iconfield iconPosition=\"left\">\n <p-inputicon><i class=\"fa fa-search\" aria-hidden=\"true\"></i></p-inputicon>\n <input id=\"user-invoice-search\"\n name=\"user-invoice-search\"\n [(ngModel)]=\"searchText\"\n (input)=\"tt.filterGlobal($event.target.value, 'contains')\"\n type=\"text\"\n pInputText\n placeholder=\"Search
|
|
1982
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: UserInvoiceComponent, isStandalone: false, selector: "pw-user-invoice", usesInheritance: true, ngImport: i0, template: "<div class=\"row\" [class.custom-disable-wrapper]=\"buttonBusy\">\n <div class=\"col-12 d-flex flex-wrap justify-content-between align-items-center\">\n <h2 class=\"card-title p-0 float-start\">Your Invoices</h2>\n </div>\n</div>\n\n@if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\">\n <p-progressSpinner strokeWidth=\"2\"></p-progressSpinner>\n </div>\n}\n<div class=\"row primeng-datatable-container actions-collapsed mt-0\" [class.custom-disable-wrapper]=\"buttonBusy\" [class.hideTable]=\"totalRecordsUnFiltered === 0\">\n <div class=\"col-12 px-0\">\n <p-table #tt\n [value]=\"invoices\"\n [paginator]=\"totalRecords !== 0\"\n [rows]=\"PAGE_SIZE\"\n [lazy]=\"true\"\n [totalRecords]=\"totalRecords\"\n (onLazyLoad)=\"onLazyLoad($event)\"\n >\n <ng-template pTemplate=\"caption\">\n <div class=\"search-filter justify-content-end\">\n <div class=\"text-end\">\n <label for=\"user-invoice-search\" class=\"visually-hidden\">Search Invoices</label>\n <p-iconfield iconPosition=\"left\">\n <p-inputicon><i class=\"fa fa-search\" aria-hidden=\"true\"></i></p-inputicon>\n <input id=\"user-invoice-search\"\n name=\"user-invoice-search\"\n [(ngModel)]=\"searchText\"\n (input)=\"tt.filterGlobal($event.target.value, 'contains')\"\n type=\"text\"\n pInputText\n placeholder=\"Search invoices...\"\n data-cy=\"incident-search\" />\n </p-iconfield>\n </div>\n </div>\n </ng-template>\n\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"col\" pSortableColumn=\"date\">Invoice Date <p-sortIcon field=\"date\"></p-sortIcon></th>\n <th scope=\"col\" pSortableColumn=\"frequency\">Frequency <p-sortIcon field=\"frequency\"></p-sortIcon></th>\n <th scope=\"col\" pSortableColumn=\"seatsPurchased\">Seats Purchased <p-sortIcon field=\"seatsPurchased\"></p-sortIcon></th>\n <th scope=\"col\" pSortableColumn=\"subtotal\">Subtotal <p-sortIcon field=\"subtotal\"></p-sortIcon></th>\n <th scope=\"col\" pSortableColumn=\"total\">Total (incl. tax) <p-sortIcon field=\"total\"></p-sortIcon></th>\n <th scope=\"col\">Action</th>\n </tr>\n </ng-template>\n\n <ng-template pTemplate=\"body\" let-invoice>\n <tr>\n <td>{{ invoice.date | date:'dd-MMM-yyyy' }}</td>\n <td>\n <span class=\"badge\"\n [appDynamicBadge]=\"{\n itemsArray: invoiceFrequency,\n item: invoice.product.billing_frequency\n }\"\n color=\"blue-grey\">{{ invoice.product.billing_frequency }}</span>\n </td>\n <td>{{ invoice?.subscription_product?.purchased_units }}</td>\n <td>{{ (invoice.subtotal_in_cents / 100) | currency:invoice?.product?.currency }}</td>\n <td class=\"td-total\">{{ (invoice.total_in_cents / 100) | currency:invoice?.product?.currency }}</td>\n <td>\n @if (invoice?.file?.url) {\n <a class=\"btn btn-sm btn-primary\" [attr.href]=\"invoice.file.url\" target=\"_blank\" title=\"Download\">\n <i class=\"fa fa-download\"> Download</i>\n </a>\n } @else {\n <a class=\"btn btn-sm btn-primary\" [attr.href]=\"invoice?.stripe_invoice_pdf\" target=\"_blank\" title=\"Download\">\n <i class=\"fa fa-download\"> Download</i>\n </a>\n }\n </td>\n </tr>\n </ng-template>\n </p-table>\n @if (totalRecords === 0 && totalRecordsUnFiltered !== 0) {\n <div>\n <pw-no-data [withImage]=\"true\" [message]=\"'Search.NoDataMessage' | transloco\" [description]=\"'Search.NoDataDescription' | transloco\" >\n </pw-no-data>\n </div>\n }\n\n @if (totalRecords !== 0) {\n <pw-records-summary [showing]=\"tt?.value?.length ?? 0\" [total]=\"totalRecords\" />\n }\n\n </div>\n</div>\n@if (totalRecordsUnFiltered === 0 && isLoaded) {\n <pw-no-data [withImage]=\"true\" message=\"You don't have any invoice yet.\">\n </pw-no-data>\n}\n\n", styles: [".page-heading{background:#fcfcfc;border-bottom:1px solid rgba(0,0,0,.1);position:relative;width:100%}.page-heading:after{clear:both;content:\"\";display:table}.page-heading .page-heading__container{padding:15px 20px;position:relative}.page-heading .page-heading__container .title{color:#242437;font-size:15px;font-weight:500;line-height:20px;margin:3px 0 0;overflow:hidden;padding:0;text-overflow:ellipsis;width:95%}.card .card-container{position:absolute;right:20px;top:25px;z-index:1}.td-total{font-weight:700}.card-inner-container{background:#0000000d;border:1px dashed rgba(0,0,0,.1);border-radius:3px;margin-bottom:20px;padding:20px}.invoice-text{display:flex;font-size:13px;justify-content:space-between;margin:10px 0}.invoice-template{min-height:calc(100vh - 190px)}\n"], dependencies: [{ kind: "directive", type: i1$3.InputText, selector: "[pInputText]", inputs: ["hostName", "ptInputText", "pInputTextPT", "pInputTextUnstyled", "pSize", "variant", "fluid", "invalid"] }, { kind: "directive", type: i3.DynamicBadgeDirective, selector: "[appDynamicBadge]", inputs: ["appDynamicBadge", "color", "colorByName", "dataName"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "component", type: i4$2.Table, selector: "p-table", inputs: ["frozenColumns", "frozenValue", "styleClass", "tableStyle", "tableStyleClass", "paginator", "pageLinks", "rowsPerPageOptions", "alwaysShowPaginator", "paginatorPosition", "paginatorStyleClass", "paginatorDropdownAppendTo", "paginatorDropdownScrollHeight", "currentPageReportTemplate", "showCurrentPageReport", "showJumpToPageDropdown", "showJumpToPageInput", "showFirstLastIcon", "showPageLinks", "defaultSortOrder", "sortMode", "resetPageOnSort", "selectionMode", "selectionPageOnly", "contextMenuSelection", "contextMenuSelectionMode", "dataKey", "metaKeySelection", "rowSelectable", "rowTrackBy", "lazy", "lazyLoadOnInit", "compareSelectionBy", "csvSeparator", "exportFilename", "filters", "globalFilterFields", "filterDelay", "filterLocale", "expandedRowKeys", "editingRowKeys", "rowExpandMode", "scrollable", "rowGroupMode", "scrollHeight", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "virtualScrollDelay", "frozenWidth", "contextMenu", "resizableColumns", "columnResizeMode", "reorderableColumns", "loading", "loadingIcon", "showLoader", "rowHover", "customSort", "showInitialSortBadge", "exportFunction", "exportHeader", "stateKey", "stateStorage", "editMode", "groupRowsBy", "size", "showGridlines", "stripedRows", "groupRowsByOrder", "responsiveLayout", "breakpoint", "paginatorLocale", "value", "columns", "first", "rows", "totalRecords", "sortField", "sortOrder", "multiSortMeta", "selection", "selectAll"], outputs: ["contextMenuSelectionChange", "selectAllChange", "selectionChange", "onRowSelect", "onRowUnselect", "onPage", "onSort", "onFilter", "onLazyLoad", "onRowExpand", "onRowCollapse", "onContextMenuSelect", "onColResize", "onColReorder", "onRowReorder", "onEditInit", "onEditComplete", "onEditCancel", "onHeaderCheckboxToggle", "sortFunction", "firstChange", "rowsChange", "onStateSave", "onStateRestore"] }, { kind: "directive", type: i5$2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "directive", type: i4$2.SortableColumn, selector: "[pSortableColumn]", inputs: ["pSortableColumn", "pSortableColumnDisabled"] }, { kind: "component", type: i4$2.SortIcon, selector: "p-sortIcon", inputs: ["field"] }, { kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i5.NoDataComponent, selector: "pw-no-data", inputs: ["message", "description", "withImage"] }, { kind: "component", type: i5.RecordsSummaryComponent, selector: "pw-records-summary", inputs: ["showing", "total"] }, { kind: "pipe", type: i8.CurrencyPipe, name: "currency" }, { kind: "pipe", type: i8.DatePipe, name: "date" }, { kind: "pipe", type: i8$2.TranslocoPipe, name: "transloco" }] }); }
|
|
1892
1983
|
}
|
|
1893
1984
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: UserInvoiceComponent, decorators: [{
|
|
1894
1985
|
type: Component,
|
|
1895
|
-
args: [{ selector: 'pw-user-invoice', standalone: false, template: "<div class=\"row\" [class.custom-disable-wrapper]=\"buttonBusy\">\n <div class=\"col-12 d-flex flex-wrap justify-content-between align-items-center\">\n <h2 class=\"card-title p-0 float-start\">Your Invoices</h2>\n </div>\n</div>\n\n@if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\">\n <p-progressSpinner strokeWidth=\"2\"></p-progressSpinner>\n </div>\n}\n<div class=\"row primeng-datatable-container actions-collapsed mt-0\" [class.custom-disable-wrapper]=\"buttonBusy\" [class.hideTable]=\"totalRecordsUnFiltered === 0\">\n <div class=\"col-12 px-0\">\n <p-table #tt\n [value]=\"invoices\"\n [paginator]=\"totalRecords !== 0\"\n [rows]=\"PAGE_SIZE\"\n [lazy]=\"true\"\n [totalRecords]=\"totalRecords\"\n (onLazyLoad)=\"onLazyLoad($event)\"\n >\n <ng-template pTemplate=\"caption\">\n <div class=\"search-filter justify-content-end\">\n <div class=\"text-end\">\n <label for=\"user-invoice-search\" class=\"visually-hidden\">Search Invoices</label>\n <p-iconfield iconPosition=\"left\">\n <p-inputicon><i class=\"fa fa-search\" aria-hidden=\"true\"></i></p-inputicon>\n <input id=\"user-invoice-search\"\n name=\"user-invoice-search\"\n [(ngModel)]=\"searchText\"\n (input)=\"tt.filterGlobal($event.target.value, 'contains')\"\n type=\"text\"\n pInputText\n placeholder=\"Search
|
|
1986
|
+
args: [{ selector: 'pw-user-invoice', standalone: false, template: "<div class=\"row\" [class.custom-disable-wrapper]=\"buttonBusy\">\n <div class=\"col-12 d-flex flex-wrap justify-content-between align-items-center\">\n <h2 class=\"card-title p-0 float-start\">Your Invoices</h2>\n </div>\n</div>\n\n@if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\">\n <p-progressSpinner strokeWidth=\"2\"></p-progressSpinner>\n </div>\n}\n<div class=\"row primeng-datatable-container actions-collapsed mt-0\" [class.custom-disable-wrapper]=\"buttonBusy\" [class.hideTable]=\"totalRecordsUnFiltered === 0\">\n <div class=\"col-12 px-0\">\n <p-table #tt\n [value]=\"invoices\"\n [paginator]=\"totalRecords !== 0\"\n [rows]=\"PAGE_SIZE\"\n [lazy]=\"true\"\n [totalRecords]=\"totalRecords\"\n (onLazyLoad)=\"onLazyLoad($event)\"\n >\n <ng-template pTemplate=\"caption\">\n <div class=\"search-filter justify-content-end\">\n <div class=\"text-end\">\n <label for=\"user-invoice-search\" class=\"visually-hidden\">Search Invoices</label>\n <p-iconfield iconPosition=\"left\">\n <p-inputicon><i class=\"fa fa-search\" aria-hidden=\"true\"></i></p-inputicon>\n <input id=\"user-invoice-search\"\n name=\"user-invoice-search\"\n [(ngModel)]=\"searchText\"\n (input)=\"tt.filterGlobal($event.target.value, 'contains')\"\n type=\"text\"\n pInputText\n placeholder=\"Search invoices...\"\n data-cy=\"incident-search\" />\n </p-iconfield>\n </div>\n </div>\n </ng-template>\n\n <ng-template pTemplate=\"header\">\n <tr>\n <th scope=\"col\" pSortableColumn=\"date\">Invoice Date <p-sortIcon field=\"date\"></p-sortIcon></th>\n <th scope=\"col\" pSortableColumn=\"frequency\">Frequency <p-sortIcon field=\"frequency\"></p-sortIcon></th>\n <th scope=\"col\" pSortableColumn=\"seatsPurchased\">Seats Purchased <p-sortIcon field=\"seatsPurchased\"></p-sortIcon></th>\n <th scope=\"col\" pSortableColumn=\"subtotal\">Subtotal <p-sortIcon field=\"subtotal\"></p-sortIcon></th>\n <th scope=\"col\" pSortableColumn=\"total\">Total (incl. tax) <p-sortIcon field=\"total\"></p-sortIcon></th>\n <th scope=\"col\">Action</th>\n </tr>\n </ng-template>\n\n <ng-template pTemplate=\"body\" let-invoice>\n <tr>\n <td>{{ invoice.date | date:'dd-MMM-yyyy' }}</td>\n <td>\n <span class=\"badge\"\n [appDynamicBadge]=\"{\n itemsArray: invoiceFrequency,\n item: invoice.product.billing_frequency\n }\"\n color=\"blue-grey\">{{ invoice.product.billing_frequency }}</span>\n </td>\n <td>{{ invoice?.subscription_product?.purchased_units }}</td>\n <td>{{ (invoice.subtotal_in_cents / 100) | currency:invoice?.product?.currency }}</td>\n <td class=\"td-total\">{{ (invoice.total_in_cents / 100) | currency:invoice?.product?.currency }}</td>\n <td>\n @if (invoice?.file?.url) {\n <a class=\"btn btn-sm btn-primary\" [attr.href]=\"invoice.file.url\" target=\"_blank\" title=\"Download\">\n <i class=\"fa fa-download\"> Download</i>\n </a>\n } @else {\n <a class=\"btn btn-sm btn-primary\" [attr.href]=\"invoice?.stripe_invoice_pdf\" target=\"_blank\" title=\"Download\">\n <i class=\"fa fa-download\"> Download</i>\n </a>\n }\n </td>\n </tr>\n </ng-template>\n </p-table>\n @if (totalRecords === 0 && totalRecordsUnFiltered !== 0) {\n <div>\n <pw-no-data [withImage]=\"true\" [message]=\"'Search.NoDataMessage' | transloco\" [description]=\"'Search.NoDataDescription' | transloco\" >\n </pw-no-data>\n </div>\n }\n\n @if (totalRecords !== 0) {\n <pw-records-summary [showing]=\"tt?.value?.length ?? 0\" [total]=\"totalRecords\" />\n }\n\n </div>\n</div>\n@if (totalRecordsUnFiltered === 0 && isLoaded) {\n <pw-no-data [withImage]=\"true\" message=\"You don't have any invoice yet.\">\n </pw-no-data>\n}\n\n", styles: [".page-heading{background:#fcfcfc;border-bottom:1px solid rgba(0,0,0,.1);position:relative;width:100%}.page-heading:after{clear:both;content:\"\";display:table}.page-heading .page-heading__container{padding:15px 20px;position:relative}.page-heading .page-heading__container .title{color:#242437;font-size:15px;font-weight:500;line-height:20px;margin:3px 0 0;overflow:hidden;padding:0;text-overflow:ellipsis;width:95%}.card .card-container{position:absolute;right:20px;top:25px;z-index:1}.td-total{font-weight:700}.card-inner-container{background:#0000000d;border:1px dashed rgba(0,0,0,.1);border-radius:3px;margin-bottom:20px;padding:20px}.invoice-text{display:flex;font-size:13px;justify-content:space-between;margin:10px 0}.invoice-template{min-height:calc(100vh - 190px)}\n"] }]
|
|
1896
1987
|
}], ctorParameters: () => [{ type: i0.Injector }, { type: i0.ChangeDetectorRef }] });
|
|
1897
1988
|
|
|
1898
1989
|
class CommunicationTabComponent extends AppBaseComponent {
|
|
@@ -1966,13 +2057,13 @@ class CommunicationTabComponent extends AppBaseComponent {
|
|
|
1966
2057
|
// this.localStorage.setItem('user', JSON.stringify(resp)).subscribe();
|
|
1967
2058
|
// });
|
|
1968
2059
|
}
|
|
1969
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: CommunicationTabComponent, deps: [{ token: i1$2.CommonService }, { token: i1$2.ProfileService }, { token: i4$
|
|
1970
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: CommunicationTabComponent, isStandalone: false, selector: "pw-communication-tab", usesInheritance: true, ngImport: i0, template: "<div class=\"communication-settings\">\n <h2>{{ 'User.Settings.Communications.Title' | transloco }}</h2>\n\n <p class=\"settings-intro\">{{ 'User.Settings.Communications.Intro1' | transloco }}</p>\n <p class=\"settings-intro\">{{ 'User.Settings.Communications.Intro2' | transloco }}</p>\n\n @if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n\n @if (isLoaded && subscriptions.length > 0) {\n <ul class=\"pref-list\">\n @for (item of subscriptions; track item; let idx = $index) {\n @if (item.visible || item.enabled) {\n <li class=\"pref-row\">\n <span class=\"pref-name\" [id]=\"'communication-tab-' + idx\">{{ item.name }}</span>\n <ui-switch [checked]=\"item.enabled\"\n [attr.aria-labelledby]=\"'communication-tab-' + idx\"\n (valueChange)=\"onValueChange(item, $event)\">\n </ui-switch>\n </li>\n }\n }\n </ul>\n }\n\n @if (isLoaded && subscriptions.length === 0) {\n <pw-no-data [withImage]=\"true\"\n [message]=\"'User.Settings.Communications.NoDataMessage' | transloco\">\n </pw-no-data>\n }\n</div>\n", styles: [":host{display:block}.communication-settings{max-width:800px}.settings-intro{color:#5a6473;font-size:14px;line-height:1.55;margin-bottom:.75rem}.pref-list{list-style:none;margin:1.75rem 0 0;padding:0;border-top:1px solid #e2e5ea}.pref-row{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:12px 4px;border-bottom:1px solid #e2e5ea}.pref-name{flex:1 1 auto;min-width:0;color:var(--text, #222);font-size:14px;font-weight:500;line-height:1.4}\n"], dependencies: [{ kind: "component", type: i4
|
|
2060
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: CommunicationTabComponent, deps: [{ token: i1$2.CommonService }, { token: i1$2.ProfileService }, { token: i4$1.Store }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2061
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: CommunicationTabComponent, isStandalone: false, selector: "pw-communication-tab", usesInheritance: true, ngImport: i0, template: "<div class=\"communication-settings\">\n <h2>{{ 'User.Settings.Communications.Title' | transloco }}</h2>\n\n <p class=\"settings-intro\">{{ 'User.Settings.Communications.Intro1' | transloco }}</p>\n <p class=\"settings-intro\">{{ 'User.Settings.Communications.Intro2' | transloco }}</p>\n\n @if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n\n @if (isLoaded && subscriptions.length > 0) {\n <ul class=\"pref-list\">\n @for (item of subscriptions; track item; let idx = $index) {\n @if (item.visible || item.enabled) {\n <li class=\"pref-row\">\n <span class=\"pref-name\" [id]=\"'communication-tab-' + idx\">{{ item.name }}</span>\n <ui-switch [checked]=\"item.enabled\"\n [attr.aria-labelledby]=\"'communication-tab-' + idx\"\n (valueChange)=\"onValueChange(item, $event)\">\n </ui-switch>\n </li>\n }\n }\n </ul>\n }\n\n @if (isLoaded && subscriptions.length === 0) {\n <pw-no-data [withImage]=\"true\"\n [message]=\"'User.Settings.Communications.NoDataMessage' | transloco\">\n </pw-no-data>\n }\n</div>\n", styles: [":host{display:block}.communication-settings{max-width:800px}.settings-intro{color:#5a6473;font-size:14px;line-height:1.55;margin-bottom:.75rem}.pref-list{list-style:none;margin:1.75rem 0 0;padding:0;border-top:1px solid #e2e5ea}.pref-row{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:12px 4px;border-bottom:1px solid #e2e5ea}.pref-name{flex:1 1 auto;min-width:0;color:var(--text, #222);font-size:14px;font-weight:500;line-height:1.4}\n"], dependencies: [{ kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "component", type: i11$1.UiSwitchComponent, selector: "ui-switch", inputs: ["size", "color", "switchOffColor", "switchColor", "defaultBgColor", "defaultBoColor", "checkedLabel", "uncheckedLabel", "checkedTextColor", "uncheckedTextColor", "beforeChange", "ariaLabel", "checked", "disabled", "reverse", "loading"], outputs: ["change", "changeEvent", "valueChange"] }, { kind: "component", type: i5.NoDataComponent, selector: "pw-no-data", inputs: ["message", "description", "withImage"] }, { kind: "pipe", type: i8$2.TranslocoPipe, name: "transloco" }] }); }
|
|
1971
2062
|
}
|
|
1972
2063
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: CommunicationTabComponent, decorators: [{
|
|
1973
2064
|
type: Component,
|
|
1974
2065
|
args: [{ selector: 'pw-communication-tab', standalone: false, template: "<div class=\"communication-settings\">\n <h2>{{ 'User.Settings.Communications.Title' | transloco }}</h2>\n\n <p class=\"settings-intro\">{{ 'User.Settings.Communications.Intro1' | transloco }}</p>\n <p class=\"settings-intro\">{{ 'User.Settings.Communications.Intro2' | transloco }}</p>\n\n @if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\">\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n\n @if (isLoaded && subscriptions.length > 0) {\n <ul class=\"pref-list\">\n @for (item of subscriptions; track item; let idx = $index) {\n @if (item.visible || item.enabled) {\n <li class=\"pref-row\">\n <span class=\"pref-name\" [id]=\"'communication-tab-' + idx\">{{ item.name }}</span>\n <ui-switch [checked]=\"item.enabled\"\n [attr.aria-labelledby]=\"'communication-tab-' + idx\"\n (valueChange)=\"onValueChange(item, $event)\">\n </ui-switch>\n </li>\n }\n }\n </ul>\n }\n\n @if (isLoaded && subscriptions.length === 0) {\n <pw-no-data [withImage]=\"true\"\n [message]=\"'User.Settings.Communications.NoDataMessage' | transloco\">\n </pw-no-data>\n }\n</div>\n", styles: [":host{display:block}.communication-settings{max-width:800px}.settings-intro{color:#5a6473;font-size:14px;line-height:1.55;margin-bottom:.75rem}.pref-list{list-style:none;margin:1.75rem 0 0;padding:0;border-top:1px solid #e2e5ea}.pref-row{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:12px 4px;border-bottom:1px solid #e2e5ea}.pref-name{flex:1 1 auto;min-width:0;color:var(--text, #222);font-size:14px;font-weight:500;line-height:1.4}\n"] }]
|
|
1975
|
-
}], ctorParameters: () => [{ type: i1$2.CommonService }, { type: i1$2.ProfileService }, { type: i4$
|
|
2066
|
+
}], ctorParameters: () => [{ type: i1$2.CommonService }, { type: i1$2.ProfileService }, { type: i4$1.Store }, { type: i0.Injector }, { type: i0.ChangeDetectorRef }] });
|
|
1976
2067
|
|
|
1977
2068
|
class OthersTabComponent extends AppBaseComponent {
|
|
1978
2069
|
constructor(commonService, injector, cdr) {
|
|
@@ -2036,7 +2127,7 @@ class OthersTabComponent extends AppBaseComponent {
|
|
|
2036
2127
|
super.ngOnDestroy();
|
|
2037
2128
|
}
|
|
2038
2129
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: OthersTabComponent, deps: [{ token: i1$2.CommonService }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2039
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: OthersTabComponent, isStandalone: false, selector: "pw-others-tab", usesInheritance: true, ngImport: i0, template: "<div class=\"row\">\n <div class=\"col-12\">\n <h2>Other</h2>\n </div>\n</div>\n@if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\"\n >\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n}\n@if (isLoaded && globalConfigs?.length) {\n <div class=\"row mt-4 pt-1\"\n >\n <div class=\"col-md-6 col-sm-6\">\n @for (item of globalConfigs; track item; let idx = $index) {\n <div class=\"mb-3\">\n <div class=\"row\">\n <div class=\"col-md-10 col-sm-6\">\n <span class=\"pw-label-style\" [id]=\"'others-tab-' + idx\"> {{ item?.name }} </span>\n </div>\n <div class=\"col-md-2 col-sm-6\">\n <ui-switch [checked]=\"item.value === 'true'\"\n [attr.aria-labelledby]=\"'others-tab-' + idx\"\n (valueChange)=\"onValueChange(item, $event)\">\n </ui-switch>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n}\n\n@if (isLoaded && !globalConfigs?.length) {\n <div>\n <pw-no-data [withImage]=\"true\" [message]=\"'User.OtherSettings.NoDataMessage' | transloco\"> </pw-no-data>\n </div>\n}\n", dependencies: [{ kind: "component", type: i4
|
|
2130
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: OthersTabComponent, isStandalone: false, selector: "pw-others-tab", usesInheritance: true, ngImport: i0, template: "<div class=\"row\">\n <div class=\"col-12\">\n <h2>Other</h2>\n </div>\n</div>\n@if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\"\n >\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n}\n@if (isLoaded && globalConfigs?.length) {\n <div class=\"row mt-4 pt-1\"\n >\n <div class=\"col-md-6 col-sm-6\">\n @for (item of globalConfigs; track item; let idx = $index) {\n <div class=\"mb-3\">\n <div class=\"row\">\n <div class=\"col-md-10 col-sm-6\">\n <span class=\"pw-label-style\" [id]=\"'others-tab-' + idx\"> {{ item?.name }} </span>\n </div>\n <div class=\"col-md-2 col-sm-6\">\n <ui-switch [checked]=\"item.value === 'true'\"\n [attr.aria-labelledby]=\"'others-tab-' + idx\"\n (valueChange)=\"onValueChange(item, $event)\">\n </ui-switch>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n}\n\n@if (isLoaded && !globalConfigs?.length) {\n <div>\n <pw-no-data [withImage]=\"true\" [message]=\"'User.OtherSettings.NoDataMessage' | transloco\"> </pw-no-data>\n </div>\n}\n", dependencies: [{ kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "component", type: i11$1.UiSwitchComponent, selector: "ui-switch", inputs: ["size", "color", "switchOffColor", "switchColor", "defaultBgColor", "defaultBoColor", "checkedLabel", "uncheckedLabel", "checkedTextColor", "uncheckedTextColor", "beforeChange", "ariaLabel", "checked", "disabled", "reverse", "loading"], outputs: ["change", "changeEvent", "valueChange"] }, { kind: "component", type: i5.NoDataComponent, selector: "pw-no-data", inputs: ["message", "description", "withImage"] }, { kind: "pipe", type: i8$2.TranslocoPipe, name: "transloco" }] }); }
|
|
2040
2131
|
}
|
|
2041
2132
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: OthersTabComponent, decorators: [{
|
|
2042
2133
|
type: Component,
|
|
@@ -2174,7 +2265,7 @@ class SecurityTabComponent extends AppBaseComponent {
|
|
|
2174
2265
|
}
|
|
2175
2266
|
}
|
|
2176
2267
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: SecurityTabComponent, deps: [{ token: i0.Injector }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2177
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: SecurityTabComponent, isStandalone: false, selector: "pw-security-tab", viewQueries: [{ propertyName: "passwordRef", first: true, predicate: ["password"], descendants: true }, { propertyName: "verificationCode", first: true, predicate: ["verificationCode"], descendants: true }, { propertyName: "ssoPasswordRef", first: true, predicate: ["ssoPassword"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"row\">\n <div class=\"col-12\">\n <h2>Security settings</h2>\n </div>\n</div>\n<p-accordion>\n <p-accordion-panel value=\"0\">\n <p-accordion-header>Two Factor Authentication (2FA)</p-accordion-header>\n <p-accordion-content>\n <div class=\"row mt-2\">\n <div class=\"col-12\">\n <div class=\"d-flex\">\n <p class=\"small text-muted\"> Add an extra layer of security to your user account by asking to verify their\n identity when they enter a username and password </p>\n </div>\n </div>\n </div>\n <div class=\"row\">\n <div class=\"col-12\">\n <!-- Disable 2FA -->\n @if (user?.enable_two_factor_authenticator) {\n <button class=\"btn btn-danger\" (click)=\"show2FA = true\"> Disable\n </button>\n }\n <!-- Enable 2FA -->\n @if (!user?.enable_two_factor_authenticator) {\n <button class=\"btn btn-primary\"\n [disabled]=\"created2faDetails?.code\" (click)=\"show2FA = true\"> Enable </button>\n }\n </div>\n </div>\n @if (show2FA) {\n <div class=\"row\">\n <div class=\"col-12 col-md-6 col-lg-4 mt-2\">\n <div class=\"mb-3\">\n @if (!passwordVerified) {\n <input type=\"password\" class=\"form-control\" #password placeholder=\"Current Password\"\n (keyup)=\"checkValidity()\" id=\"input_current_password_800\" name=\"input_current_password_800\" />\n }\n </div>\n </div>\n @if (created2faDetails?.code) {\n <div class=\"col-12\">\n <p class=\"small\"> Scan the QR code below or use secret manually with the Google authenticator app on your mobile\n device, after that fill in the field below with the code generated in the app </p>\n <img [src]=\"created2faDetails?.qr_uri\" alt=\"loading QR code...\" class=\"qr-code img-thumbnail img-responsive\" />\n <strong> Secret Key: {{ created2faDetails?.code }}</strong>\n <p class=\"small\">Auth Type: Time Based OTP</p>\n </div>\n }\n </div>\n }\n @if (show2FA) {\n <div class=\"row\">\n <div class=\"col-4\">\n <div class=\"mb-3 mt-2\">\n @if (passwordVerified) {\n <input type=\"text\" #verificationCode class=\"form-control\"\n placeholder=\"Provide passcode from authenticator app\" id=\"input_provide_passcode_from_authenticator_app_800\" name=\"input_provide_passcode_from_authenticator_app_800\" />\n }\n </div>\n </div>\n @if (show2FA) {\n <div class=\"col-12\">\n <div class=\"d-flex mt-2\">\n <button class=\"btn btn-raised btn-outline-default me-2\" (click)=\"reset()\"> Cancel </button>\n @if (!passwordVerified) {\n <button class=\"btn btn-raised btn-primary\" (click)=\"validatePassword()\"\n [disabled]=\"isCurrentPasswordValid\"> Validate </button>\n }\n @if (passwordVerified) {\n <button class=\"btn btn-raised btn-primary\" (click)=\"verify2FA()\"> Confirm </button>\n }\n </div>\n </div>\n }\n </div>\n }\n </p-accordion-content>\n </p-accordion-panel>\n <p-accordion-panel value=\"1\">\n <p-accordion-header>Single Sign On (SSO) - AWS Cognito</p-accordion-header>\n <p-accordion-content>\n <div class=\"row mt-2\">\n <div class=\"col-12\">\n <p class=\"small text-muted\"> {{ user?.cognito_sso_activated ? 'You have already activated AWS Cognito SSO, if you click on \u2018Resend activation email\u2018 you\u2018ll receive an email with instructions to reset your SSO\n password.' : 'Once you click \u2018Enable\u2019, you\u2019ll receive an email with instructions to activate your AWS Cognito\n SSO. This will enable you to access all our systems using a single password.' }} </p>\n </div>\n </div>\n <!-- Enable or Resend Button -->\n @if (!showSSOSection) {\n <div class=\"row\">\n <div class=\"col-12\">\n <button class=\"btn btn-primary\" (click)=\"showSSOSection = true\"> {{ user?.cognito_sso_activated ? 'Resend\n activation email' : 'Enable' }} </button>\n </div>\n </div>\n }\n <!-- Password Validation -->\n @if (showSSOSection) {\n <div class=\"row\">\n @if (!ssoPasswordVerified) {\n <div class=\"col-12 col-md-6 col-lg-4 mt-2\">\n <div class=\"mb-3\">\n <input type=\"password\" class=\"form-control\" #ssoPassword placeholder=\"Current Password\"\n (keyup)=\"checkSSOPasswordValidity()\" id=\"input_current_password_801\" name=\"input_current_password_801\" />\n </div>\n </div>\n }\n <div class=\"col-12\">\n <div class=\"d-flex mt-2\">\n <button class=\"btn btn-raised btn-outline-default me-2\" (click)=\"resetSSO()\"> Cancel </button>\n @if (!ssoPasswordVerified) {\n <button class=\"btn btn-raised btn-primary\" (click)=\"validateSSOPassword()\"\n [disabled]=\"isSSOPasswordInvalid\"> Validate </button>\n }\n @if (ssoPasswordVerified) {\n <button class=\"btn btn-primary\" (click)=\"triggerSSO()\"> Confirm </button>\n }\n </div>\n </div>\n </div>\n }\n </p-accordion-content>\n </p-accordion-panel>\n</p-accordion>\n", styles: [".qr-code{margin:10px;max-width:200px}.text-muted{font-size:15px!important}\n"], dependencies: [{ kind: "directive", type:
|
|
2268
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: SecurityTabComponent, isStandalone: false, selector: "pw-security-tab", viewQueries: [{ propertyName: "passwordRef", first: true, predicate: ["password"], descendants: true }, { propertyName: "verificationCode", first: true, predicate: ["verificationCode"], descendants: true }, { propertyName: "ssoPasswordRef", first: true, predicate: ["ssoPassword"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"row\">\n <div class=\"col-12\">\n <h2>Security settings</h2>\n </div>\n</div>\n<p-accordion>\n <p-accordion-panel value=\"0\">\n <p-accordion-header>Two Factor Authentication (2FA)</p-accordion-header>\n <p-accordion-content>\n <div class=\"row mt-2\">\n <div class=\"col-12\">\n <div class=\"d-flex\">\n <p class=\"small text-muted\"> Add an extra layer of security to your user account by asking to verify their\n identity when they enter a username and password </p>\n </div>\n </div>\n </div>\n <div class=\"row\">\n <div class=\"col-12\">\n <!-- Disable 2FA -->\n @if (user?.enable_two_factor_authenticator) {\n <button class=\"btn btn-danger\" (click)=\"show2FA = true\"> Disable\n </button>\n }\n <!-- Enable 2FA -->\n @if (!user?.enable_two_factor_authenticator) {\n <button class=\"btn btn-primary\"\n [disabled]=\"created2faDetails?.code\" (click)=\"show2FA = true\"> Enable </button>\n }\n </div>\n </div>\n @if (show2FA) {\n <div class=\"row\">\n <div class=\"col-12 col-md-6 col-lg-4 mt-2\">\n <div class=\"mb-3\">\n @if (!passwordVerified) {\n <input type=\"password\" class=\"form-control\" #password placeholder=\"Current Password\"\n (keyup)=\"checkValidity()\" id=\"input_current_password_800\" name=\"input_current_password_800\" />\n }\n </div>\n </div>\n @if (created2faDetails?.code) {\n <div class=\"col-12\">\n <p class=\"small\"> Scan the QR code below or use secret manually with the Google authenticator app on your mobile\n device, after that fill in the field below with the code generated in the app </p>\n <img [src]=\"created2faDetails?.qr_uri\" alt=\"loading QR code...\" class=\"qr-code img-thumbnail img-responsive\" />\n <strong> Secret Key: {{ created2faDetails?.code }}</strong>\n <p class=\"small\">Auth Type: Time Based OTP</p>\n </div>\n }\n </div>\n }\n @if (show2FA) {\n <div class=\"row\">\n <div class=\"col-4\">\n <div class=\"mb-3 mt-2\">\n @if (passwordVerified) {\n <input type=\"text\" #verificationCode class=\"form-control\"\n placeholder=\"Provide passcode from authenticator app\" id=\"input_provide_passcode_from_authenticator_app_800\" name=\"input_provide_passcode_from_authenticator_app_800\" />\n }\n </div>\n </div>\n @if (show2FA) {\n <div class=\"col-12\">\n <div class=\"d-flex mt-2\">\n <button class=\"btn btn-raised btn-outline-default me-2\" (click)=\"reset()\"> Cancel </button>\n @if (!passwordVerified) {\n <button class=\"btn btn-raised btn-primary\" (click)=\"validatePassword()\"\n [disabled]=\"isCurrentPasswordValid\"> Validate </button>\n }\n @if (passwordVerified) {\n <button class=\"btn btn-raised btn-primary\" (click)=\"verify2FA()\"> Confirm </button>\n }\n </div>\n </div>\n }\n </div>\n }\n </p-accordion-content>\n </p-accordion-panel>\n <p-accordion-panel value=\"1\">\n <p-accordion-header>Single Sign On (SSO) - AWS Cognito</p-accordion-header>\n <p-accordion-content>\n <div class=\"row mt-2\">\n <div class=\"col-12\">\n <p class=\"small text-muted\"> {{ user?.cognito_sso_activated ? 'You have already activated AWS Cognito SSO, if you click on \u2018Resend activation email\u2018 you\u2018ll receive an email with instructions to reset your SSO\n password.' : 'Once you click \u2018Enable\u2019, you\u2019ll receive an email with instructions to activate your AWS Cognito\n SSO. This will enable you to access all our systems using a single password.' }} </p>\n </div>\n </div>\n <!-- Enable or Resend Button -->\n @if (!showSSOSection) {\n <div class=\"row\">\n <div class=\"col-12\">\n <button class=\"btn btn-primary\" (click)=\"showSSOSection = true\"> {{ user?.cognito_sso_activated ? 'Resend\n activation email' : 'Enable' }} </button>\n </div>\n </div>\n }\n <!-- Password Validation -->\n @if (showSSOSection) {\n <div class=\"row\">\n @if (!ssoPasswordVerified) {\n <div class=\"col-12 col-md-6 col-lg-4 mt-2\">\n <div class=\"mb-3\">\n <input type=\"password\" class=\"form-control\" #ssoPassword placeholder=\"Current Password\"\n (keyup)=\"checkSSOPasswordValidity()\" id=\"input_current_password_801\" name=\"input_current_password_801\" />\n </div>\n </div>\n }\n <div class=\"col-12\">\n <div class=\"d-flex mt-2\">\n <button class=\"btn btn-raised btn-outline-default me-2\" (click)=\"resetSSO()\"> Cancel </button>\n @if (!ssoPasswordVerified) {\n <button class=\"btn btn-raised btn-primary\" (click)=\"validateSSOPassword()\"\n [disabled]=\"isSSOPasswordInvalid\"> Validate </button>\n }\n @if (ssoPasswordVerified) {\n <button class=\"btn btn-primary\" (click)=\"triggerSSO()\"> Confirm </button>\n }\n </div>\n </div>\n </div>\n }\n </p-accordion-content>\n </p-accordion-panel>\n</p-accordion>\n", styles: [".qr-code{margin:10px;max-width:200px}.text-muted{font-size:15px!important}\n"], dependencies: [{ kind: "directive", type: i3.LazyImgDirective, selector: "img" }, { kind: "component", type: i2$2.Accordion, selector: "p-accordion", inputs: ["value", "multiple", "styleClass", "expandIcon", "collapseIcon", "selectOnFocus", "transitionOptions", "motionOptions"], outputs: ["valueChange", "onClose", "onOpen"] }, { kind: "component", type: i2$2.AccordionPanel, selector: "p-accordion-panel, p-accordionpanel", inputs: ["value", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: i2$2.AccordionHeader, selector: "p-accordion-header, p-accordionheader" }, { kind: "component", type: i2$2.AccordionContent, selector: "p-accordion-content, p-accordioncontent" }] }); }
|
|
2178
2269
|
}
|
|
2179
2270
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: SecurityTabComponent, decorators: [{
|
|
2180
2271
|
type: Component,
|
|
@@ -2258,7 +2349,7 @@ class SupportComponent extends AppBaseComponent {
|
|
|
2258
2349
|
});
|
|
2259
2350
|
}
|
|
2260
2351
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: SupportComponent, deps: [{ token: i0.Injector }, { token: i1$2.CommonService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2261
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: SupportComponent, isStandalone: false, selector: "pw-support", usesInheritance: true, ngImport: i0, template: "<div class=\"row m-3\">\n <div class=\"col-12 mb-3\">\n <div\n class=\"col-12 d-flex flex-wrap justify-content-between align-items-center mt-4\">\n <h2 class=\"card-title p-0 float-start\">Support Center</h2>\n <a routerLink=\"/support-details/add\"\n aria-label=\"Navigate to Target\"\n class=\"btn btn-sm btn-outline-primary float-end\"\n tabindex=\"0\"\n (keydown)=\"$event.key === 'Enter' && $event.target.click()\"\n aria-expanded=\"false\">\n <i class=\"fa fa-plus-circle\"\n aria-hidden=\"true\"></i>\n Create new support request\n </a>\n </div>\n </div>\n <div class=\"col-12 my-3\">\n <h3>Previous support requests</h3>\n <p>Please note that responses to your support requests are sent directly to your email. You can simply reply to those\n emails for further assistance.</p>\n </div>\n @if (isLoading) {\n <div class=\"w-100 text-center mt-3\"\n >\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n @if (supports?.length) {\n <div class=\"col-12 mb-3\">\n <p-accordion>\n @for (item of supports; track item; let i = $index) {\n <p-accordion-panel [value]=\"i\">\n <p-accordion-header>{{ item?.created_at | dateFormat }} ({{ item?.user_name }}) {{ item?.title }}</p-accordion-header>\n <p-accordion-content>\n <p>{{ item?.description }}</p>\n <a [href]=\"item?.attachment?.version_200x200?.url\"\n target=\"_blank\">\n @if (item?.attachment?.version_200x200?.url) {\n <img alt=\"version_200x200\"\n [src]=\"item?.attachment?.version_200x200?.url\"\n class=\"img-fluid\" />\n }</a>\n </p-accordion-content>\n </p-accordion-panel>\n }\n </p-accordion>\n </div>\n }\n @if (!supports?.length && isLoaded) {\n <div class=\"col-12\"\n >\n <pw-no-data [withImage]=\"true\" message=\"No support requests found\"> </pw-no-data>\n </div>\n }\n </div>\n", styles: [".contact-support{font-size:24px;font-weight:600}\n"], dependencies: [{ kind: "directive", type:
|
|
2352
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: SupportComponent, isStandalone: false, selector: "pw-support", usesInheritance: true, ngImport: i0, template: "<div class=\"row m-3\">\n <div class=\"col-12 mb-3\">\n <div\n class=\"col-12 d-flex flex-wrap justify-content-between align-items-center mt-4\">\n <h2 class=\"card-title p-0 float-start\">Support Center</h2>\n <a routerLink=\"/support-details/add\"\n aria-label=\"Navigate to Target\"\n class=\"btn btn-sm btn-outline-primary float-end\"\n tabindex=\"0\"\n (keydown)=\"$event.key === 'Enter' && $event.target.click()\"\n aria-expanded=\"false\">\n <i class=\"fa fa-plus-circle\"\n aria-hidden=\"true\"></i>\n Create new support request\n </a>\n </div>\n </div>\n <div class=\"col-12 my-3\">\n <h3>Previous support requests</h3>\n <p>Please note that responses to your support requests are sent directly to your email. You can simply reply to those\n emails for further assistance.</p>\n </div>\n @if (isLoading) {\n <div class=\"w-100 text-center mt-3\"\n >\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n @if (supports?.length) {\n <div class=\"col-12 mb-3\">\n <p-accordion>\n @for (item of supports; track item; let i = $index) {\n <p-accordion-panel [value]=\"i\">\n <p-accordion-header>{{ item?.created_at | dateFormat }} ({{ item?.user_name }}) {{ item?.title }}</p-accordion-header>\n <p-accordion-content>\n <p>{{ item?.description }}</p>\n <a [href]=\"item?.attachment?.version_200x200?.url\"\n target=\"_blank\">\n @if (item?.attachment?.version_200x200?.url) {\n <img alt=\"version_200x200\"\n [src]=\"item?.attachment?.version_200x200?.url\"\n class=\"img-fluid\" />\n }</a>\n </p-accordion-content>\n </p-accordion-panel>\n }\n </p-accordion>\n </div>\n }\n @if (!supports?.length && isLoaded) {\n <div class=\"col-12\"\n >\n <pw-no-data [withImage]=\"true\" message=\"No support requests found\"> </pw-no-data>\n </div>\n }\n </div>\n", styles: [".contact-support{font-size:24px;font-weight:600}\n"], dependencies: [{ kind: "directive", type: i3.LazyImgDirective, selector: "img" }, { kind: "directive", type: i1.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "component", type: i5.NoDataComponent, selector: "pw-no-data", inputs: ["message", "description", "withImage"] }, { kind: "component", type: i2$2.Accordion, selector: "p-accordion", inputs: ["value", "multiple", "styleClass", "expandIcon", "collapseIcon", "selectOnFocus", "transitionOptions", "motionOptions"], outputs: ["valueChange", "onClose", "onOpen"] }, { kind: "component", type: i2$2.AccordionPanel, selector: "p-accordion-panel, p-accordionpanel", inputs: ["value", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: i2$2.AccordionHeader, selector: "p-accordion-header, p-accordionheader" }, { kind: "component", type: i2$2.AccordionContent, selector: "p-accordion-content, p-accordioncontent" }, { kind: "pipe", type: i6.DateFormatPipe, name: "dateFormat" }] }); }
|
|
2262
2353
|
}
|
|
2263
2354
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: SupportComponent, decorators: [{
|
|
2264
2355
|
type: Component,
|
|
@@ -2357,7 +2448,7 @@ class SupportDetailsComponent extends AppBaseComponent {
|
|
|
2357
2448
|
HelperService.onUploadError(event, this.toast);
|
|
2358
2449
|
}
|
|
2359
2450
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: SupportDetailsComponent, deps: [{ token: i0.Injector }, { token: i1$2.CommonService }, { token: i1$2.AuthService }, { token: i0.Renderer2 }, { token: i0.ElementRef }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2360
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: SupportDetailsComponent, isStandalone: false, selector: "pw-support-details", usesInheritance: true, ngImport: i0, template: "<div class=\"container-fluid pw-tab overflow-hidden\">\n <div class=\"dashboard\">\n <div class=\"dashboard-body\">\n <div class=\"me-auto col-xs-6 mt-4\">\n <a aria-label=\"Navigate to Target\" (click)=\"back()\" class=\"previous\"><i\n class=\"fa fa-arrow-alt-circle-left\" aria-hidden=\"true\"></i></a>\n <h3 class=\"mt-3\">{{ 'Label.NewSupport' | transloco }}</h3>\n </div>\n <div class=\"p-2 m-1 mt-3\">\n <form [formGroup]=\"form\"\n (ngSubmit)=\"onSave()\">\n <div class=\"row\">\n <div class=\"col-12\">\n <pw-input-container controlId=\"support-details-title\"\n label=\"title\"\n name=\"title\"\n errorMsg=\"Title is required\">\n <input type=\"text\"\n id=\"support-details-title\"\n class=\"form-control\"\n [placeholder]=\"'Support.Placeholder.Title' | transloco\"\n formControlName=\"title\" />\n </pw-input-container>\n </div>\n <div class=\"col-12\">\n <pw-input-container controlId=\"support-details-description\"\n label=\"Description\"\n errorMsg=\"description is required\"\n name=\"description\">\n <textarea rows=\"3\"\n id=\"support-details-description\"\n type=\"text\"\n class=\"form-control\"\n [placeholder]=\"'Support.Placeholder.Description' | transloco\"\n formControlName=\"description\"></textarea>\n </pw-input-container>\n </div>\n <div class=\"col-12\">\n <div class=\"mb-3 file-upload-support-details\">\n <span id=\"support-details-file-label\" class=\"pw-label-style\">Upload Picture</span>\n <p-fileUpload #forms\n [attr.aria-labelledby]=\"'support-details-file-label'\"\n name=\"myfile[]\"\n [customUpload]=\"true\"\n [showUploadButton]=\"false\"\n accept=\"image/*\"\n [disabled]=\"uploadedFiles && uploadedFiles.length > 0\"\n (onSelect)=\"onSelect($event)\"\n (onRemove)=\"onRemove($event)\"\n (onError)=\"onUploadError($event)\">\n <ng-template pTemplate=\"content\">\n @if (!uploadedFiles?.length) {\n <div class=\"drag-drop-text\">\n <p>You can drag and drop your file here</p>\n </div>\n }\n </ng-template>\n </p-fileUpload>\n </div>\n </div>\n @if (isLoading) {\n <div class=\"w-100 text-center mt-3\"\n >\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n <div class=\"col-12 text-end mt-3\">\n @if (isSubmitClicked) {\n <div class=\"support-details-captcha\">\n <ngx-recaptcha2 [ngModelOptions]=\"{ standalone: true }\"\n [siteKey]=\"siteKey\"\n size=\"normal\"\n [(ngModel)]=\"recaptcha\"\n (success)=\"handleSuccess($event)\">\n </ngx-recaptcha2>\n </div>\n }\n @if (!isSubmitClicked) {\n <button type=\"button\"\n class=\"btn btn-outline-default me-2\"\n (click)=\"back()\">\n {{ 'Button.Cancel' | transloco }}\n </button>\n <button type=\"submit\"\n class=\"btn btn-primary\" [disabled]=\"invalidFile\">\n {{ 'Button.Submit' | transloco }}\n </button>\n }\n </div>\n </div>\n </form>\n </div>\n </div>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";::ng-deep .file-upload-support-details .p-fileupload .p-fileupload-content{padding:4rem 1rem}::ng-deep .file-upload-support-details .p-fileupload-content .p-fileupload-files .p-fileupload-row>:first-child{display:none}.support-details-captcha{text-align:-webkit-right}:host .pw-label-style{display:block;height:18px;line-height:18px;margin-bottom:8px}.drag-drop-text{padding:20px;border:2px dashed #ccc;text-align:center;color:#aaa;margin-top:10px}::ng-deep .file-upload-support-details .p-fileupload .p-fileupload-content{padding:1rem}::ng-deep .file-upload-support-details .p-fileupload-content .p-fileupload-files .p-fileupload-row>:first-child{display:flex}\n"], dependencies: [{ kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i5$2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: i4
|
|
2451
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: SupportDetailsComponent, isStandalone: false, selector: "pw-support-details", usesInheritance: true, ngImport: i0, template: "<div class=\"container-fluid pw-tab overflow-hidden\">\n <div class=\"dashboard\">\n <div class=\"dashboard-body\">\n <div class=\"me-auto col-xs-6 mt-4\">\n <a aria-label=\"Navigate to Target\" (click)=\"back()\" class=\"previous\"><i\n class=\"fa fa-arrow-alt-circle-left\" aria-hidden=\"true\"></i></a>\n <h3 class=\"mt-3\">{{ 'Label.NewSupport' | transloco }}</h3>\n </div>\n <div class=\"p-2 m-1 mt-3\">\n <form [formGroup]=\"form\"\n (ngSubmit)=\"onSave()\">\n <div class=\"row\">\n <div class=\"col-12\">\n <pw-input-container controlId=\"support-details-title\"\n label=\"title\"\n name=\"title\"\n errorMsg=\"Title is required\">\n <input type=\"text\"\n id=\"support-details-title\"\n class=\"form-control\"\n [placeholder]=\"'Support.Placeholder.Title' | transloco\"\n formControlName=\"title\" />\n </pw-input-container>\n </div>\n <div class=\"col-12\">\n <pw-input-container controlId=\"support-details-description\"\n label=\"Description\"\n errorMsg=\"description is required\"\n name=\"description\">\n <textarea rows=\"3\"\n id=\"support-details-description\"\n type=\"text\"\n class=\"form-control\"\n [placeholder]=\"'Support.Placeholder.Description' | transloco\"\n formControlName=\"description\"></textarea>\n </pw-input-container>\n </div>\n <div class=\"col-12\">\n <div class=\"mb-3 file-upload-support-details\">\n <span id=\"support-details-file-label\" class=\"pw-label-style\">Upload Picture</span>\n <p-fileUpload #forms\n [attr.aria-labelledby]=\"'support-details-file-label'\"\n name=\"myfile[]\"\n [customUpload]=\"true\"\n [showUploadButton]=\"false\"\n accept=\"image/*\"\n [disabled]=\"uploadedFiles && uploadedFiles.length > 0\"\n (onSelect)=\"onSelect($event)\"\n (onRemove)=\"onRemove($event)\"\n (onError)=\"onUploadError($event)\">\n <ng-template pTemplate=\"content\">\n @if (!uploadedFiles?.length) {\n <div class=\"drag-drop-text\">\n <p>You can drag and drop your file here</p>\n </div>\n }\n </ng-template>\n </p-fileUpload>\n </div>\n </div>\n @if (isLoading) {\n <div class=\"w-100 text-center mt-3\"\n >\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n <div class=\"col-12 text-end mt-3\">\n @if (isSubmitClicked) {\n <div class=\"support-details-captcha\">\n <ngx-recaptcha2 [ngModelOptions]=\"{ standalone: true }\"\n [siteKey]=\"siteKey\"\n size=\"normal\"\n [(ngModel)]=\"recaptcha\"\n (success)=\"handleSuccess($event)\">\n </ngx-recaptcha2>\n </div>\n }\n @if (!isSubmitClicked) {\n <button type=\"button\"\n class=\"btn btn-outline-default me-2\"\n (click)=\"back()\">\n {{ 'Button.Cancel' | transloco }}\n </button>\n <button type=\"submit\"\n class=\"btn btn-primary\" [disabled]=\"invalidFile\">\n {{ 'Button.Submit' | transloco }}\n </button>\n }\n </div>\n </div>\n </form>\n </div>\n </div>\n </div>\n</div>\n", styles: ["@charset \"UTF-8\";::ng-deep .file-upload-support-details .p-fileupload .p-fileupload-content{padding:4rem 1rem}::ng-deep .file-upload-support-details .p-fileupload-content .p-fileupload-files .p-fileupload-row>:first-child{display:none}.support-details-captcha{text-align:-webkit-right}:host .pw-label-style{display:block;height:18px;line-height:18px;margin-bottom:8px}.drag-drop-text{padding:20px;border:2px dashed #ccc;text-align:center;color:#aaa;margin-top:10px}::ng-deep .file-upload-support-details .p-fileupload .p-fileupload-content{padding:1rem}::ng-deep .file-upload-support-details .p-fileupload-content .p-fileupload-files .p-fileupload-row>:first-child{display:flex}\n"], dependencies: [{ kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i5$2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i5.InputContainerComponent, selector: "pw-input-container", inputs: ["name", "controlId", "useAriaLabelledbyOnly", "label", "labelClass", "tooltipPosition", "required", "errorMsg", "isReadOnly", "showTooltip", "tooltipText", "showTriangle", "afterLabel", "showAfterLabel", "showTriangleText", "isLeftTooltip"] }, { kind: "component", type: i6$1.ReCaptcha2Component, selector: "ngx-recaptcha2", inputs: ["theme", "size"] }, { kind: "component", type: i7$1.FileUpload, selector: "p-fileupload, p-fileUpload", inputs: ["name", "url", "method", "multiple", "accept", "disabled", "auto", "withCredentials", "maxFileSize", "invalidFileSizeMessageSummary", "invalidFileSizeMessageDetail", "invalidFileTypeMessageSummary", "invalidFileTypeMessageDetail", "invalidFileLimitMessageDetail", "invalidFileLimitMessageSummary", "style", "styleClass", "previewWidth", "chooseLabel", "uploadLabel", "cancelLabel", "chooseIcon", "uploadIcon", "cancelIcon", "showUploadButton", "showCancelButton", "mode", "headers", "customUpload", "fileLimit", "uploadStyleClass", "cancelStyleClass", "removeStyleClass", "chooseStyleClass", "chooseButtonProps", "uploadButtonProps", "cancelButtonProps", "files"], outputs: ["onBeforeUpload", "onSend", "onUpload", "onError", "onClear", "onRemove", "onSelect", "onProgress", "uploadHandler", "onImageError", "onRemoveUploadedFile"] }, { kind: "pipe", type: i8$2.TranslocoPipe, name: "transloco" }] }); }
|
|
2361
2452
|
}
|
|
2362
2453
|
__decorate([
|
|
2363
2454
|
ValidateForm('form'),
|
|
@@ -2457,7 +2548,7 @@ class EditPortfoliosComponent {
|
|
|
2457
2548
|
HelperService.onUploadError(event);
|
|
2458
2549
|
}
|
|
2459
2550
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: EditPortfoliosComponent, deps: [{ token: i1$1.NgbModal }, { token: i1$2.ProfileService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2460
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: EditPortfoliosComponent, isStandalone: false, selector: "pw-edit-portfolios", inputs: { id: "id", slug: "slug" }, outputs: { successEvent: "successEvent" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, static: true }, { propertyName: "uploader", first: true, predicate: ["form"], descendants: true }], ngImport: i0, template: "<ng-template #content\n let-modal>\n <div class=\"modal-header\">\n <h4 class=\"modal-title\"\n id=\"modal-basic-title\">Add/Edit Portfolio Item</h4>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n Add a cover image or a downloadable file for your portfolio item\n <p-fileUpload #form\n name=\"myfile[]\"\n [customUpload]=\"true\"\n [showUploadButton]=\"false\"\n accept=\"\"\n [disabled]=\"uploadedFiles && uploadedFiles.length > 0\"\n (onSelect)=\"onSelect($event)\"\n (onRemove)=\"onRemove($event)\"\n (onError)=\"onUploadError($event)\">\n <ng-template pTemplate=\"content\">\n @if (!uploadedFiles?.length) {\n <div class=\"drag-drop-text\">\n <p>You can drag and drop your file here</p>\n </div>\n }\n </ng-template>\n </p-fileUpload>\n <div class=\"ui-fileupload-content ui-widget-content ui-corner-bottom\">\n <div class=\"ui-fileupload-files\">\n <div class=\"\">\n <h5>Uploaded Pictures</h5>\n @for (image of projectPictures; track trackByImage($index, image)) {\n <div\n class=\"ui-fileupload-row d-inline-block\">\n <div>\n <img [src]=\"image?.picture?.version_50x50?.url\"\n alt=\"\"\n width=\"50\" />\n </div>\n <div class=\"pt-1 ps-1\">\n <button icon=\"pi pi-times\"\n type=\"button\"\n (click)=\"deleteProjectPicture(image.id)\"\n class=\"ui-button ui-widget ui-state-default ui-corner-all ui-button-icon-only\">\n <span class=\"ui-button-icon-left ui-clickable pi pi-times\"></span>\n </button>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\"\n class=\"btn btn-outline-default\"\n (click)=\"modal.close()\">\n Cancel\n </button>\n <button type=\"button\"\n class=\"btn btn-primary\"\n [buttonBusy]=\"busy\"\n (click)=\"onSave(form)\">\n Save\n </button>\n </div>\n</ng-template>\n", styles: [".drag-drop-text{padding:20px;border:2px dashed #ccc;text-align:center;color:#aaa;margin-top:10px}\n"], dependencies: [{ kind: "directive", type:
|
|
2551
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: EditPortfoliosComponent, isStandalone: false, selector: "pw-edit-portfolios", inputs: { id: "id", slug: "slug" }, outputs: { successEvent: "successEvent" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, static: true }, { propertyName: "uploader", first: true, predicate: ["form"], descendants: true }], ngImport: i0, template: "<ng-template #content\n let-modal>\n <div class=\"modal-header\">\n <h4 class=\"modal-title\"\n id=\"modal-basic-title\">Add/Edit Portfolio Item</h4>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n Add a cover image or a downloadable file for your portfolio item\n <p-fileUpload #form\n name=\"myfile[]\"\n [customUpload]=\"true\"\n [showUploadButton]=\"false\"\n accept=\"\"\n [disabled]=\"uploadedFiles && uploadedFiles.length > 0\"\n (onSelect)=\"onSelect($event)\"\n (onRemove)=\"onRemove($event)\"\n (onError)=\"onUploadError($event)\">\n <ng-template pTemplate=\"content\">\n @if (!uploadedFiles?.length) {\n <div class=\"drag-drop-text\">\n <p>You can drag and drop your file here</p>\n </div>\n }\n </ng-template>\n </p-fileUpload>\n <div class=\"ui-fileupload-content ui-widget-content ui-corner-bottom\">\n <div class=\"ui-fileupload-files\">\n <div class=\"\">\n <h5>Uploaded Pictures</h5>\n @for (image of projectPictures; track trackByImage($index, image)) {\n <div\n class=\"ui-fileupload-row d-inline-block\">\n <div>\n <img [src]=\"image?.picture?.version_50x50?.url\"\n alt=\"\"\n width=\"50\" />\n </div>\n <div class=\"pt-1 ps-1\">\n <button icon=\"pi pi-times\"\n type=\"button\"\n (click)=\"deleteProjectPicture(image.id)\"\n class=\"ui-button ui-widget ui-state-default ui-corner-all ui-button-icon-only\">\n <span class=\"ui-button-icon-left ui-clickable pi pi-times\"></span>\n </button>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\"\n class=\"btn btn-outline-default\"\n (click)=\"modal.close()\">\n Cancel\n </button>\n <button type=\"button\"\n class=\"btn btn-primary\"\n [buttonBusy]=\"busy\"\n (click)=\"onSave(form)\">\n Save\n </button>\n </div>\n</ng-template>\n", styles: [".drag-drop-text{padding:20px;border:2px dashed #ccc;text-align:center;color:#aaa;margin-top:10px}\n"], dependencies: [{ kind: "directive", type: i3.ButtonBusyDirective, selector: "[buttonBusy]", inputs: ["buttonBusy", "busyText"] }, { kind: "directive", type: i3.LazyImgDirective, selector: "img" }, { kind: "directive", type: i5$2.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "component", type: i7$1.FileUpload, selector: "p-fileupload, p-fileUpload", inputs: ["name", "url", "method", "multiple", "accept", "disabled", "auto", "withCredentials", "maxFileSize", "invalidFileSizeMessageSummary", "invalidFileSizeMessageDetail", "invalidFileTypeMessageSummary", "invalidFileTypeMessageDetail", "invalidFileLimitMessageDetail", "invalidFileLimitMessageSummary", "style", "styleClass", "previewWidth", "chooseLabel", "uploadLabel", "cancelLabel", "chooseIcon", "uploadIcon", "cancelIcon", "showUploadButton", "showCancelButton", "mode", "headers", "customUpload", "fileLimit", "uploadStyleClass", "cancelStyleClass", "removeStyleClass", "chooseStyleClass", "chooseButtonProps", "uploadButtonProps", "cancelButtonProps", "files"], outputs: ["onBeforeUpload", "onSend", "onUpload", "onError", "onClear", "onRemove", "onSelect", "onProgress", "uploadHandler", "onImageError", "onRemoveUploadedFile"] }] }); }
|
|
2461
2552
|
}
|
|
2462
2553
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: EditPortfoliosComponent, decorators: [{
|
|
2463
2554
|
type: Component,
|
|
@@ -2595,7 +2686,7 @@ class EditProjectModalComponent extends AppBaseComponent {
|
|
|
2595
2686
|
});
|
|
2596
2687
|
}
|
|
2597
2688
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: EditProjectModalComponent, deps: [{ token: i1$1.NgbModal }, { token: i2.UntypedFormBuilder }, { token: i1$2.ProfileService }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2598
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.6", type: EditProjectModalComponent, isStandalone: false, selector: "pw-edit-project-modal", outputs: { cancelEvent: "cancelEvent", saveEvent: "saveEvent" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<ng-template #content\n let-modal>\n <div class=\"modal-header\">\n <h4 class=\"modal-title\"\n id=\"modal-basic-title\">{{ title }}</h4>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n <form [formGroup]=\"form\">\n <div class=\"row p-2\">\n <!-- Title -->\n <pw-input-container class=\"col-12\"\n controlId=\"edit-project-title\"\n label=\"Title\"\n name=\"title\"\n errorMsg=\"This field is required.\">\n <input type=\"text\"\n id=\"edit-project-title\"\n class=\"form-control\"\n formControlName=\"title\"\n [placeholder]=\"'User.Profile.Projects.Placeholder.Title' | transloco\"\n [ngClass]=\"{ 'is-invalid': submitted && f.title.errors }\" />\n </pw-input-container>\n <!-- Client Name -->\n <pw-input-container class=\"col-12\"\n controlId=\"edit-project-client_name\"\n label=\"Client Name\"\n name=\"client_name\"\n errorMsg=\"This field is required.\">\n <input type=\"text\"\n id=\"edit-project-client_name\"\n class=\"form-control\"\n formControlName=\"client_name\"\n [placeholder]=\"'User.Profile.Projects.Placeholder.ClientName' | transloco\"\n [ngClass]=\"{ 'is-invalid': submitted && f.client_name.errors }\" />\n </pw-input-container>\n <!-- Project Start Year -->\n <pw-input-container class=\"col-12 col-md-4\"\n controlId=\"edit-project-start_year\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"Start\"\n name=\"start_year\"\n errorMsg=\"YYYY format date is required\">\n <p-select\n [attr.aria-labelledby]=\"'edit-project-start_year-label'\"\n (onShow)=\"getStartYear()\"\n formControlName=\"start_year\"\n [options]=\"startYears\"\n [placeholder]=\"'User.Profile.Projects.Placeholder.StartYear' | transloco\"\n (onChange)=\"getEndYears($event.value)\"\n [ngClass]=\"{ 'is-invalid': submitted && f.start_year.errors }\">\n </p-select>\n </pw-input-container>\n <!-- Project End Year -->\n <pw-input-container class=\"col-12 col-md-4\"\n controlId=\"edit-project-end_year\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"End\"\n name=\"end_year\"\n errorMsg=\"YYYY format date is required\">\n <p-select\n [attr.aria-labelledby]=\"'edit-project-end_year-label'\"\n formControlName=\"end_year\"\n [options]=\"endYears\"\n [placeholder]=\"'User.Profile.Projects.Placeholder.EndYear' | transloco\"\n (onChange)=\"getEndYears($event.value)\"\n [ngClass]=\"{ 'is-invalid': submitted && f.end_year.errors }\">\n </p-select>\n </pw-input-container>\n <!-- Total Weeks Worked -->\n <pw-input-container class=\"col-12 col-md-4\"\n controlId=\"edit-project-length\"\n label=\"Weeks worked\"\n name=\"length\"\n errorMsg=\"This field is required. (0-5000)\">\n <input type=\"number\"\n id=\"edit-project-length\"\n formControlName=\"length\"\n class=\"form-control\"\n [ngClass]=\"{ 'is-invalid': submitted && f.length.errors }\" />\n </pw-input-container>\n <!-- Description -->\n <pw-input-container class=\"col-12\"\n controlId=\"edit-project-description\"\n label=\"Description\"\n name=\"description\"\n errorMsg=\"This field is required.\">\n <textarea type=\"text\"\n id=\"edit-project-description\"\n class=\"form-control\"\n formControlName=\"description\"\n required\n [placeholder]=\"'User.Profile.Projects.Placeholder.Description' | transloco\"\n [ngClass]=\"{ 'is-invalid': submitted && f.description.errors }\"></textarea>\n </pw-input-container>\n </div>\n </form>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\"\n class=\"btn btn-outline-default\"\n (click)=\"modal.close()\">\n Cancel\n </button>\n <button type=\"submit\"\n [buttonBusy]=\"buttonBusy\"\n class=\"btn btn-primary\"\n (click)=\"onSaveDetail()\">Save</button>\n </div>\n</ng-template>\n", styles: [".ng-valid.is-invalid{background-image:none;border-color:inherit}\n"], dependencies: [{ kind: "directive", type:
|
|
2689
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.6", type: EditProjectModalComponent, isStandalone: false, selector: "pw-edit-project-modal", outputs: { cancelEvent: "cancelEvent", saveEvent: "saveEvent" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<ng-template #content\n let-modal>\n <div class=\"modal-header\">\n <h4 class=\"modal-title\"\n id=\"modal-basic-title\">{{ title }}</h4>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n <form [formGroup]=\"form\">\n <div class=\"row p-2\">\n <!-- Title -->\n <pw-input-container class=\"col-12\"\n controlId=\"edit-project-title\"\n label=\"Title\"\n name=\"title\"\n errorMsg=\"This field is required.\">\n <input type=\"text\"\n id=\"edit-project-title\"\n class=\"form-control\"\n formControlName=\"title\"\n [placeholder]=\"'User.Profile.Projects.Placeholder.Title' | transloco\"\n [ngClass]=\"{ 'is-invalid': submitted && f.title.errors }\" />\n </pw-input-container>\n <!-- Client Name -->\n <pw-input-container class=\"col-12\"\n controlId=\"edit-project-client_name\"\n label=\"Client Name\"\n name=\"client_name\"\n errorMsg=\"This field is required.\">\n <input type=\"text\"\n id=\"edit-project-client_name\"\n class=\"form-control\"\n formControlName=\"client_name\"\n [placeholder]=\"'User.Profile.Projects.Placeholder.ClientName' | transloco\"\n [ngClass]=\"{ 'is-invalid': submitted && f.client_name.errors }\" />\n </pw-input-container>\n <!-- Project Start Year -->\n <pw-input-container class=\"col-12 col-md-4\"\n controlId=\"edit-project-start_year\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"Start\"\n name=\"start_year\"\n errorMsg=\"YYYY format date is required\">\n <p-select\n [attr.aria-labelledby]=\"'edit-project-start_year-label'\"\n (onShow)=\"getStartYear()\"\n formControlName=\"start_year\"\n [options]=\"startYears\"\n [placeholder]=\"'User.Profile.Projects.Placeholder.StartYear' | transloco\"\n (onChange)=\"getEndYears($event.value)\"\n [ngClass]=\"{ 'is-invalid': submitted && f.start_year.errors }\">\n </p-select>\n </pw-input-container>\n <!-- Project End Year -->\n <pw-input-container class=\"col-12 col-md-4\"\n controlId=\"edit-project-end_year\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"End\"\n name=\"end_year\"\n errorMsg=\"YYYY format date is required\">\n <p-select\n [attr.aria-labelledby]=\"'edit-project-end_year-label'\"\n formControlName=\"end_year\"\n [options]=\"endYears\"\n [placeholder]=\"'User.Profile.Projects.Placeholder.EndYear' | transloco\"\n (onChange)=\"getEndYears($event.value)\"\n [ngClass]=\"{ 'is-invalid': submitted && f.end_year.errors }\">\n </p-select>\n </pw-input-container>\n <!-- Total Weeks Worked -->\n <pw-input-container class=\"col-12 col-md-4\"\n controlId=\"edit-project-length\"\n label=\"Weeks worked\"\n name=\"length\"\n errorMsg=\"This field is required. (0-5000)\">\n <input type=\"number\"\n id=\"edit-project-length\"\n formControlName=\"length\"\n class=\"form-control\"\n [ngClass]=\"{ 'is-invalid': submitted && f.length.errors }\" />\n </pw-input-container>\n <!-- Description -->\n <pw-input-container class=\"col-12\"\n controlId=\"edit-project-description\"\n label=\"Description\"\n name=\"description\"\n errorMsg=\"This field is required.\">\n <textarea type=\"text\"\n id=\"edit-project-description\"\n class=\"form-control\"\n formControlName=\"description\"\n required\n [placeholder]=\"'User.Profile.Projects.Placeholder.Description' | transloco\"\n [ngClass]=\"{ 'is-invalid': submitted && f.description.errors }\"></textarea>\n </pw-input-container>\n </div>\n </form>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\"\n class=\"btn btn-outline-default\"\n (click)=\"modal.close()\">\n Cancel\n </button>\n <button type=\"submit\"\n [buttonBusy]=\"buttonBusy\"\n class=\"btn btn-primary\"\n (click)=\"onSaveDetail()\">Save</button>\n </div>\n</ng-template>\n", styles: [".ng-valid.is-invalid{background-image:none;border-color:inherit}\n"], dependencies: [{ kind: "directive", type: i3.ButtonBusyDirective, selector: "[buttonBusy]", inputs: ["buttonBusy", "busyText"] }, { kind: "directive", type: i8.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i8$1.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i5.InputContainerComponent, selector: "pw-input-container", inputs: ["name", "controlId", "useAriaLabelledbyOnly", "label", "labelClass", "tooltipPosition", "required", "errorMsg", "isReadOnly", "showTooltip", "tooltipText", "showTriangle", "afterLabel", "showAfterLabel", "showTriangleText", "isLeftTooltip"] }, { kind: "pipe", type: i8$2.TranslocoPipe, name: "transloco" }] }); }
|
|
2599
2690
|
}
|
|
2600
2691
|
__decorate([
|
|
2601
2692
|
ValidateForm('form'),
|
|
@@ -2703,7 +2794,7 @@ class EditQualificationsModalComponent extends AppBaseComponent {
|
|
|
2703
2794
|
});
|
|
2704
2795
|
}
|
|
2705
2796
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: EditQualificationsModalComponent, deps: [{ token: i1$1.NgbModal }, { token: i2.UntypedFormBuilder }, { token: i1$2.QualificationService }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2706
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.6", type: EditQualificationsModalComponent, isStandalone: false, selector: "pw-edit-qualifications-modal", outputs: { saveEvent: "saveEvent" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<ng-template #content\n let-modal>\n <div class=\"modal-header\">\n <h4 class=\"modal-title\"\n id=\"modal-basic-title\">{{ title }}</h4>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n <form [formGroup]=\"form\">\n <div class=\"row p-2\">\n <pw-input-container class=\"col-12\"\n controlId=\"edit-qualifications-school\"\n label=\"School\"\n name=\"school\"\n errorMsg=\"This field is required.\">\n <input type=\"text\"\n id=\"edit-qualifications-school\"\n class=\"form-control\"\n [placeholder]=\"'User.Profile.Qualifications.Placeholder.School' | transloco\"\n formControlName=\"school\" />\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-qualifications-started_on\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"Dates Attended\"\n name=\"started_on\"\n errorMsg=\"This field is required.\">\n <div class=\"ui-fluid\">\n <p-datepicker inputId=\"edit-qualifications-started_on\" formControlName=\"started_on\"\n [attr.aria-labelledby]=\"'edit-qualifications-started_on-label'\"\n [monthNavigator]=\"true\"\n [yearNavigator]=\"true\"\n yearRange=\"1950:2020\"\n (onSelect)=\"onDateChange()\"\n [showIcon]=\"true\"\n placeholder=\"yyyy-mm-dd\"\n dateFormat=\"yy-mm-dd\">\n </p-datepicker>\n </div>\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-qualifications-ended_on\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"Dates Completed\"\n name=\"ended_on\"\n errorMsg=\"This field is required.\">\n <div class=\"ui-fluid\">\n <p-datepicker inputId=\"edit-qualifications-ended_on\" formControlName=\"ended_on\"\n [attr.aria-labelledby]=\"'edit-qualifications-ended_on-label'\"\n [monthNavigator]=\"true\"\n [yearNavigator]=\"true\"\n [showIcon]=\"true\"\n (onSelect)=\"onDateChange()\"\n [minDate]=\"minToDate\"\n placeholder=\"yyyy-mm-dd\"\n dateFormat=\"yy-mm-dd\"\n yearRange=\"1950:2025\"></p-datepicker>\n </div>\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-qualifications-points\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"Degree\"\n name=\"points\"\n errorMsg=\"This field is required.\">\n <p-select inputId=\"edit-qualifications-points\"\n [options]=\"qualifications\"\n [attr.aria-labelledby]=\"'edit-qualifications-points-label'\"\n [placeholder]=\"'User.Profile.Qualifications.Placeholder.Degree' | transloco\"\n formControlName=\"points\"></p-select>\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-qualifications-course\"\n label=\"Course\"\n name=\"course\"\n errorMsg=\"This field is required.\">\n <input type=\"text\"\n id=\"edit-qualifications-course\"\n class=\"form-control\"\n [placeholder]=\"'User.Profile.Qualifications.Placeholder.Course' | transloco\"\n formControlName=\"course\" />\n </pw-input-container>\n\n <pw-input-container class=\"col-12\"\n controlId=\"edit-qualifications-description\"\n label=\"Description\"\n name=\"description\">\n <textarea type=\"text\"\n id=\"edit-qualifications-description\"\n class=\"form-control\"\n [placeholder]=\"'User.Profile.Qualifications.Placeholder.Description' | transloco\"\n formControlName=\"description\"></textarea>\n </pw-input-container>\n </div>\n </form>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\"\n class=\"btn btn-outline-default\"\n (click)=\"modal.close()\">\n Cancel\n </button>\n <button type=\"submit\"\n [buttonBusy]=\"buttonBusy\"\n class=\"btn btn-primary\"\n (click)=\"onSaveDetail()\">Save</button>\n </div>\n</ng-template>\n\n<i\n class=\"fa fa-lg pi pi-plus-circle float-end mt-2 pt-1 pt-md-0 profile-icons\"\n data-cy=\"add-qualification\"\n (keydown.enter)=\"onOpen()\"\n aria-label=\"Add Qualification\"\n (click)=\"onOpen()\"\n aria-hidden=\"true\"\n></i>\n", styles: ["@charset \"UTF-8\";:root{--first: rgb(23 105 225);--second: rgb(54 194 131);--third: rgb(255 171 0);--text: rgb(34 34 34);--tabs_bg: rgb(23 105 225);--tabs_sub_bg: rgb(70, 136, 236);--tabs_text: rgb(255 255 255);--titles: rgb(34 34 34);--sidebar_bg: rgb(0, 48, 63);--sidebar_text: rgb(255 255 255)}.btn-add{cursor:pointer;font-size:24px}.profile-icons{color:var(--first)}\n"], dependencies: [{ kind: "directive", type:
|
|
2797
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.6", type: EditQualificationsModalComponent, isStandalone: false, selector: "pw-edit-qualifications-modal", outputs: { saveEvent: "saveEvent" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<ng-template #content\n let-modal>\n <div class=\"modal-header\">\n <h4 class=\"modal-title\"\n id=\"modal-basic-title\">{{ title }}</h4>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n <form [formGroup]=\"form\">\n <div class=\"row p-2\">\n <pw-input-container class=\"col-12\"\n controlId=\"edit-qualifications-school\"\n label=\"School\"\n name=\"school\"\n errorMsg=\"This field is required.\">\n <input type=\"text\"\n id=\"edit-qualifications-school\"\n class=\"form-control\"\n [placeholder]=\"'User.Profile.Qualifications.Placeholder.School' | transloco\"\n formControlName=\"school\" />\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-qualifications-started_on\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"Dates Attended\"\n name=\"started_on\"\n errorMsg=\"This field is required.\">\n <div class=\"ui-fluid\">\n <p-datepicker inputId=\"edit-qualifications-started_on\" formControlName=\"started_on\"\n [attr.aria-labelledby]=\"'edit-qualifications-started_on-label'\"\n [monthNavigator]=\"true\"\n [yearNavigator]=\"true\"\n yearRange=\"1950:2020\"\n (onSelect)=\"onDateChange()\"\n [showIcon]=\"true\"\n placeholder=\"yyyy-mm-dd\"\n dateFormat=\"yy-mm-dd\">\n </p-datepicker>\n </div>\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-qualifications-ended_on\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"Dates Completed\"\n name=\"ended_on\"\n errorMsg=\"This field is required.\">\n <div class=\"ui-fluid\">\n <p-datepicker inputId=\"edit-qualifications-ended_on\" formControlName=\"ended_on\"\n [attr.aria-labelledby]=\"'edit-qualifications-ended_on-label'\"\n [monthNavigator]=\"true\"\n [yearNavigator]=\"true\"\n [showIcon]=\"true\"\n (onSelect)=\"onDateChange()\"\n [minDate]=\"minToDate\"\n placeholder=\"yyyy-mm-dd\"\n dateFormat=\"yy-mm-dd\"\n yearRange=\"1950:2025\"></p-datepicker>\n </div>\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-qualifications-points\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"Degree\"\n name=\"points\"\n errorMsg=\"This field is required.\">\n <p-select inputId=\"edit-qualifications-points\"\n [options]=\"qualifications\"\n [attr.aria-labelledby]=\"'edit-qualifications-points-label'\"\n [placeholder]=\"'User.Profile.Qualifications.Placeholder.Degree' | transloco\"\n formControlName=\"points\"></p-select>\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-qualifications-course\"\n label=\"Course\"\n name=\"course\"\n errorMsg=\"This field is required.\">\n <input type=\"text\"\n id=\"edit-qualifications-course\"\n class=\"form-control\"\n [placeholder]=\"'User.Profile.Qualifications.Placeholder.Course' | transloco\"\n formControlName=\"course\" />\n </pw-input-container>\n\n <pw-input-container class=\"col-12\"\n controlId=\"edit-qualifications-description\"\n label=\"Description\"\n name=\"description\">\n <textarea type=\"text\"\n id=\"edit-qualifications-description\"\n class=\"form-control\"\n [placeholder]=\"'User.Profile.Qualifications.Placeholder.Description' | transloco\"\n formControlName=\"description\"></textarea>\n </pw-input-container>\n </div>\n </form>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\"\n class=\"btn btn-outline-default\"\n (click)=\"modal.close()\">\n Cancel\n </button>\n <button type=\"submit\"\n [buttonBusy]=\"buttonBusy\"\n class=\"btn btn-primary\"\n (click)=\"onSaveDetail()\">Save</button>\n </div>\n</ng-template>\n\n<i\n class=\"fa fa-lg pi pi-plus-circle float-end mt-2 pt-1 pt-md-0 profile-icons\"\n data-cy=\"add-qualification\"\n (keydown.enter)=\"onOpen()\"\n aria-label=\"Add Qualification\"\n (click)=\"onOpen()\"\n aria-hidden=\"true\"\n></i>\n", styles: ["@charset \"UTF-8\";:root{--first: rgb(23 105 225);--second: rgb(54 194 131);--third: rgb(255 171 0);--text: rgb(34 34 34);--tabs_bg: rgb(23 105 225);--tabs_sub_bg: rgb(70, 136, 236);--tabs_text: rgb(255 255 255);--titles: rgb(34 34 34);--sidebar_bg: rgb(0, 48, 63);--sidebar_text: rgb(255 255 255)}.btn-add{cursor:pointer;font-size:24px}.profile-icons{color:var(--first)}\n"], dependencies: [{ kind: "directive", type: i3.ButtonBusyDirective, selector: "[buttonBusy]", inputs: ["buttonBusy", "busyText"] }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i8$1.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i5.InputContainerComponent, selector: "pw-input-container", inputs: ["name", "controlId", "useAriaLabelledbyOnly", "label", "labelClass", "tooltipPosition", "required", "errorMsg", "isReadOnly", "showTooltip", "tooltipText", "showTriangle", "afterLabel", "showAfterLabel", "showTriangleText", "isLeftTooltip"] }, { kind: "component", type: i7$2.DatePicker, selector: "p-datePicker, p-datepicker, p-date-picker", inputs: ["iconDisplay", "styleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "ariaLabelledBy", "ariaLabel", "iconAriaLabel", "dateFormat", "multipleSeparator", "rangeSeparator", "inline", "showOtherMonths", "selectOtherMonths", "showIcon", "icon", "readonlyInput", "shortYearCutoff", "hourFormat", "timeOnly", "stepHour", "stepMinute", "stepSecond", "showSeconds", "showOnFocus", "showWeek", "startWeekFromFirstDayOfYear", "showClear", "dataType", "selectionMode", "maxDateCount", "showButtonBar", "todayButtonStyleClass", "clearButtonStyleClass", "autofocus", "autoZIndex", "baseZIndex", "panelStyleClass", "panelStyle", "keepInvalid", "hideOnDateTimeSelect", "touchUI", "timeSeparator", "focusTrap", "showTransitionOptions", "hideTransitionOptions", "tabindex", "minDate", "maxDate", "disabledDates", "disabledDays", "showTime", "responsiveOptions", "numberOfMonths", "firstDayOfWeek", "view", "defaultDate", "appendTo", "motionOptions"], outputs: ["onFocus", "onBlur", "onClose", "onSelect", "onClear", "onInput", "onTodayClick", "onClearClick", "onMonthChange", "onYearChange", "onClickOutside", "onShow"] }, { kind: "pipe", type: i8$2.TranslocoPipe, name: "transloco" }] }); }
|
|
2707
2798
|
}
|
|
2708
2799
|
__decorate([
|
|
2709
2800
|
ValidateForm('form'),
|
|
@@ -2771,7 +2862,7 @@ class EditRecommendationModalComponent {
|
|
|
2771
2862
|
});
|
|
2772
2863
|
}
|
|
2773
2864
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: EditRecommendationModalComponent, deps: [{ token: i1$1.NgbModal }, { token: i2.UntypedFormBuilder }, { token: i1$2.ProfileService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2774
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.6", type: EditRecommendationModalComponent, isStandalone: false, selector: "pw-edit-recommendation-modal", inputs: { user: "user" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, static: true }], ngImport: i0, template: "<ng-template #content\n let-modal>\n <div class=\"modal-header\">\n <h4 class=\"modal-title\"\n id=\"modal-basic-title\">{{ title }}</h4>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n <form [formGroup]=\"form\">\n <div class=\"row p-2\">\n <pw-input-container class=\"col-12 col-md-4\"\n controlId=\"edit-recommendation-quality\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"Quality\"\n name=\"quality\"\n errorMsg=\"This field is required.\">\n <p-rating formControlName=\"quality\"\n [attr.aria-labelledby]=\"'edit-recommendation-quality-label'\"\n [cancel]=\"false\"></p-rating>\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-4\"\n controlId=\"edit-recommendation-communication\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"Communication\"\n name=\"communication\"\n errorMsg=\"This field is required.\">\n <p-rating formControlName=\"communication\"\n [attr.aria-labelledby]=\"'edit-recommendation-communication-label'\"\n [cancel]=\"false\"></p-rating>\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-4\"\n controlId=\"edit-recommendation-time\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"Time\"\n name=\"time\"\n errorMsg=\"This field is required.\">\n <p-rating formControlName=\"time\"\n [attr.aria-labelledby]=\"'edit-recommendation-time-label'\"\n [cancel]=\"false\"></p-rating>\n </pw-input-container>\n\n <pw-input-container class=\"col-12\"\n controlId=\"edit-recommendation-description\"\n label=\"Description\"\n name=\"description\"\n errorMsg=\"This field is required.\">\n <textarea type=\"text\"\n id=\"edit-recommendation-description\"\n class=\"form-control\"\n formControlName=\"description\"></textarea>\n </pw-input-container>\n </div>\n </form>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\"\n class=\"btn btn-outline-default\"\n (click)=\"modal.close()\">\n Cancel\n </button>\n <button type=\"submit\"\n [buttonBusy]=\"buttonBusy\"\n class=\"btn btn-primary\"\n (click)=\"onSaveDetail()\">Save</button>\n </div>\n</ng-template>\n\n<!-- <i class=\"fal fa-plus-circle fa-2x btn-link float-end btn-add\" (click)=\"onOpen()\" aria-hidden=\"true\"></i> -->\n", dependencies: [{ kind: "directive", type:
|
|
2865
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.6", type: EditRecommendationModalComponent, isStandalone: false, selector: "pw-edit-recommendation-modal", inputs: { user: "user" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, static: true }], ngImport: i0, template: "<ng-template #content\n let-modal>\n <div class=\"modal-header\">\n <h4 class=\"modal-title\"\n id=\"modal-basic-title\">{{ title }}</h4>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n <form [formGroup]=\"form\">\n <div class=\"row p-2\">\n <pw-input-container class=\"col-12 col-md-4\"\n controlId=\"edit-recommendation-quality\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"Quality\"\n name=\"quality\"\n errorMsg=\"This field is required.\">\n <p-rating formControlName=\"quality\"\n [attr.aria-labelledby]=\"'edit-recommendation-quality-label'\"\n [cancel]=\"false\"></p-rating>\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-4\"\n controlId=\"edit-recommendation-communication\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"Communication\"\n name=\"communication\"\n errorMsg=\"This field is required.\">\n <p-rating formControlName=\"communication\"\n [attr.aria-labelledby]=\"'edit-recommendation-communication-label'\"\n [cancel]=\"false\"></p-rating>\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-4\"\n controlId=\"edit-recommendation-time\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"Time\"\n name=\"time\"\n errorMsg=\"This field is required.\">\n <p-rating formControlName=\"time\"\n [attr.aria-labelledby]=\"'edit-recommendation-time-label'\"\n [cancel]=\"false\"></p-rating>\n </pw-input-container>\n\n <pw-input-container class=\"col-12\"\n controlId=\"edit-recommendation-description\"\n label=\"Description\"\n name=\"description\"\n errorMsg=\"This field is required.\">\n <textarea type=\"text\"\n id=\"edit-recommendation-description\"\n class=\"form-control\"\n formControlName=\"description\"></textarea>\n </pw-input-container>\n </div>\n </form>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\"\n class=\"btn btn-outline-default\"\n (click)=\"modal.close()\">\n Cancel\n </button>\n <button type=\"submit\"\n [buttonBusy]=\"buttonBusy\"\n class=\"btn btn-primary\"\n (click)=\"onSaveDetail()\">Save</button>\n </div>\n</ng-template>\n\n<!-- <i class=\"fal fa-plus-circle fa-2x btn-link float-end btn-add\" (click)=\"onOpen()\" aria-hidden=\"true\"></i> -->\n", dependencies: [{ kind: "directive", type: i3.ButtonBusyDirective, selector: "[buttonBusy]", inputs: ["buttonBusy", "busyText"] }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i5.InputContainerComponent, selector: "pw-input-container", inputs: ["name", "controlId", "useAriaLabelledbyOnly", "label", "labelClass", "tooltipPosition", "required", "errorMsg", "isReadOnly", "showTooltip", "tooltipText", "showTriangle", "afterLabel", "showAfterLabel", "showTriangleText", "isLeftTooltip"] }, { kind: "component", type: i6$2.Rating, selector: "p-rating", inputs: ["readonly", "stars", "iconOnClass", "iconOnStyle", "iconOffClass", "iconOffStyle", "autofocus"], outputs: ["onRate", "onFocus", "onBlur"] }] }); }
|
|
2775
2866
|
}
|
|
2776
2867
|
__decorate([
|
|
2777
2868
|
ValidateForm('form'),
|
|
@@ -2874,7 +2965,7 @@ class EditSkillsModalComponent extends AppBaseComponent {
|
|
|
2874
2965
|
});
|
|
2875
2966
|
}
|
|
2876
2967
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: EditSkillsModalComponent, deps: [{ token: i1$1.NgbModal }, { token: i1$2.TagService }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2877
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.6", type: EditSkillsModalComponent, isStandalone: false, selector: "pw-edit-skills-modal", inputs: { userId: "userId", slug: "slug", entityType: "entityType", entityEntity: "entityEntity" }, outputs: { saveEvent: "saveEvent" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<ng-template #content\n let-modal>\n <div class=\"modal-header\">\n <h4 class=\"modal-title\"\n id=\"modal-basic-title\">My Skills</h4>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n <div class=\"ui-fluid skills-modal skills-dropdown\">\n <p-autoComplete appendTo=\"body\" [(ngModel)]=\"selectedSkills\"\n [suggestions]=\"searchSkills\"\n dataKey=\"id\"\n optionLabel=\"name\"\n (completeMethod)=\"search($event)\"\n styleClass=\"w-100\"\n [minLength]=\"1\"\n [maxlength]=\"10\"\n placeholder=\"Skills\"\n [dropdown]=\"true\"\n [multiple]=\"true\"></p-autoComplete>\n\n <small class=\"p-2\">Select up to 10 skills.</small>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\"\n class=\"btn btn-outline-default\"\n (click)=\"close(modal)\">Cancel</button>\n <button type=\"button\"\n class=\"btn btn-primary\"\n (click)=\"saveUserSkills()\">Save</button>\n </div>\n</ng-template>\n", dependencies: [{ kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "component", type: i4$
|
|
2968
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.6", type: EditSkillsModalComponent, isStandalone: false, selector: "pw-edit-skills-modal", inputs: { userId: "userId", slug: "slug", entityType: "entityType", entityEntity: "entityEntity" }, outputs: { saveEvent: "saveEvent" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<ng-template #content\n let-modal>\n <div class=\"modal-header\">\n <h4 class=\"modal-title\"\n id=\"modal-basic-title\">My Skills</h4>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n <div class=\"ui-fluid skills-modal skills-dropdown\">\n <p-autoComplete appendTo=\"body\" [(ngModel)]=\"selectedSkills\"\n [suggestions]=\"searchSkills\"\n dataKey=\"id\"\n optionLabel=\"name\"\n (completeMethod)=\"search($event)\"\n styleClass=\"w-100\"\n [minLength]=\"1\"\n [maxlength]=\"10\"\n placeholder=\"Skills\"\n [dropdown]=\"true\"\n [multiple]=\"true\"></p-autoComplete>\n\n <small class=\"p-2\">Select up to 10 skills.</small>\n </div>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\"\n class=\"btn btn-outline-default\"\n (click)=\"close(modal)\">Cancel</button>\n <button type=\"button\"\n class=\"btn btn-primary\"\n (click)=\"saveUserSkills()\">Save</button>\n </div>\n</ng-template>\n", dependencies: [{ kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "component", type: i4$3.AutoComplete, selector: "p-autoComplete, p-autocomplete, p-auto-complete", inputs: ["minLength", "minQueryLength", "delay", "panelStyle", "styleClass", "panelStyleClass", "inputStyle", "inputId", "inputStyleClass", "placeholder", "readonly", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "autoHighlight", "forceSelection", "type", "autoZIndex", "baseZIndex", "ariaLabel", "dropdownAriaLabel", "ariaLabelledBy", "dropdownIcon", "unique", "group", "completeOnFocus", "showClear", "dropdown", "showEmptyMessage", "dropdownMode", "multiple", "addOnTab", "tabindex", "dataKey", "emptyMessage", "showTransitionOptions", "hideTransitionOptions", "autofocus", "autocomplete", "optionGroupChildren", "optionGroupLabel", "overlayOptions", "suggestions", "optionLabel", "optionValue", "id", "searchMessage", "emptySelectionMessage", "selectionMessage", "autoOptionFocus", "selectOnFocus", "searchLocale", "optionDisabled", "focusOnHover", "typeahead", "addOnBlur", "separator", "appendTo", "motionOptions"], outputs: ["completeMethod", "onSelect", "onUnselect", "onAdd", "onFocus", "onBlur", "onDropdownClick", "onClear", "onInputKeydown", "onKeyUp", "onShow", "onHide", "onLazyLoad"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); }
|
|
2878
2969
|
}
|
|
2879
2970
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: EditSkillsModalComponent, decorators: [{
|
|
2880
2971
|
type: Component,
|
|
@@ -2960,7 +3051,7 @@ class EditSocialLinksComponent extends AppBaseComponent {
|
|
|
2960
3051
|
});
|
|
2961
3052
|
}
|
|
2962
3053
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: EditSocialLinksComponent, deps: [{ token: i0.Injector }, { token: i1$1.NgbModal }, { token: i2.UntypedFormBuilder }, { token: i1$2.ProfileService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2963
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.6", type: EditSocialLinksComponent, isStandalone: false, selector: "pw-edit-social-links", inputs: { links: "links", userId: "userId" }, outputs: { saveEvent: "saveEvent" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<ng-template #content\n let-modal>\n <div class=\"modal-header\">\n <h4 class=\"modal-title\"\n id=\"modal-basic-title\">Tell us your external portfolio</h4>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n <form [formGroup]=\"form\"\n class=\"p-sm-3\"\n (ngSubmit)=\"onSaveDetail()\">\n <div>\n <p>\n Please tell us where we can find more information about you or about your\n work/projects. This will impact your ranking on the site.\n </p>\n </div>\n\n <div class=\"row mt-0\">\n <div class=\"col-sm-6 col-12\">\n <div class=\"mb-3\">\n <label for=\"external-portfolio-linkedin\"><img src=\"/assets/img/icons/social/linkedin.svg\"\n width=\"20\"\n alt=\"\" />\n LinkedIn</label>\n <input type=\"url\"\n id=\"external-portfolio-linkedin\"\n name=\"linkedin\"\n formControlName=\"linkedin\"\n class=\"form-control\"\n placeholder=\"https://linkedin.com/in/nickname\"\n autocomplete=\"url\" />\n </div>\n </div>\n\n <div class=\"col-sm-6 col-12\">\n <div class=\"mb-3\">\n <label for=\"external-portfolio-twitter\"><img src=\"/assets/img/icons/social/twitter.svg\"\n width=\"20\"\n alt=\"\" />\n Twitter</label>\n <input type=\"url\"\n id=\"external-portfolio-twitter\"\n name=\"twitter\"\n formControlName=\"twitter\"\n class=\"form-control\"\n placeholder=\"https://twitter.com/nickname\"\n autocomplete=\"url\" />\n </div>\n </div>\n\n <div class=\"col-sm-6 col-12\">\n <div class=\"mb-3\">\n <label for=\"external-portfolio-facebook\"><img src=\"/assets/img/icons/social/facebook.svg\"\n width=\"20\"\n alt=\"\" />\n Facebook</label>\n <input type=\"url\"\n id=\"external-portfolio-facebook\"\n name=\"facebook\"\n formControlName=\"facebook\"\n class=\"form-control\"\n placeholder=\"https://www.facebook.com/nickname\"\n autocomplete=\"url\" />\n </div>\n </div>\n\n <div class=\"col-sm-6 col-12\">\n <div class=\"mb-3\">\n <label for=\"external-portfolio-youtube\"><img src=\"/assets/img/icons/social/youtube.svg\"\n width=\"20\"\n alt=\"\" />\n YouTube</label>\n <input type=\"url\"\n id=\"external-portfolio-youtube\"\n name=\"youtube\"\n formControlName=\"youtube\"\n class=\"form-control\"\n placeholder=\"https://www.youtube.com/nickname\"\n autocomplete=\"url\" />\n </div>\n </div>\n\n <div class=\"col-sm-6 col-12\">\n <div class=\"mb-3\">\n <label for=\"external-portfolio-skype\">\n <img src=\"/assets/img/icons/social/skype.svg\"\n width=\"20\"\n alt=\"\" /> Skype\n </label>\n <input type=\"url\"\n id=\"external-portfolio-skype\"\n name=\"skype\"\n formControlName=\"skype\"\n class=\"form-control\"\n placeholder=\"https://www.skype.com/nickname\"\n autocomplete=\"url\" />\n </div>\n </div>\n\n <div class=\"col-sm-6 col-12\">\n <div class=\"mb-3\">\n <label for=\"external-portfolio-github\"><img src=\"/assets/img/icons/social/github.svg\"\n width=\"20\"\n alt=\"\" />\n Github</label>\n <input type=\"url\"\n id=\"external-portfolio-github\"\n name=\"github\"\n formControlName=\"github\"\n class=\"form-control\"\n placeholder=\"https://github.com/nickname\"\n autocomplete=\"url\" />\n </div>\n </div>\n\n <div class=\"col-sm-6 col-12\">\n <div class=\"mb-3\">\n <label for=\"external-portfolio-stackoverflow\"><img src=\"/assets/img/icons/social/stackoverflow.svg\"\n width=\"20\"\n alt=\"\" />\n StackOverflow</label>\n <input type=\"url\"\n id=\"external-portfolio-stackoverflow\"\n name=\"stackoverflow\"\n formControlName=\"stackoverflow\"\n class=\"form-control\"\n placeholder=\"http://stackoverflow.com/users/nickname\"\n autocomplete=\"url\" />\n </div>\n </div>\n </div>\n </form>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\"\n class=\"btn btn-outline-default\"\n (click)=\"modal.close()\">\n Cancel\n </button>\n <button type=\"submit\"\n [buttonBusy]=\"buttonBusy\"\n class=\"btn btn-primary\"\n (click)=\"onSaveDetail()\">Save</button>\n </div>\n</ng-template>\n", dependencies: [{ kind: "directive", type:
|
|
3054
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.6", type: EditSocialLinksComponent, isStandalone: false, selector: "pw-edit-social-links", inputs: { links: "links", userId: "userId" }, outputs: { saveEvent: "saveEvent" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<ng-template #content\n let-modal>\n <div class=\"modal-header\">\n <h4 class=\"modal-title\"\n id=\"modal-basic-title\">Tell us your external portfolio</h4>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n <form [formGroup]=\"form\"\n class=\"p-sm-3\"\n (ngSubmit)=\"onSaveDetail()\">\n <div>\n <p>\n Please tell us where we can find more information about you or about your\n work/projects. This will impact your ranking on the site.\n </p>\n </div>\n\n <div class=\"row mt-0\">\n <div class=\"col-sm-6 col-12\">\n <div class=\"mb-3\">\n <label for=\"external-portfolio-linkedin\"><img src=\"/assets/img/icons/social/linkedin.svg\"\n width=\"20\"\n alt=\"\" />\n LinkedIn</label>\n <input type=\"url\"\n id=\"external-portfolio-linkedin\"\n name=\"linkedin\"\n formControlName=\"linkedin\"\n class=\"form-control\"\n placeholder=\"https://linkedin.com/in/nickname\"\n autocomplete=\"url\" />\n </div>\n </div>\n\n <div class=\"col-sm-6 col-12\">\n <div class=\"mb-3\">\n <label for=\"external-portfolio-twitter\"><img src=\"/assets/img/icons/social/twitter.svg\"\n width=\"20\"\n alt=\"\" />\n Twitter</label>\n <input type=\"url\"\n id=\"external-portfolio-twitter\"\n name=\"twitter\"\n formControlName=\"twitter\"\n class=\"form-control\"\n placeholder=\"https://twitter.com/nickname\"\n autocomplete=\"url\" />\n </div>\n </div>\n\n <div class=\"col-sm-6 col-12\">\n <div class=\"mb-3\">\n <label for=\"external-portfolio-facebook\"><img src=\"/assets/img/icons/social/facebook.svg\"\n width=\"20\"\n alt=\"\" />\n Facebook</label>\n <input type=\"url\"\n id=\"external-portfolio-facebook\"\n name=\"facebook\"\n formControlName=\"facebook\"\n class=\"form-control\"\n placeholder=\"https://www.facebook.com/nickname\"\n autocomplete=\"url\" />\n </div>\n </div>\n\n <div class=\"col-sm-6 col-12\">\n <div class=\"mb-3\">\n <label for=\"external-portfolio-youtube\"><img src=\"/assets/img/icons/social/youtube.svg\"\n width=\"20\"\n alt=\"\" />\n YouTube</label>\n <input type=\"url\"\n id=\"external-portfolio-youtube\"\n name=\"youtube\"\n formControlName=\"youtube\"\n class=\"form-control\"\n placeholder=\"https://www.youtube.com/nickname\"\n autocomplete=\"url\" />\n </div>\n </div>\n\n <div class=\"col-sm-6 col-12\">\n <div class=\"mb-3\">\n <label for=\"external-portfolio-skype\">\n <img src=\"/assets/img/icons/social/skype.svg\"\n width=\"20\"\n alt=\"\" /> Skype\n </label>\n <input type=\"url\"\n id=\"external-portfolio-skype\"\n name=\"skype\"\n formControlName=\"skype\"\n class=\"form-control\"\n placeholder=\"https://www.skype.com/nickname\"\n autocomplete=\"url\" />\n </div>\n </div>\n\n <div class=\"col-sm-6 col-12\">\n <div class=\"mb-3\">\n <label for=\"external-portfolio-github\"><img src=\"/assets/img/icons/social/github.svg\"\n width=\"20\"\n alt=\"\" />\n Github</label>\n <input type=\"url\"\n id=\"external-portfolio-github\"\n name=\"github\"\n formControlName=\"github\"\n class=\"form-control\"\n placeholder=\"https://github.com/nickname\"\n autocomplete=\"url\" />\n </div>\n </div>\n\n <div class=\"col-sm-6 col-12\">\n <div class=\"mb-3\">\n <label for=\"external-portfolio-stackoverflow\"><img src=\"/assets/img/icons/social/stackoverflow.svg\"\n width=\"20\"\n alt=\"\" />\n StackOverflow</label>\n <input type=\"url\"\n id=\"external-portfolio-stackoverflow\"\n name=\"stackoverflow\"\n formControlName=\"stackoverflow\"\n class=\"form-control\"\n placeholder=\"http://stackoverflow.com/users/nickname\"\n autocomplete=\"url\" />\n </div>\n </div>\n </div>\n </form>\n </div>\n <div class=\"modal-footer\">\n <button type=\"button\"\n class=\"btn btn-outline-default\"\n (click)=\"modal.close()\">\n Cancel\n </button>\n <button type=\"submit\"\n [buttonBusy]=\"buttonBusy\"\n class=\"btn btn-primary\"\n (click)=\"onSaveDetail()\">Save</button>\n </div>\n</ng-template>\n", dependencies: [{ kind: "directive", type: i3.ButtonBusyDirective, selector: "[buttonBusy]", inputs: ["buttonBusy", "busyText"] }, { kind: "directive", type: i3.LazyImgDirective, selector: "img" }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] }); }
|
|
2964
3055
|
}
|
|
2965
3056
|
__decorate([
|
|
2966
3057
|
ValidateForm('form'),
|
|
@@ -3085,7 +3176,7 @@ class EditUserProfileModalComponent extends AppBaseComponent {
|
|
|
3085
3176
|
});
|
|
3086
3177
|
}
|
|
3087
3178
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: EditUserProfileModalComponent, deps: [{ token: i1$1.NgbModal }, { token: i2.UntypedFormBuilder }, { token: i1$2.ProfileService }, { token: i1$2.GeoService }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3088
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: EditUserProfileModalComponent, isStandalone: false, selector: "pw-edit-user-profile-modal", inputs: { slug: "slug", user: "user" }, outputs: { saveEvent: "saveEvent" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, static: true }, { propertyName: "placesRef", first: true, predicate: ["ngxPlaces"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<ng-template #content\n let-modal>\n <div class=\"modal-header\">\n <h4 class=\"modal-title\"\n id=\"modal-basic-title\">Edit Intro</h4>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n <form [formGroup]=\"form\"\n (ngSubmit)=\"onSaveDetail()\">\n <div class=\"row\">\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-intro-first-name\"\n label=\"First Name\"\n name=\"first_name\"\n errorMsg=\"Please enter first Name\">\n <input type=\"text\"\n class=\"form-control\"\n formControlName=\"first_name\"\n id=\"edit-intro-first-name\"\n [placeholder]=\"'User.Profile.Intro.Placeholder.FirstName' | transloco\"\n autocomplete=\"given-name\" name=\"input_first_name_1\"/>\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-intro-last-name\"\n label=\"Last Name\"\n name=\"last_name\"\n errorMsg=\"Please enter last Name\">\n <input type=\"text\"\n class=\"form-control\"\n formControlName=\"last_name\"\n id=\"edit-intro-last-name\"\n [placeholder]=\"'User.Profile.Intro.Placeholder.LastName' | transloco\"\n autocomplete=\"family-name\" name=\"input_last_name_2\"/>\n </pw-input-container>\n\n <pw-input-container class=\"col-12\"\n controlId=\"edit-intro-headline\"\n label=\"Headline\"\n name=\"headline\"\n errorMsg=\"Please enter headline\">\n <input type=\"text\"\n class=\"form-control\"\n formControlName=\"headline\"\n id=\"edit-intro-headline\"\n [placeholder]=\"'User.Profile.Intro.Placeholder.Headline' | transloco\" name=\"input_headline_3\"/>\n </pw-input-container>\n\n <pw-input-container class=\"col-12\"\n controlId=\"edit-intro-description\"\n label=\"About me\"\n name=\"description\"\n errorMsg=\"Please enter description\">\n <textarea class=\"form-control\"\n id=\"edit-intro-description\"\n name=\"description\"\n [placeholder]=\"'User.Profile.Intro.Placeholder.Description' | transloco\"\n formControlName=\"description\"></textarea>\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-intro-gender\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"Gender\"\n name=\"gender\"\n errorMsg=\"Please enter Gender\">\n <p-selectButton [options]=\"[\n { label: 'Male', value: 'M' },\n { label: 'Female', value: 'F' }\n ]\"\n [attr.aria-labelledby]=\"'edit-intro-gender-label'\"\n formControlName=\"gender\"></p-selectButton>\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-intro-dob\"\n label=\"Date of Birth\"\n name=\"dob\"\n errorMsg=\"Please enter date of birth\">\n <div class=\"input-group\">\n <input class=\"form-control\"\n id=\"edit-intro-dob\"\n name=\"dob\"\n placeholder=\"yyyy-mm-dd\"\n formControlName=\"dob\"\n ngbDatepicker\n #d=\"ngbDatepicker\"\n [minDate]=\"{ year: 1950, month: 1, day: 1 }\"\n [maxDate]=\"{ year: 2018, month: 12, day: 31 }\"\n autocomplete=\"off\" />\n <button class=\"btn btn-primary\"\n type=\"button\"\n aria-label=\"Open date picker\"\n (click)=\"d.toggle()\">\n <i class=\"fa fa-calendar\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-intro-phone\"\n label=\"Phone\"\n name=\"phone_number\"\n errorMsg=\"Please enter phone\">\n <input type=\"text\"\n class=\"form-control\"\n formControlName=\"phone_number\"\n id=\"edit-intro-phone\"\n name=\"phone_number\"\n [placeholder]=\"'User.Profile.Intro.Placeholder.Phone' | transloco\"\n autocomplete=\"tel\" />\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-intro-postcode\"\n label=\"Postcode\"\n name=\"postcode\"\n errorMsg=\"Please enter postcode\">\n <input type=\"text\"\n class=\"form-control\"\n formControlName=\"postcode\"\n id=\"edit-intro-postcode\"\n [placeholder]=\"'User.Profile.Intro.Placeholder.Postcode' | transloco\"\n autocomplete=\"postal-code\" name=\"input_postcode_6\"/>\n </pw-input-container>\n\n @if (countries$ | async; as countries) {\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-intro-country\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"Country\"\n name=\"country\"\n errorMsg=\"Please select a country\">\n <p-select\n [attr.aria-labelledby]=\"'edit-intro-country-label'\"\n [options]=\"countries\"\n optionLabel=\"name\"\n optionValue=\"code\"\n formControlName=\"country\"\n (onChange)=\"getRegion($event.value)\"\n [placeholder]=\"'User.Profile.SelectCountry' | transloco\">\n </p-select>\n </pw-input-container>\n }\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-intro-state\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"State\"\n name=\"state\"\n errorMsg=\"Please select a state\">\n <p-select\n [attr.aria-labelledby]=\"'edit-intro-state-label'\"\n [options]=\"states\"\n optionLabel=\"name\"\n optionValue=\"code\"\n formControlName=\"state\"\n [placeholder]=\"'User.Profile.SelectState' | transloco\">\n </p-select>\n </pw-input-container>\n\n <!-- Location -->\n <pw-input-container label=\"Location\"\n class=\"col-12 col-md-6\"\n controlId=\"edit-intro-location\"\n [useAriaLabelledbyOnly]=\"true\"\n name=\"location\">\n <input ngx-gp-autocomplete\n id=\"edit-intro-location\"\n name=\"location\"\n class=\"form-control\"\n #places=\"ngx-places\"\n formControlName=\"location\"\n [placeholder]=\"'User.Profile.Intro.Placeholder.Location' | transloco\"\n [attr.aria-labelledby]=\"'edit-intro-location-label'\"\n (onAddressChange)=\"handleAddressChange($event)\" />\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-intro-website\"\n label=\"Website\"\n name=\"website_url\"\n errorMsg=\"Please enter Website\">\n <input type=\"text\"\n class=\"form-control\"\n formControlName=\"website_url\"\n id=\"edit-intro-website\"\n [placeholder]=\"'User.Profile.Intro.Placeholder.Website' | transloco\"\n autocomplete=\"url\" name=\"input_website_url_8\"/>\n </pw-input-container>\n </div>\n <div class=\"modal-footer\">\n <input type=\"button\"\n class=\"btn btn-outline-default me-2\"\n (click)=\"modal.close()\"\n value=\"Cancel\" id=\"input_field_9\" name=\"input_field_9\"/>\n <input type=\"submit\"\n [buttonBusy]=\"buttonBusy\"\n class=\"btn btn-primary\"\n value=\"Save Changes\" id=\"input_field_10\" name=\"input_field_10\"/>\n </div>\n </form>\n </div>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:root{--first: rgb(23 105 225);--second: rgb(54 194 131);--third: rgb(255 171 0);--text: rgb(34 34 34);--tabs_bg: rgb(23 105 225);--tabs_sub_bg: rgb(70, 136, 236);--tabs_text: rgb(255 255 255);--titles: rgb(34 34 34);--sidebar_bg: rgb(0, 48, 63);--sidebar_text: rgb(255 255 255)}::ng-deep .p-selectbutton .p-button{margin-right:1rem}::ng-deep body .p-selectbutton .p-button.p-highlight{background-color:var(--first)!important}\n"], dependencies: [{ kind: "directive", type: i4.ButtonBusyDirective, selector: "[buttonBusy]", inputs: ["buttonBusy", "busyText"] }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i6$1.NgxGpAutocompleteDirective, selector: "[ngx-gp-autocomplete]", inputs: ["options"], outputs: ["onAddressChange"], exportAs: ["ngx-places"] }, { kind: "component", type: i6$2.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i5.InputContainerComponent, selector: "pw-input-container", inputs: ["name", "controlId", "useAriaLabelledbyOnly", "label", "labelClass", "tooltipPosition", "required", "errorMsg", "isReadOnly", "showTooltip", "tooltipText", "showTriangle", "afterLabel", "showAfterLabel", "showTriangleText", "isLeftTooltip"] }, { kind: "component", type: i8$1.SelectButton, selector: "p-selectButton, p-selectbutton, p-select-button", inputs: ["options", "optionLabel", "optionValue", "optionDisabled", "unselectable", "tabindex", "multiple", "allowEmpty", "styleClass", "ariaLabelledBy", "dataKey", "autofocus", "size", "fluid"], outputs: ["onOptionClick", "onChange"] }, { kind: "directive", type: i1$1.NgbInputDatepicker, selector: "input[ngbDatepicker]", inputs: ["autoClose", "contentTemplate", "datepickerClass", "dayTemplate", "dayTemplateData", "displayMonths", "firstDayOfWeek", "footerTemplate", "markDisabled", "minDate", "maxDate", "navigation", "outsideDays", "placement", "popperOptions", "restoreFocus", "showWeekNumbers", "startDate", "container", "positionTarget", "weekdays", "disabled"], outputs: ["dateSelect", "navigate", "closed"], exportAs: ["ngbDatepicker"] }, { kind: "pipe", type: i6.AsyncPipe, name: "async" }, { kind: "pipe", type: i8.TranslocoPipe, name: "transloco" }] }); }
|
|
3179
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: EditUserProfileModalComponent, isStandalone: false, selector: "pw-edit-user-profile-modal", inputs: { slug: "slug", user: "user" }, outputs: { saveEvent: "saveEvent" }, viewQueries: [{ propertyName: "content", first: true, predicate: ["content"], descendants: true, static: true }, { propertyName: "placesRef", first: true, predicate: ["ngxPlaces"], descendants: true }], usesInheritance: true, ngImport: i0, template: "<ng-template #content\n let-modal>\n <div class=\"modal-header\">\n <h4 class=\"modal-title\"\n id=\"modal-basic-title\">Edit Intro</h4>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"modal-body\">\n <form [formGroup]=\"form\"\n (ngSubmit)=\"onSaveDetail()\">\n <div class=\"row\">\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-intro-first-name\"\n label=\"First Name\"\n name=\"first_name\"\n errorMsg=\"Please enter first Name\">\n <input type=\"text\"\n class=\"form-control\"\n formControlName=\"first_name\"\n id=\"edit-intro-first-name\"\n [placeholder]=\"'User.Profile.Intro.Placeholder.FirstName' | transloco\"\n autocomplete=\"given-name\" name=\"input_first_name_1\"/>\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-intro-last-name\"\n label=\"Last Name\"\n name=\"last_name\"\n errorMsg=\"Please enter last Name\">\n <input type=\"text\"\n class=\"form-control\"\n formControlName=\"last_name\"\n id=\"edit-intro-last-name\"\n [placeholder]=\"'User.Profile.Intro.Placeholder.LastName' | transloco\"\n autocomplete=\"family-name\" name=\"input_last_name_2\"/>\n </pw-input-container>\n\n <pw-input-container class=\"col-12\"\n controlId=\"edit-intro-headline\"\n label=\"Headline\"\n name=\"headline\"\n errorMsg=\"Please enter headline\">\n <input type=\"text\"\n class=\"form-control\"\n formControlName=\"headline\"\n id=\"edit-intro-headline\"\n [placeholder]=\"'User.Profile.Intro.Placeholder.Headline' | transloco\" name=\"input_headline_3\"/>\n </pw-input-container>\n\n <pw-input-container class=\"col-12\"\n controlId=\"edit-intro-description\"\n label=\"About me\"\n name=\"description\"\n errorMsg=\"Please enter description\">\n <textarea class=\"form-control\"\n id=\"edit-intro-description\"\n name=\"description\"\n [placeholder]=\"'User.Profile.Intro.Placeholder.Description' | transloco\"\n formControlName=\"description\"></textarea>\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-intro-gender\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"Gender\"\n name=\"gender\"\n errorMsg=\"Please enter Gender\">\n <p-selectButton [options]=\"[\n { label: 'Male', value: 'M' },\n { label: 'Female', value: 'F' }\n ]\"\n [attr.aria-labelledby]=\"'edit-intro-gender-label'\"\n formControlName=\"gender\"></p-selectButton>\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-intro-dob\"\n label=\"Date of Birth\"\n name=\"dob\"\n errorMsg=\"Please enter date of birth\">\n <div class=\"input-group\">\n <input class=\"form-control\"\n id=\"edit-intro-dob\"\n name=\"dob\"\n placeholder=\"yyyy-mm-dd\"\n formControlName=\"dob\"\n ngbDatepicker\n #d=\"ngbDatepicker\"\n [minDate]=\"{ year: 1950, month: 1, day: 1 }\"\n [maxDate]=\"{ year: 2018, month: 12, day: 31 }\"\n autocomplete=\"off\" />\n <button class=\"btn btn-primary\"\n type=\"button\"\n aria-label=\"Open date picker\"\n (click)=\"d.toggle()\">\n <i class=\"fa fa-calendar\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-intro-phone\"\n label=\"Phone\"\n name=\"phone_number\"\n errorMsg=\"Please enter phone\">\n <input type=\"text\"\n class=\"form-control\"\n formControlName=\"phone_number\"\n id=\"edit-intro-phone\"\n name=\"phone_number\"\n [placeholder]=\"'User.Profile.Intro.Placeholder.Phone' | transloco\"\n autocomplete=\"tel\" />\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-intro-postcode\"\n label=\"Postcode\"\n name=\"postcode\"\n errorMsg=\"Please enter postcode\">\n <input type=\"text\"\n class=\"form-control\"\n formControlName=\"postcode\"\n id=\"edit-intro-postcode\"\n [placeholder]=\"'User.Profile.Intro.Placeholder.Postcode' | transloco\"\n autocomplete=\"postal-code\" name=\"input_postcode_6\"/>\n </pw-input-container>\n\n @if (countries$ | async; as countries) {\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-intro-country\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"Country\"\n name=\"country\"\n errorMsg=\"Please select a country\">\n <p-select\n [attr.aria-labelledby]=\"'edit-intro-country-label'\"\n [options]=\"countries\"\n optionLabel=\"name\"\n optionValue=\"code\"\n formControlName=\"country\"\n (onChange)=\"getRegion($event.value)\"\n [placeholder]=\"'User.Profile.SelectCountry' | transloco\">\n </p-select>\n </pw-input-container>\n }\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-intro-state\"\n [useAriaLabelledbyOnly]=\"true\"\n label=\"State\"\n name=\"state\"\n errorMsg=\"Please select a state\">\n <p-select\n [attr.aria-labelledby]=\"'edit-intro-state-label'\"\n [options]=\"states\"\n optionLabel=\"name\"\n optionValue=\"code\"\n formControlName=\"state\"\n [placeholder]=\"'User.Profile.SelectState' | transloco\">\n </p-select>\n </pw-input-container>\n\n <!-- Location -->\n <pw-input-container label=\"Location\"\n class=\"col-12 col-md-6\"\n controlId=\"edit-intro-location\"\n [useAriaLabelledbyOnly]=\"true\"\n name=\"location\">\n <input ngx-gp-autocomplete\n id=\"edit-intro-location\"\n name=\"location\"\n class=\"form-control\"\n #places=\"ngx-places\"\n formControlName=\"location\"\n [placeholder]=\"'User.Profile.Intro.Placeholder.Location' | transloco\"\n [attr.aria-labelledby]=\"'edit-intro-location-label'\"\n (onAddressChange)=\"handleAddressChange($event)\" />\n </pw-input-container>\n\n <pw-input-container class=\"col-12 col-md-6\"\n controlId=\"edit-intro-website\"\n label=\"Website\"\n name=\"website_url\"\n errorMsg=\"Please enter Website\">\n <input type=\"text\"\n class=\"form-control\"\n formControlName=\"website_url\"\n id=\"edit-intro-website\"\n [placeholder]=\"'User.Profile.Intro.Placeholder.Website' | transloco\"\n autocomplete=\"url\" name=\"input_website_url_8\"/>\n </pw-input-container>\n </div>\n <div class=\"modal-footer\">\n <input type=\"button\"\n class=\"btn btn-outline-default me-2\"\n (click)=\"modal.close()\"\n value=\"Cancel\" id=\"input_field_9\" name=\"input_field_9\"/>\n <input type=\"submit\"\n [buttonBusy]=\"buttonBusy\"\n class=\"btn btn-primary\"\n value=\"Save Changes\" id=\"input_field_10\" name=\"input_field_10\"/>\n </div>\n </form>\n </div>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:root{--first: rgb(23 105 225);--second: rgb(54 194 131);--third: rgb(255 171 0);--text: rgb(34 34 34);--tabs_bg: rgb(23 105 225);--tabs_sub_bg: rgb(70, 136, 236);--tabs_text: rgb(255 255 255);--titles: rgb(34 34 34);--sidebar_bg: rgb(0, 48, 63);--sidebar_text: rgb(255 255 255)}::ng-deep .p-selectbutton .p-button{margin-right:1rem}::ng-deep body .p-selectbutton .p-button.p-highlight{background-color:var(--first)!important}\n"], dependencies: [{ kind: "directive", type: i3.ButtonBusyDirective, selector: "[buttonBusy]", inputs: ["buttonBusy", "busyText"] }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i7.NgxGpAutocompleteDirective, selector: "[ngx-gp-autocomplete]", inputs: ["options"], outputs: ["onAddressChange"], exportAs: ["ngx-places"] }, { kind: "component", type: i8$1.Select, selector: "p-select", inputs: ["id", "scrollHeight", "filter", "panelStyle", "styleClass", "panelStyleClass", "readonly", "editable", "tabindex", "placeholder", "loadingIcon", "filterPlaceholder", "filterLocale", "inputId", "dataKey", "filterBy", "filterFields", "autofocus", "resetFilterOnHide", "checkmark", "dropdownIcon", "loading", "optionLabel", "optionValue", "optionDisabled", "optionGroupLabel", "optionGroupChildren", "group", "showClear", "emptyFilterMessage", "emptyMessage", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "overlayOptions", "ariaFilterLabel", "ariaLabel", "ariaLabelledBy", "filterMatchMode", "tooltip", "tooltipPosition", "tooltipPositionStyle", "tooltipStyleClass", "focusOnHover", "selectOnFocus", "autoOptionFocus", "autofocusFilter", "filterValue", "options", "appendTo", "motionOptions"], outputs: ["onChange", "onFilter", "onFocus", "onBlur", "onClick", "onShow", "onHide", "onClear", "onLazyLoad"] }, { kind: "component", type: i5.InputContainerComponent, selector: "pw-input-container", inputs: ["name", "controlId", "useAriaLabelledbyOnly", "label", "labelClass", "tooltipPosition", "required", "errorMsg", "isReadOnly", "showTooltip", "tooltipText", "showTriangle", "afterLabel", "showAfterLabel", "showTriangleText", "isLeftTooltip"] }, { kind: "component", type: i8$3.SelectButton, selector: "p-selectButton, p-selectbutton, p-select-button", inputs: ["options", "optionLabel", "optionValue", "optionDisabled", "unselectable", "tabindex", "multiple", "allowEmpty", "styleClass", "ariaLabelledBy", "dataKey", "autofocus", "size", "fluid"], outputs: ["onOptionClick", "onChange"] }, { kind: "directive", type: i1$1.NgbInputDatepicker, selector: "input[ngbDatepicker]", inputs: ["autoClose", "contentTemplate", "datepickerClass", "dayTemplate", "dayTemplateData", "displayMonths", "firstDayOfWeek", "footerTemplate", "markDisabled", "minDate", "maxDate", "navigation", "outsideDays", "placement", "popperOptions", "restoreFocus", "showWeekNumbers", "startDate", "container", "positionTarget", "weekdays", "disabled"], outputs: ["dateSelect", "navigate", "closed"], exportAs: ["ngbDatepicker"] }, { kind: "pipe", type: i8.AsyncPipe, name: "async" }, { kind: "pipe", type: i8$2.TranslocoPipe, name: "transloco" }] }); }
|
|
3089
3180
|
}
|
|
3090
3181
|
__decorate([
|
|
3091
3182
|
ValidateForm('form'),
|
|
@@ -3111,12 +3202,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
|
|
|
3111
3202
|
}], save: [] } });
|
|
3112
3203
|
|
|
3113
3204
|
class UserAboutComponent extends AppBaseComponent {
|
|
3114
|
-
constructor(profileService, qualificationService, tagService, injector, cdr) {
|
|
3205
|
+
constructor(profileService, qualificationService, tagService, injector, cdr, confirmDialog) {
|
|
3115
3206
|
super(injector);
|
|
3116
3207
|
this.profileService = profileService;
|
|
3117
3208
|
this.qualificationService = qualificationService;
|
|
3118
3209
|
this.tagService = tagService;
|
|
3119
3210
|
this.cdr = cdr;
|
|
3211
|
+
this.confirmDialog = confirmDialog;
|
|
3120
3212
|
this.isEdit = false;
|
|
3121
3213
|
this.saveEvent = new EventEmitter();
|
|
3122
3214
|
this.allSkills = [];
|
|
@@ -3187,20 +3279,21 @@ class UserAboutComponent extends AppBaseComponent {
|
|
|
3187
3279
|
this.qualificationModal.onOpen(item);
|
|
3188
3280
|
}
|
|
3189
3281
|
deleteQualification(item) {
|
|
3190
|
-
|
|
3282
|
+
this.confirmDialog
|
|
3283
|
+
.open({
|
|
3191
3284
|
title: 'Delete',
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
this.qualificationService.deleteQualifications(item.id).subscribe(() => {
|
|
3199
|
-
this.toast.success(this.translation.translate('User.Profile.Qualifications.QualificationDelete'));
|
|
3200
|
-
this.getUserDetails();
|
|
3201
|
-
this.cdr.markForCheck();
|
|
3202
|
-
});
|
|
3285
|
+
text: `Are you sure you want to delete <strong>${item.degree}</strong>?`,
|
|
3286
|
+
destructive: true
|
|
3287
|
+
})
|
|
3288
|
+
.then(ok => {
|
|
3289
|
+
if (!ok) {
|
|
3290
|
+
return;
|
|
3203
3291
|
}
|
|
3292
|
+
this.qualificationService.deleteQualifications(item.id).subscribe(() => {
|
|
3293
|
+
this.toast.success(this.translation.translate('User.Profile.Qualifications.QualificationDelete'));
|
|
3294
|
+
this.getUserDetails();
|
|
3295
|
+
this.cdr.markForCheck();
|
|
3296
|
+
});
|
|
3204
3297
|
});
|
|
3205
3298
|
}
|
|
3206
3299
|
onSaveUserLinks() {
|
|
@@ -3217,13 +3310,13 @@ class UserAboutComponent extends AppBaseComponent {
|
|
|
3217
3310
|
this.navigationSubscription.unsubscribe();
|
|
3218
3311
|
}
|
|
3219
3312
|
}
|
|
3220
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: UserAboutComponent, deps: [{ token: i1$2.ProfileService }, { token: i1$2.QualificationService }, { token: i1$2.TagService }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3221
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: UserAboutComponent, isStandalone: false, selector: "pw-user-about", inputs: { user: "user", isEdit: "isEdit" }, outputs: { saveEvent: "saveEvent" }, viewQueries: [{ propertyName: "modal", first: true, predicate: EditUserProfileModalComponent, descendants: true }, { propertyName: "qualificationModal", first: true, predicate: EditQualificationsModalComponent, descendants: true }, { propertyName: "skillsModal", first: true, predicate: EditSkillsModalComponent, descendants: true }, { propertyName: "socialModal", first: true, predicate: EditSocialLinksComponent, descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"about\">\n <!-- Personal Information -->\n <section class=\"about-section\" data-cy=\"personal-info\">\n <header class=\"about-section__head\">\n <span class=\"about-section__icon\"><i class=\"fa fa-user\" aria-hidden=\"true\"></i></span>\n <h2 class=\"about-section__title\">{{ 'User.Profile.About.PersonalInfo' | transloco }}</h2>\n @if (user && isEdit) {\n <button type=\"button\" class=\"about-section__edit\" (click)=\"onProfileOpen()\" [attr.aria-label]=\"'User.Profile.About.EditPersonalInfo' | transloco\">\n <i class=\"fa fa-pen\" aria-hidden=\"true\"></i>\n </button>\n }\n </header>\n <div class=\"about-bio\">\n <span class=\"about-field__label\">{{ 'User.Profile.About.AboutMe' | transloco }}</span>\n <p class=\"about-bio__text\" [class.is-empty]=\"!user_profile?.description\">\n {{ user_profile?.description || ('User.Profile.About.NoDescription' | transloco) }}\n </p>\n </div>\n <dl class=\"about-grid\">\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Birthday' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user_profile?.dob\">{{ (user_profile?.dob | dateFormat) || '\u2014' }}</dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.LivesIn' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user_profile?.country\">{{ user_profile?.country || '\u2014' }}</dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Gender' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user_profile?.gender\">\n {{\n user_profile?.gender === 'M'\n ? ('User.Profile.About.Male' | transloco)\n : user_profile?.gender === 'F'\n ? ('User.Profile.About.Female' | transloco)\n : '\u2014'\n }}\n </dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Email' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user?.email\">\n @if (user?.email) {\n <a class=\"about-field__link\" [href]=\"'mailto:' + user.email\">{{ user.email }}</a>\n } @else {\n \u2014\n }\n </dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.PhoneNumber' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user_profile?.phone_number\">{{ user_profile?.phone_number || '\u2014' }}</dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Website' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user_profile?.website_url\">\n @if (user_profile?.website_url) {\n <a class=\"about-field__link\" target=\"_blank\" rel=\"noopener noreferrer\" [href]=\"user_profile.website_url\">{{ user_profile.website_url }}</a>\n } @else {\n \u2014\n }\n </dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Joined' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user?.joined_at\">{{ (user?.joined_at | dateFormat) || '\u2014' }}</dd>\n </div>\n </dl>\n @if (user && isEdit) {\n <pw-edit-user-profile-modal [user]=\"user\" (saveEvent)=\"onProfileSaved($event)\" [slug]=\"user?.slug\"></pw-edit-user-profile-modal>\n }\n </section>\n\n <!-- Skills -->\n <section class=\"about-section\" data-cy=\"skills-info\">\n <header class=\"about-section__head\">\n <span class=\"about-section__icon\"><i class=\"fa fa-bolt\" aria-hidden=\"true\"></i></span>\n <h2 class=\"about-section__title\">{{ 'User.Profile.About.Skills' | transloco }}</h2>\n @if (isEdit) {\n <button type=\"button\" class=\"about-section__edit\" (click)=\"openSkills()\" [attr.aria-label]=\"'User.Profile.About.EditSkills' | transloco\">\n <i class=\"fa fa-pen\" aria-hidden=\"true\"></i>\n </button>\n }\n </header>\n @if (selectedSkills?.length) {\n <div class=\"about-skills\">\n @for (skill of selectedSkills; track skill) {\n <div class=\"about-skills__group\">\n <span class=\"about-skills__category\">{{ skill.category_name }}</span>\n <div class=\"about-tags\">\n @for (item of skill.tags; track item) {\n <span class=\"about-tag\">{{ item.name }}</span>\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <p class=\"about-empty\">{{ (isEdit ? 'User.Profile.About.NoSkillsEdit' : 'User.Profile.About.NoSkills') | transloco }}</p>\n }\n @if (isEdit) {\n <pw-edit-skills-modal [userId]=\"user?.id\" [slug]=\"user?.slug\" (saveEvent)=\"getUserDetails()\"></pw-edit-skills-modal>\n }\n </section>\n\n <!-- Educational Information -->\n <section class=\"about-section\" data-cy=\"educational-info\">\n <header class=\"about-section__head\">\n <span class=\"about-section__icon\"><i class=\"fa fa-graduation-cap\" aria-hidden=\"true\"></i></span>\n <h2 class=\"about-section__title\">{{ 'User.Profile.About.Education' | transloco }}</h2>\n @if (isEdit) {\n <button type=\"button\" class=\"about-section__edit\" (click)=\"qualificationModal.onOpen()\" [attr.aria-label]=\"'User.Profile.About.AddEducation' | transloco\">\n <i class=\"fa fa-plus\" aria-hidden=\"true\"></i>\n </button>\n }\n </header>\n @if (qualifications?.length) {\n <div class=\"about-edu\">\n @for (item of qualifications; track trackByQualification($index, item)) {\n <article class=\"about-edu__item\">\n <div class=\"about-edu__main\">\n <h4 class=\"about-edu__school\">{{ item?.school }}</h4>\n <dl class=\"about-grid about-grid--compact\">\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Period' | transloco }}</dt>\n <dd class=\"about-field__value\">{{ item?.started_on }} \u2013 {{ item?.ended_on }}</dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Degree' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!item?.degree\">{{ item?.degree || '\u2014' }}</dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Course' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!item?.course\">{{ item?.course || '\u2014' }}</dd>\n </div>\n </dl>\n </div>\n @if (isEdit) {\n <div class=\"about-edu__actions\">\n <button type=\"button\" class=\"about-icon-btn\" [attr.aria-label]=\"'User.Profile.About.EditEducation' | transloco\" (click)=\"editQualification(item)\">\n <i class=\"fa fa-pen\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"about-icon-btn about-icon-btn--danger\" data-cy=\"delete-qualification\" [attr.aria-label]=\"'User.Profile.About.DeleteEducation' | transloco\" (click)=\"deleteQualification(item)\">\n <i class=\"fa fa-trash\" aria-hidden=\"true\"></i>\n </button>\n </div>\n }\n </article>\n }\n </div>\n } @else {\n <p class=\"about-empty\">{{ 'User.Profile.About.NoEducation' | transloco }}</p>\n }\n @if (isEdit) {\n <pw-edit-qualifications-modal (saveEvent)=\"getUserDetails()\"></pw-edit-qualifications-modal>\n }\n </section>\n\n <!-- External Portfolio -->\n <section class=\"about-section\" data-cy=\"portfolio-info\">\n <header class=\"about-section__head\">\n <span class=\"about-section__icon\"><i class=\"fa fa-link\" aria-hidden=\"true\"></i></span>\n <h2 class=\"about-section__title\">{{ 'User.Profile.About.Portfolio' | transloco }}</h2>\n @if (isEdit) {\n <button type=\"button\" class=\"about-section__edit\" (click)=\"onOpenSocial()\" [attr.aria-label]=\"'User.Profile.About.EditPortfolio' | transloco\">\n <i class=\"fa fa-pen\" aria-hidden=\"true\"></i>\n </button>\n }\n </header>\n @if (noUserLinks) {\n <div class=\"about-social\">\n @for (link of objectKeys(userLinks); track link) {\n @if (userLinks[link]) {\n <a class=\"about-social__link\" target=\"_blank\" rel=\"noopener noreferrer\" [href]=\"userLinks[link]\" [attr.aria-label]=\"link\">\n <img src=\"assets/img/icons/social/{{ link }}.svg\" width=\"32\" height=\"32\" [alt]=\"link\" />\n </a>\n }\n }\n </div>\n } @else {\n <p class=\"about-empty\">{{ 'User.Profile.About.NoPortfolio' | transloco }}</p>\n }\n @if (user && isEdit) {\n <pw-edit-social-links [userId]=\"user.id\" [links]=\"userLinks\" (saveEvent)=\"onSaveUserLinks()\"></pw-edit-social-links>\n }\n </section>\n\n @if (loading) {\n <div class=\"w-100 text-center p-3\"><p-progressSpinner strokeWidth=\"2\"></p-progressSpinner></div>\n }\n</div>\n", styles: ["@charset \"UTF-8\";:root{--first: rgb(23 105 225);--second: rgb(54 194 131);--third: rgb(255 171 0);--text: rgb(34 34 34);--tabs_bg: rgb(23 105 225);--tabs_sub_bg: rgb(70, 136, 236);--tabs_text: rgb(255 255 255);--titles: rgb(34 34 34);--sidebar_bg: rgb(0, 48, 63);--sidebar_text: rgb(255 255 255)}.about{display:flex;flex-direction:column;gap:16px}.about-section{background:#fff;border:1px solid #e2e5ea;border-radius:8px;padding:20px 24px;float:none}.about-section ::ng-deep .pi-plus-circle{display:none}.about-section__head{display:flex;align-items:center;margin-bottom:18px;float:none}.about-section__icon{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;margin-right:12px;border-radius:8px;background:#f7f8fa;color:#5a6473;font-size:.95rem;flex-shrink:0}.about-section__title{margin:0!important;padding:0!important}.about-section__edit{margin-left:auto}.about-field__label,.about-skills__category{margin:0;font-size:1rem;font-weight:600;letter-spacing:.03em;text-transform:uppercase;color:#7c8696}.about-section__edit,.about-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;border:1px solid #e2e5ea;border-radius:7px;background:#fff;color:#5a6473;font-size:.9rem;cursor:pointer;transition:all .12s ease-out}.about-section__edit:hover,.about-icon-btn:hover{background:#f7f8fa;color:#1a1d21;border-color:#cfd4dc}.about-empty{margin:0;color:#7c8696;font-size:1.2rem}.about-bio{margin-bottom:22px}.about-bio__text{margin:6px 0 0;color:#1a1d21;font-size:1.25rem;line-height:1.55}.about-bio__text.is-empty{color:#7c8696;font-size:1.2rem}.about-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:20px 28px;margin:0}.about-grid--compact{gap:14px 24px}.about-field{display:flex;flex-direction:column;gap:5px;min-width:0}.about-field__value{margin:0;font-size:1.15rem;color:#1a1d21;word-break:break-word}.about-field__value.is-empty{color:#cfd4dc}.about-field__link{color:var(--first);text-decoration:none}.about-field__link:hover{text-decoration:underline}.about-skills{display:flex;flex-direction:column;gap:16px}.about-skills__group{display:flex;flex-direction:column;gap:8px}.about-tags{display:flex;flex-wrap:wrap;gap:8px}.about-tag{display:inline-flex;align-items:center;padding:5px 13px;border:1px solid #e2e5ea;border-radius:9999px;background:#eef0f3;color:#3d4654;font-size:1.05rem;font-weight:500;line-height:1.4}.about-edu{display:flex;flex-direction:column;gap:14px}.about-edu__item{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:16px;border:1px solid #e2e5ea;border-radius:8px;background:#f7f8fa}.about-edu__main{min-width:0;flex:1}.about-edu__school{margin:0 0 12px}.about-edu__actions{display:flex;gap:6px;flex-shrink:0}.about-icon-btn--danger:hover{color:#c0392b;border-color:#c0392b}.about-social{display:flex;flex-wrap:wrap;gap:14px}.about-social__link{display:inline-flex}\n"], dependencies: [{ kind: "directive", type: i4.LazyImgDirective, selector: "img" }, { kind: "component", type: i4$1.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "component", type: EditQualificationsModalComponent, selector: "pw-edit-qualifications-modal", outputs: ["saveEvent"] }, { kind: "component", type: EditSkillsModalComponent, selector: "pw-edit-skills-modal", inputs: ["userId", "slug", "entityType", "entityEntity"], outputs: ["saveEvent"] }, { kind: "component", type: EditSocialLinksComponent, selector: "pw-edit-social-links", inputs: ["links", "userId"], outputs: ["saveEvent"] }, { kind: "component", type: EditUserProfileModalComponent, selector: "pw-edit-user-profile-modal", inputs: ["slug", "user"], outputs: ["saveEvent"] }, { kind: "pipe", type: i8.TranslocoPipe, name: "transloco" }, { kind: "pipe", type: i6$3.DateFormatPipe, name: "dateFormat" }] }); }
|
|
3313
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: UserAboutComponent, deps: [{ token: i1$2.ProfileService }, { token: i1$2.QualificationService }, { token: i1$2.TagService }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }, { token: i5.ConfirmDialogService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3314
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: UserAboutComponent, isStandalone: false, selector: "pw-user-about", inputs: { user: "user", isEdit: "isEdit" }, outputs: { saveEvent: "saveEvent" }, viewQueries: [{ propertyName: "modal", first: true, predicate: EditUserProfileModalComponent, descendants: true }, { propertyName: "qualificationModal", first: true, predicate: EditQualificationsModalComponent, descendants: true }, { propertyName: "skillsModal", first: true, predicate: EditSkillsModalComponent, descendants: true }, { propertyName: "socialModal", first: true, predicate: EditSocialLinksComponent, descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"about\">\n <!-- Personal Information -->\n <section class=\"about-section\" data-cy=\"personal-info\">\n <header class=\"about-section__head\">\n <span class=\"about-section__icon\"><i class=\"fa fa-user\" aria-hidden=\"true\"></i></span>\n <h2 class=\"about-section__title\">{{ 'User.Profile.About.PersonalInfo' | transloco }}</h2>\n @if (user && isEdit) {\n <button type=\"button\" class=\"about-section__edit\" (click)=\"onProfileOpen()\" [attr.aria-label]=\"'User.Profile.About.EditPersonalInfo' | transloco\">\n <i class=\"fa fa-pen\" aria-hidden=\"true\"></i>\n </button>\n }\n </header>\n <div class=\"about-bio\">\n <span class=\"about-field__label\">{{ 'User.Profile.About.AboutMe' | transloco }}</span>\n <p class=\"about-bio__text\" [class.is-empty]=\"!user_profile?.description\">\n {{ user_profile?.description || ('User.Profile.About.NoDescription' | transloco) }}\n </p>\n </div>\n <dl class=\"about-grid\">\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Birthday' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user_profile?.dob\">{{ (user_profile?.dob | dateFormat) || '\u2014' }}</dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.LivesIn' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user_profile?.country\">{{ user_profile?.country || '\u2014' }}</dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Gender' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user_profile?.gender\">\n {{\n user_profile?.gender === 'M'\n ? ('User.Profile.About.Male' | transloco)\n : user_profile?.gender === 'F'\n ? ('User.Profile.About.Female' | transloco)\n : '\u2014'\n }}\n </dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Email' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user?.email\">\n @if (user?.email) {\n <a class=\"about-field__link\" [href]=\"'mailto:' + user.email\">{{ user.email }}</a>\n } @else {\n \u2014\n }\n </dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.PhoneNumber' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user_profile?.phone_number\">{{ user_profile?.phone_number || '\u2014' }}</dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Website' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user_profile?.website_url\">\n @if (user_profile?.website_url) {\n <a class=\"about-field__link\" target=\"_blank\" rel=\"noopener noreferrer\" [href]=\"user_profile.website_url\">{{ user_profile.website_url }}</a>\n } @else {\n \u2014\n }\n </dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Joined' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user?.joined_at\">{{ (user?.joined_at | dateFormat) || '\u2014' }}</dd>\n </div>\n </dl>\n @if (user && isEdit) {\n <pw-edit-user-profile-modal [user]=\"user\" (saveEvent)=\"onProfileSaved($event)\" [slug]=\"user?.slug\"></pw-edit-user-profile-modal>\n }\n </section>\n\n <!-- Skills -->\n <section class=\"about-section\" data-cy=\"skills-info\">\n <header class=\"about-section__head\">\n <span class=\"about-section__icon\"><i class=\"fa fa-bolt\" aria-hidden=\"true\"></i></span>\n <h2 class=\"about-section__title\">{{ 'User.Profile.About.Skills' | transloco }}</h2>\n @if (isEdit) {\n <button type=\"button\" class=\"about-section__edit\" (click)=\"openSkills()\" [attr.aria-label]=\"'User.Profile.About.EditSkills' | transloco\">\n <i class=\"fa fa-pen\" aria-hidden=\"true\"></i>\n </button>\n }\n </header>\n @if (selectedSkills?.length) {\n <div class=\"about-skills\">\n @for (skill of selectedSkills; track skill) {\n <div class=\"about-skills__group\">\n <span class=\"about-skills__category\">{{ skill.category_name }}</span>\n <div class=\"about-tags\">\n @for (item of skill.tags; track item) {\n <span class=\"about-tag\">{{ item.name }}</span>\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <p class=\"about-empty\">{{ (isEdit ? 'User.Profile.About.NoSkillsEdit' : 'User.Profile.About.NoSkills') | transloco }}</p>\n }\n @if (isEdit) {\n <pw-edit-skills-modal [userId]=\"user?.id\" [slug]=\"user?.slug\" (saveEvent)=\"getUserDetails()\"></pw-edit-skills-modal>\n }\n </section>\n\n <!-- Educational Information -->\n <section class=\"about-section\" data-cy=\"educational-info\">\n <header class=\"about-section__head\">\n <span class=\"about-section__icon\"><i class=\"fa fa-graduation-cap\" aria-hidden=\"true\"></i></span>\n <h2 class=\"about-section__title\">{{ 'User.Profile.About.Education' | transloco }}</h2>\n @if (isEdit) {\n <button type=\"button\" class=\"about-section__edit\" (click)=\"qualificationModal.onOpen()\" [attr.aria-label]=\"'User.Profile.About.AddEducation' | transloco\">\n <i class=\"fa fa-plus\" aria-hidden=\"true\"></i>\n </button>\n }\n </header>\n @if (qualifications?.length) {\n <div class=\"about-edu\">\n @for (item of qualifications; track trackByQualification($index, item)) {\n <article class=\"about-edu__item\">\n <div class=\"about-edu__main\">\n <h4 class=\"about-edu__school\">{{ item?.school }}</h4>\n <dl class=\"about-grid about-grid--compact\">\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Period' | transloco }}</dt>\n <dd class=\"about-field__value\">{{ item?.started_on }} \u2013 {{ item?.ended_on }}</dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Degree' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!item?.degree\">{{ item?.degree || '\u2014' }}</dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Course' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!item?.course\">{{ item?.course || '\u2014' }}</dd>\n </div>\n </dl>\n </div>\n @if (isEdit) {\n <div class=\"about-edu__actions\">\n <button type=\"button\" class=\"about-icon-btn\" [attr.aria-label]=\"'User.Profile.About.EditEducation' | transloco\" (click)=\"editQualification(item)\">\n <i class=\"fa fa-pen\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"about-icon-btn about-icon-btn--danger\" data-cy=\"delete-qualification\" [attr.aria-label]=\"'User.Profile.About.DeleteEducation' | transloco\" (click)=\"deleteQualification(item)\">\n <i class=\"fa fa-trash\" aria-hidden=\"true\"></i>\n </button>\n </div>\n }\n </article>\n }\n </div>\n } @else {\n <p class=\"about-empty\">{{ 'User.Profile.About.NoEducation' | transloco }}</p>\n }\n @if (isEdit) {\n <pw-edit-qualifications-modal (saveEvent)=\"getUserDetails()\"></pw-edit-qualifications-modal>\n }\n </section>\n\n <!-- External Portfolio -->\n <section class=\"about-section\" data-cy=\"portfolio-info\">\n <header class=\"about-section__head\">\n <span class=\"about-section__icon\"><i class=\"fa fa-link\" aria-hidden=\"true\"></i></span>\n <h2 class=\"about-section__title\">{{ 'User.Profile.About.Portfolio' | transloco }}</h2>\n @if (isEdit) {\n <button type=\"button\" class=\"about-section__edit\" (click)=\"onOpenSocial()\" [attr.aria-label]=\"'User.Profile.About.EditPortfolio' | transloco\">\n <i class=\"fa fa-pen\" aria-hidden=\"true\"></i>\n </button>\n }\n </header>\n @if (noUserLinks) {\n <div class=\"about-social\">\n @for (link of objectKeys(userLinks); track link) {\n @if (userLinks[link]) {\n <a class=\"about-social__link\" target=\"_blank\" rel=\"noopener noreferrer\" [href]=\"userLinks[link]\" [attr.aria-label]=\"link\">\n <img src=\"assets/img/icons/social/{{ link }}.svg\" width=\"32\" height=\"32\" [alt]=\"link\" />\n </a>\n }\n }\n </div>\n } @else {\n <p class=\"about-empty\">{{ 'User.Profile.About.NoPortfolio' | transloco }}</p>\n }\n @if (user && isEdit) {\n <pw-edit-social-links [userId]=\"user.id\" [links]=\"userLinks\" (saveEvent)=\"onSaveUserLinks()\"></pw-edit-social-links>\n }\n </section>\n\n @if (loading) {\n <div class=\"w-100 text-center p-3\"><p-progressSpinner strokeWidth=\"2\"></p-progressSpinner></div>\n }\n</div>\n", styles: ["@charset \"UTF-8\";:root{--first: rgb(23 105 225);--second: rgb(54 194 131);--third: rgb(255 171 0);--text: rgb(34 34 34);--tabs_bg: rgb(23 105 225);--tabs_sub_bg: rgb(70, 136, 236);--tabs_text: rgb(255 255 255);--titles: rgb(34 34 34);--sidebar_bg: rgb(0, 48, 63);--sidebar_text: rgb(255 255 255)}.about{display:flex;flex-direction:column;gap:16px}.about-section{background:#fff;border:1px solid #e2e5ea;border-radius:8px;padding:20px 24px;float:none}.about-section ::ng-deep .pi-plus-circle{display:none}.about-section__head{display:flex;align-items:center;margin-bottom:18px;float:none}.about-section__icon{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;margin-right:12px;border-radius:8px;background:#f7f8fa;color:#5a6473;font-size:.95rem;flex-shrink:0}.about-section__title{margin:0!important;padding:0!important}.about-section__edit{margin-left:auto}.about-field__label,.about-skills__category{margin:0;font-size:1rem;font-weight:600;letter-spacing:.03em;text-transform:uppercase;color:#7c8696}.about-section__edit,.about-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;border:1px solid #e2e5ea;border-radius:7px;background:#fff;color:#5a6473;font-size:.9rem;cursor:pointer;transition:all .12s ease-out}.about-section__edit:hover,.about-icon-btn:hover{background:#f7f8fa;color:#1a1d21;border-color:#cfd4dc}.about-empty{margin:0;color:#7c8696;font-size:1.2rem}.about-bio{margin-bottom:22px}.about-bio__text{margin:6px 0 0;color:#1a1d21;font-size:1.25rem;line-height:1.55}.about-bio__text.is-empty{color:#7c8696;font-size:1.2rem}.about-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:20px 28px;margin:0}.about-grid--compact{gap:14px 24px}.about-field{display:flex;flex-direction:column;gap:5px;min-width:0}.about-field__value{margin:0;font-size:1.15rem;color:#1a1d21;word-break:break-word}.about-field__value.is-empty{color:#cfd4dc}.about-field__link{color:var(--first);text-decoration:none}.about-field__link:hover{text-decoration:underline}.about-skills{display:flex;flex-direction:column;gap:16px}.about-skills__group{display:flex;flex-direction:column;gap:8px}.about-tags{display:flex;flex-wrap:wrap;gap:8px}.about-tag{display:inline-flex;align-items:center;padding:5px 13px;border:1px solid #e2e5ea;border-radius:9999px;background:#eef0f3;color:#3d4654;font-size:1.05rem;font-weight:500;line-height:1.4}.about-edu{display:flex;flex-direction:column;gap:14px}.about-edu__item{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:16px;border:1px solid #e2e5ea;border-radius:8px;background:#f7f8fa}.about-edu__main{min-width:0;flex:1}.about-edu__school{margin:0 0 12px}.about-edu__actions{display:flex;gap:6px;flex-shrink:0}.about-icon-btn--danger:hover{color:#c0392b;border-color:#c0392b}.about-social{display:flex;flex-wrap:wrap;gap:14px}.about-social__link{display:inline-flex}\n"], dependencies: [{ kind: "directive", type: i3.LazyImgDirective, selector: "img" }, { kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "component", type: EditQualificationsModalComponent, selector: "pw-edit-qualifications-modal", outputs: ["saveEvent"] }, { kind: "component", type: EditSkillsModalComponent, selector: "pw-edit-skills-modal", inputs: ["userId", "slug", "entityType", "entityEntity"], outputs: ["saveEvent"] }, { kind: "component", type: EditSocialLinksComponent, selector: "pw-edit-social-links", inputs: ["links", "userId"], outputs: ["saveEvent"] }, { kind: "component", type: EditUserProfileModalComponent, selector: "pw-edit-user-profile-modal", inputs: ["slug", "user"], outputs: ["saveEvent"] }, { kind: "pipe", type: i8$2.TranslocoPipe, name: "transloco" }, { kind: "pipe", type: i6.DateFormatPipe, name: "dateFormat" }] }); }
|
|
3222
3315
|
}
|
|
3223
3316
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: UserAboutComponent, decorators: [{
|
|
3224
3317
|
type: Component,
|
|
3225
3318
|
args: [{ selector: 'pw-user-about', standalone: false, template: "<div class=\"about\">\n <!-- Personal Information -->\n <section class=\"about-section\" data-cy=\"personal-info\">\n <header class=\"about-section__head\">\n <span class=\"about-section__icon\"><i class=\"fa fa-user\" aria-hidden=\"true\"></i></span>\n <h2 class=\"about-section__title\">{{ 'User.Profile.About.PersonalInfo' | transloco }}</h2>\n @if (user && isEdit) {\n <button type=\"button\" class=\"about-section__edit\" (click)=\"onProfileOpen()\" [attr.aria-label]=\"'User.Profile.About.EditPersonalInfo' | transloco\">\n <i class=\"fa fa-pen\" aria-hidden=\"true\"></i>\n </button>\n }\n </header>\n <div class=\"about-bio\">\n <span class=\"about-field__label\">{{ 'User.Profile.About.AboutMe' | transloco }}</span>\n <p class=\"about-bio__text\" [class.is-empty]=\"!user_profile?.description\">\n {{ user_profile?.description || ('User.Profile.About.NoDescription' | transloco) }}\n </p>\n </div>\n <dl class=\"about-grid\">\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Birthday' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user_profile?.dob\">{{ (user_profile?.dob | dateFormat) || '\u2014' }}</dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.LivesIn' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user_profile?.country\">{{ user_profile?.country || '\u2014' }}</dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Gender' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user_profile?.gender\">\n {{\n user_profile?.gender === 'M'\n ? ('User.Profile.About.Male' | transloco)\n : user_profile?.gender === 'F'\n ? ('User.Profile.About.Female' | transloco)\n : '\u2014'\n }}\n </dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Email' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user?.email\">\n @if (user?.email) {\n <a class=\"about-field__link\" [href]=\"'mailto:' + user.email\">{{ user.email }}</a>\n } @else {\n \u2014\n }\n </dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.PhoneNumber' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user_profile?.phone_number\">{{ user_profile?.phone_number || '\u2014' }}</dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Website' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user_profile?.website_url\">\n @if (user_profile?.website_url) {\n <a class=\"about-field__link\" target=\"_blank\" rel=\"noopener noreferrer\" [href]=\"user_profile.website_url\">{{ user_profile.website_url }}</a>\n } @else {\n \u2014\n }\n </dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Joined' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!user?.joined_at\">{{ (user?.joined_at | dateFormat) || '\u2014' }}</dd>\n </div>\n </dl>\n @if (user && isEdit) {\n <pw-edit-user-profile-modal [user]=\"user\" (saveEvent)=\"onProfileSaved($event)\" [slug]=\"user?.slug\"></pw-edit-user-profile-modal>\n }\n </section>\n\n <!-- Skills -->\n <section class=\"about-section\" data-cy=\"skills-info\">\n <header class=\"about-section__head\">\n <span class=\"about-section__icon\"><i class=\"fa fa-bolt\" aria-hidden=\"true\"></i></span>\n <h2 class=\"about-section__title\">{{ 'User.Profile.About.Skills' | transloco }}</h2>\n @if (isEdit) {\n <button type=\"button\" class=\"about-section__edit\" (click)=\"openSkills()\" [attr.aria-label]=\"'User.Profile.About.EditSkills' | transloco\">\n <i class=\"fa fa-pen\" aria-hidden=\"true\"></i>\n </button>\n }\n </header>\n @if (selectedSkills?.length) {\n <div class=\"about-skills\">\n @for (skill of selectedSkills; track skill) {\n <div class=\"about-skills__group\">\n <span class=\"about-skills__category\">{{ skill.category_name }}</span>\n <div class=\"about-tags\">\n @for (item of skill.tags; track item) {\n <span class=\"about-tag\">{{ item.name }}</span>\n }\n </div>\n </div>\n }\n </div>\n } @else {\n <p class=\"about-empty\">{{ (isEdit ? 'User.Profile.About.NoSkillsEdit' : 'User.Profile.About.NoSkills') | transloco }}</p>\n }\n @if (isEdit) {\n <pw-edit-skills-modal [userId]=\"user?.id\" [slug]=\"user?.slug\" (saveEvent)=\"getUserDetails()\"></pw-edit-skills-modal>\n }\n </section>\n\n <!-- Educational Information -->\n <section class=\"about-section\" data-cy=\"educational-info\">\n <header class=\"about-section__head\">\n <span class=\"about-section__icon\"><i class=\"fa fa-graduation-cap\" aria-hidden=\"true\"></i></span>\n <h2 class=\"about-section__title\">{{ 'User.Profile.About.Education' | transloco }}</h2>\n @if (isEdit) {\n <button type=\"button\" class=\"about-section__edit\" (click)=\"qualificationModal.onOpen()\" [attr.aria-label]=\"'User.Profile.About.AddEducation' | transloco\">\n <i class=\"fa fa-plus\" aria-hidden=\"true\"></i>\n </button>\n }\n </header>\n @if (qualifications?.length) {\n <div class=\"about-edu\">\n @for (item of qualifications; track trackByQualification($index, item)) {\n <article class=\"about-edu__item\">\n <div class=\"about-edu__main\">\n <h4 class=\"about-edu__school\">{{ item?.school }}</h4>\n <dl class=\"about-grid about-grid--compact\">\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Period' | transloco }}</dt>\n <dd class=\"about-field__value\">{{ item?.started_on }} \u2013 {{ item?.ended_on }}</dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Degree' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!item?.degree\">{{ item?.degree || '\u2014' }}</dd>\n </div>\n <div class=\"about-field\">\n <dt class=\"about-field__label\">{{ 'User.Profile.About.Course' | transloco }}</dt>\n <dd class=\"about-field__value\" [class.is-empty]=\"!item?.course\">{{ item?.course || '\u2014' }}</dd>\n </div>\n </dl>\n </div>\n @if (isEdit) {\n <div class=\"about-edu__actions\">\n <button type=\"button\" class=\"about-icon-btn\" [attr.aria-label]=\"'User.Profile.About.EditEducation' | transloco\" (click)=\"editQualification(item)\">\n <i class=\"fa fa-pen\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\" class=\"about-icon-btn about-icon-btn--danger\" data-cy=\"delete-qualification\" [attr.aria-label]=\"'User.Profile.About.DeleteEducation' | transloco\" (click)=\"deleteQualification(item)\">\n <i class=\"fa fa-trash\" aria-hidden=\"true\"></i>\n </button>\n </div>\n }\n </article>\n }\n </div>\n } @else {\n <p class=\"about-empty\">{{ 'User.Profile.About.NoEducation' | transloco }}</p>\n }\n @if (isEdit) {\n <pw-edit-qualifications-modal (saveEvent)=\"getUserDetails()\"></pw-edit-qualifications-modal>\n }\n </section>\n\n <!-- External Portfolio -->\n <section class=\"about-section\" data-cy=\"portfolio-info\">\n <header class=\"about-section__head\">\n <span class=\"about-section__icon\"><i class=\"fa fa-link\" aria-hidden=\"true\"></i></span>\n <h2 class=\"about-section__title\">{{ 'User.Profile.About.Portfolio' | transloco }}</h2>\n @if (isEdit) {\n <button type=\"button\" class=\"about-section__edit\" (click)=\"onOpenSocial()\" [attr.aria-label]=\"'User.Profile.About.EditPortfolio' | transloco\">\n <i class=\"fa fa-pen\" aria-hidden=\"true\"></i>\n </button>\n }\n </header>\n @if (noUserLinks) {\n <div class=\"about-social\">\n @for (link of objectKeys(userLinks); track link) {\n @if (userLinks[link]) {\n <a class=\"about-social__link\" target=\"_blank\" rel=\"noopener noreferrer\" [href]=\"userLinks[link]\" [attr.aria-label]=\"link\">\n <img src=\"assets/img/icons/social/{{ link }}.svg\" width=\"32\" height=\"32\" [alt]=\"link\" />\n </a>\n }\n }\n </div>\n } @else {\n <p class=\"about-empty\">{{ 'User.Profile.About.NoPortfolio' | transloco }}</p>\n }\n @if (user && isEdit) {\n <pw-edit-social-links [userId]=\"user.id\" [links]=\"userLinks\" (saveEvent)=\"onSaveUserLinks()\"></pw-edit-social-links>\n }\n </section>\n\n @if (loading) {\n <div class=\"w-100 text-center p-3\"><p-progressSpinner strokeWidth=\"2\"></p-progressSpinner></div>\n }\n</div>\n", styles: ["@charset \"UTF-8\";:root{--first: rgb(23 105 225);--second: rgb(54 194 131);--third: rgb(255 171 0);--text: rgb(34 34 34);--tabs_bg: rgb(23 105 225);--tabs_sub_bg: rgb(70, 136, 236);--tabs_text: rgb(255 255 255);--titles: rgb(34 34 34);--sidebar_bg: rgb(0, 48, 63);--sidebar_text: rgb(255 255 255)}.about{display:flex;flex-direction:column;gap:16px}.about-section{background:#fff;border:1px solid #e2e5ea;border-radius:8px;padding:20px 24px;float:none}.about-section ::ng-deep .pi-plus-circle{display:none}.about-section__head{display:flex;align-items:center;margin-bottom:18px;float:none}.about-section__icon{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;margin-right:12px;border-radius:8px;background:#f7f8fa;color:#5a6473;font-size:.95rem;flex-shrink:0}.about-section__title{margin:0!important;padding:0!important}.about-section__edit{margin-left:auto}.about-field__label,.about-skills__category{margin:0;font-size:1rem;font-weight:600;letter-spacing:.03em;text-transform:uppercase;color:#7c8696}.about-section__edit,.about-icon-btn{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;border:1px solid #e2e5ea;border-radius:7px;background:#fff;color:#5a6473;font-size:.9rem;cursor:pointer;transition:all .12s ease-out}.about-section__edit:hover,.about-icon-btn:hover{background:#f7f8fa;color:#1a1d21;border-color:#cfd4dc}.about-empty{margin:0;color:#7c8696;font-size:1.2rem}.about-bio{margin-bottom:22px}.about-bio__text{margin:6px 0 0;color:#1a1d21;font-size:1.25rem;line-height:1.55}.about-bio__text.is-empty{color:#7c8696;font-size:1.2rem}.about-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(230px,1fr));gap:20px 28px;margin:0}.about-grid--compact{gap:14px 24px}.about-field{display:flex;flex-direction:column;gap:5px;min-width:0}.about-field__value{margin:0;font-size:1.15rem;color:#1a1d21;word-break:break-word}.about-field__value.is-empty{color:#cfd4dc}.about-field__link{color:var(--first);text-decoration:none}.about-field__link:hover{text-decoration:underline}.about-skills{display:flex;flex-direction:column;gap:16px}.about-skills__group{display:flex;flex-direction:column;gap:8px}.about-tags{display:flex;flex-wrap:wrap;gap:8px}.about-tag{display:inline-flex;align-items:center;padding:5px 13px;border:1px solid #e2e5ea;border-radius:9999px;background:#eef0f3;color:#3d4654;font-size:1.05rem;font-weight:500;line-height:1.4}.about-edu{display:flex;flex-direction:column;gap:14px}.about-edu__item{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;padding:16px;border:1px solid #e2e5ea;border-radius:8px;background:#f7f8fa}.about-edu__main{min-width:0;flex:1}.about-edu__school{margin:0 0 12px}.about-edu__actions{display:flex;gap:6px;flex-shrink:0}.about-icon-btn--danger:hover{color:#c0392b;border-color:#c0392b}.about-social{display:flex;flex-wrap:wrap;gap:14px}.about-social__link{display:inline-flex}\n"] }]
|
|
3226
|
-
}], ctorParameters: () => [{ type: i1$2.ProfileService }, { type: i1$2.QualificationService }, { type: i1$2.TagService }, { type: i0.Injector }, { type: i0.ChangeDetectorRef }], propDecorators: { user: [{
|
|
3319
|
+
}], ctorParameters: () => [{ type: i1$2.ProfileService }, { type: i1$2.QualificationService }, { type: i1$2.TagService }, { type: i0.Injector }, { type: i0.ChangeDetectorRef }, { type: i5.ConfirmDialogService }], propDecorators: { user: [{
|
|
3227
3320
|
type: Input
|
|
3228
3321
|
}], isEdit: [{
|
|
3229
3322
|
type: Input
|
|
@@ -3288,7 +3381,7 @@ class PortfoliosComponent {
|
|
|
3288
3381
|
}
|
|
3289
3382
|
}
|
|
3290
3383
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: PortfoliosComponent, deps: [{ token: i1$2.ProfileService }, { token: i1$1.NgbModal }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3291
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: PortfoliosComponent, isStandalone: false, selector: "pw-portfolios", inputs: { user: "user", isEdit: "isEdit" }, ngImport: i0, template: "<div class=\"row\">\n <div class=\"col-sm-12 mt-2\">\n <h2>User's Portfolio</h2>\n @if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\"\n >\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n @if (projectPictures.length === 0 && isLoaded) {\n <pw-no-data [withImage]=\"true\" message=\"No portfolio listed yet - please consider adding some.\"\n ></pw-no-data>\n }\n <div class=\"card-body\">\n @if (projectPictures.length) {\n <div class=\"card-block\"\n >\n <div class=\"grid-hover\">\n <div class=\"row\">\n @for (picture of projectPictures; track trackByImage($index, picture)) {\n <div class=\"col-md-4 col-12 mb-2\"\n >\n <figure class=\"effect-marley\"\n (keydown.enter)=\"showFullImage(picture, content, $event)\"\n (click)=\"showFullImage(picture, content, $event)\">\n <img [src]=\"picture.picture.url\"\n alt=\"project pic\" />\n <figcaption>\n <h2>\n <span class=\"portfolio-header-text\">{{ picture.project_title }}</span>\n </h2>\n @if (isEdit) {\n <i\n class=\"fal fa-2x fa-times white\"\n id=\"delete-icon\"\n (click)=\"deletePicture(picture.id)\"\n (keydown.enter)=\"deletePicture(picture.id)\"\n aria-hidden=\"true\"\n ></i>\n }\n <p class=\"thumb-description\">\n {{ picture?.project_description }}\n </p>\n </figcaption>\n </figure>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n</div>\n<ng-template #content\n let-modal>\n <div class=\"modal-img-popup\">\n <img alt=\"Selected Url\"\n [src]=\"selectedPicURL\"\n class=\"img-fluid\" />\n <button type=\"button\"\n class=\"close close-img\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss('Cross click')\">\n <span class=\"btn\">×</span>\n </button>\n </div>\n</ng-template>\n", styles: [".grid-hover figure{height:100%}.grid-hover figure figcaption:hover{background-color:#343a4066}.grid-hover figure figcaption h2{color:#fff}.thumb-description{color:#fff!important;height:154px;overflow:hidden;text-overflow:ellipsis;top:91px}.demo .modal-dialog{max-width:800px}.close-img{position:absolute}.close-img span{background-color:#4a4a4a;border:1px solid rgb(255,255,255);border-radius:50px;color:#fff;cursor:pointer;display:inline-block;font-size:1rem;height:40px;position:absolute;right:-30px;text-align:center;top:-30px;width:40px}@media screen and (max-width:767px){.grid-hover figure{max-width:100%;min-width:100%}}@media screen and (min-device-width:768px)and (max-device-width:1200px){.grid-hover figure{min-width:fit-content}}.portfolio-header-text{color:#fff!important}\n"], dependencies: [{ kind: "directive", type:
|
|
3384
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: PortfoliosComponent, isStandalone: false, selector: "pw-portfolios", inputs: { user: "user", isEdit: "isEdit" }, ngImport: i0, template: "<div class=\"row\">\n <div class=\"col-sm-12 mt-2\">\n <h2>User's Portfolio</h2>\n @if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\"\n >\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n @if (projectPictures.length === 0 && isLoaded) {\n <pw-no-data [withImage]=\"true\" message=\"No portfolio listed yet - please consider adding some.\"\n ></pw-no-data>\n }\n <div class=\"card-body\">\n @if (projectPictures.length) {\n <div class=\"card-block\"\n >\n <div class=\"grid-hover\">\n <div class=\"row\">\n @for (picture of projectPictures; track trackByImage($index, picture)) {\n <div class=\"col-md-4 col-12 mb-2\"\n >\n <figure class=\"effect-marley\"\n (keydown.enter)=\"showFullImage(picture, content, $event)\"\n (click)=\"showFullImage(picture, content, $event)\">\n <img [src]=\"picture.picture.url\"\n alt=\"project pic\" />\n <figcaption>\n <h2>\n <span class=\"portfolio-header-text\">{{ picture.project_title }}</span>\n </h2>\n @if (isEdit) {\n <i\n class=\"fal fa-2x fa-times white\"\n id=\"delete-icon\"\n (click)=\"deletePicture(picture.id)\"\n (keydown.enter)=\"deletePicture(picture.id)\"\n aria-hidden=\"true\"\n ></i>\n }\n <p class=\"thumb-description\">\n {{ picture?.project_description }}\n </p>\n </figcaption>\n </figure>\n </div>\n }\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n</div>\n<ng-template #content\n let-modal>\n <div class=\"modal-img-popup\">\n <img alt=\"Selected Url\"\n [src]=\"selectedPicURL\"\n class=\"img-fluid\" />\n <button type=\"button\"\n class=\"close close-img\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss('Cross click')\">\n <span class=\"btn\">×</span>\n </button>\n </div>\n</ng-template>\n", styles: [".grid-hover figure{height:100%}.grid-hover figure figcaption:hover{background-color:#343a4066}.grid-hover figure figcaption h2{color:#fff}.thumb-description{color:#fff!important;height:154px;overflow:hidden;text-overflow:ellipsis;top:91px}.demo .modal-dialog{max-width:800px}.close-img{position:absolute}.close-img span{background-color:#4a4a4a;border:1px solid rgb(255,255,255);border-radius:50px;color:#fff;cursor:pointer;display:inline-block;font-size:1rem;height:40px;position:absolute;right:-30px;text-align:center;top:-30px;width:40px}@media screen and (max-width:767px){.grid-hover figure{max-width:100%;min-width:100%}}@media screen and (min-device-width:768px)and (max-device-width:1200px){.grid-hover figure{min-width:fit-content}}.portfolio-header-text{color:#fff!important}\n"], dependencies: [{ kind: "directive", type: i3.LazyImgDirective, selector: "img" }, { kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "component", type: i5.NoDataComponent, selector: "pw-no-data", inputs: ["message", "description", "withImage"] }] }); }
|
|
3292
3385
|
}
|
|
3293
3386
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: PortfoliosComponent, decorators: [{
|
|
3294
3387
|
type: Component,
|
|
@@ -3300,10 +3393,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
|
|
|
3300
3393
|
}] } });
|
|
3301
3394
|
|
|
3302
3395
|
class UserProjectsComponent extends AppBaseComponent {
|
|
3303
|
-
constructor(service, injector, cdr) {
|
|
3396
|
+
constructor(service, injector, cdr, confirmDialog) {
|
|
3304
3397
|
super(injector);
|
|
3305
3398
|
this.service = service;
|
|
3306
3399
|
this.cdr = cdr;
|
|
3400
|
+
this.confirmDialog = confirmDialog;
|
|
3307
3401
|
this.isEdit = false;
|
|
3308
3402
|
this.projects = [];
|
|
3309
3403
|
this.isLoaded = false;
|
|
@@ -3340,19 +3434,20 @@ class UserProjectsComponent extends AppBaseComponent {
|
|
|
3340
3434
|
this.portfolios.getProjectPictures();
|
|
3341
3435
|
}
|
|
3342
3436
|
onDeleteProject(project) {
|
|
3343
|
-
|
|
3437
|
+
this.confirmDialog
|
|
3438
|
+
.open({
|
|
3344
3439
|
title: 'Delete',
|
|
3345
3440
|
text: `Are you sure you want to delete ${project.title}?`,
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
this.service.deleteProject(project.id).subscribe(() => {
|
|
3352
|
-
this.projects = this.projects.filter((x) => x.id !== project.id);
|
|
3353
|
-
this.cdr.markForCheck();
|
|
3354
|
-
});
|
|
3441
|
+
destructive: true
|
|
3442
|
+
})
|
|
3443
|
+
.then(ok => {
|
|
3444
|
+
if (!ok) {
|
|
3445
|
+
return;
|
|
3355
3446
|
}
|
|
3447
|
+
this.service.deleteProject(project.id).subscribe(() => {
|
|
3448
|
+
this.projects = this.projects.filter((x) => x.id !== project.id);
|
|
3449
|
+
this.cdr.markForCheck();
|
|
3450
|
+
});
|
|
3356
3451
|
});
|
|
3357
3452
|
}
|
|
3358
3453
|
trackByProject(_index, item) {
|
|
@@ -3364,13 +3459,13 @@ class UserProjectsComponent extends AppBaseComponent {
|
|
|
3364
3459
|
this.cdr.markForCheck();
|
|
3365
3460
|
});
|
|
3366
3461
|
}
|
|
3367
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: UserProjectsComponent, deps: [{ token: i1$2.ProfileService }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3368
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: UserProjectsComponent, isStandalone: false, selector: "pw-user-projects", inputs: { user: "user", isEdit: "isEdit", slug: "slug" }, viewQueries: [{ propertyName: "projectModal", first: true, predicate: EditProjectModalComponent, descendants: true, static: true }, { propertyName: "skillModal", first: true, predicate: EditSkillsModalComponent, descendants: true }, { propertyName: "recommendationModal", first: true, predicate: EditRecommendationModalComponent, descendants: true, static: true }, { propertyName: "portfolios", first: true, predicate: EditPortfoliosComponent, descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"row\">\n <div class=\"col-sm-12 mt-2\">\n <h2>User's Projects</h2>\n @if (isEdit) {\n <div class=\"row\"\n >\n <div class=\"col-12\">\n <div class=\"content-header\">\n <button class=\"btn btn-primary float-end\"\n (click)=\"onEditProject(null)\">\n <i class=\"fa fa-plus-circle\" aria-hidden=\"true\"></i> {{'Create Project' | transloco}}\n </button>\n </div>\n </div>\n </div>\n }\n @if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\"\n >\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n @if (projects?.length) {\n <div id=\"timeline\"\n class=\"timeline-center timeline-wrapper\"\n >\n <ul class=\"timeline\">\n <li class=\"timeline-line\"></li>\n </ul>\n <ul class=\"timeline\">\n <li class=\"timeline-line\"></li>\n @for (\n project of projects; track trackByProject(i,\n project); let i = $index; let odd = $odd; let even = $even) {\n <li class=\"timeline-item\"\n [ngClass]=\"{ 'mt-5': odd }\"\n >\n <div class=\"timeline-badge\">\n <span class=\"bg-red bg-lighten-1\"\n data-bs-toggle=\"tooltip\"\n data-placement=\"right\"\n title=\"Portfolio project work\">\n <span class=\"timeline-year\"> {{ project.start_year }} </span>\n </span>\n </div>\n <div class=\"timeline-card card pb-0\">\n <div class=\"card-header\">\n <h4 class=\"mb-0 card-title\">\n <a>{{ project.title }}</a>\n </h4>\n <div class=\"card-subtitle text-muted mt-0\">\n <span class=\"font-small-3\">\n {{ project.start_year }} - {{ project.end_year }}</span>\n </div>\n </div>\n <div class=\"card-body project-card\">\n @if (project.project_pictures?.length) {\n <i\n class=\"fal fa-times\"\n (click)=\"deletePicture(project)\"\n (keydown.enter)=\"deletePicture(project)\"\n aria-hidden=\"true\"\n ></i>\n <img class=\"img-fluid project-picture\"\n [src]=\"project.project_pictures[0].picture.url\"\n alt=\"Project Cover\" />\n }\n <div class=\"card-body\">\n <div class=\"\">\n <p class=\"card-text\">{{ project.description }}</p>\n <div class=\"list-inline mb-1\">\n <!-- Skills -->\n @if (project.tags?.length) {\n <div>\n <div class=\"my-2\">\n <i class=\"fa fa-user-tag\" aria-hidden=\"true\"></i>\n Skills\n </div>\n @for (tag of project.tags; track tag) {\n <span class=\"badge bg-success me-2\">{{\n tag.name\n }}</span>\n }\n </div>\n }\n @if (project.project_recommendations?.length) {\n <div class=\"mt-2\"\n >\n <div class=\"my-2\">\n <i\n class=\"fa fa-clipboard-check me-2\"\n aria-hidden=\"true\"\n ></i>\n Recommendations\n </div>\n @for (\n recommendation of project.project_recommendations\n ; track\n recommendation) {\n <section class=\"mb-2\"\n >\n <div class=\"me-2\">\n Client: {{ recommendation?.client_name }}\n </div>\n <div class=\"me-2\">\n Message: {{ recommendation?.description }}\n </div>\n <div class=\"row recommendation\">\n <div class=\"col-4\">\n <span>Communication</span>\n <p-rating [(ngModel)]=\"\n recommendation.communication\n \"\n [cancel]=\"false\"\n [readonly]=\"true\">\n </p-rating>\n </div>\n <div class=\"col-4\">\n <span>Quality</span>\n <p-rating [(ngModel)]=\"recommendation.quality\"\n [cancel]=\"false\"\n [readonly]=\"true\">\n </p-rating>\n </div>\n <div class=\"col-4\">\n <span>Time</span>\n <p-rating [(ngModel)]=\"recommendation.time\"\n [cancel]=\"false\"\n [readonly]=\"true\">\n </p-rating>\n </div>\n </div>\n </section>\n }\n </div>\n }\n @if (isEdit) {\n <div class=\"text-end mt-3 d-flex justify-content-end project-actions\"\n >\n <!-- Project Edit -->\n <span class=\"btn btn-link pb-0 actions\"\n (keydown.enter)=\"onEditProject(project)\"\n (click)=\"onEditProject(project)\">\n Edit\n </span>\n <button class=\"btn btn-link pb-0 actions\"\n (click)=\"openSkills(project)\">\n Skills\n </button>\n <pw-edit-skills-modal [userId]=\"user?.id\"\n entityEntity=\"Project\"\n entityType=\"skills\"\n (saveEvent)=\"onSkillsSave()\"\n [slug]=\"project?.slug\">\n </pw-edit-skills-modal>\n <!-- Portfolios -->\n <button class=\"btn btn-link pb-0 actions\"\n (click)=\"openPortfolios(project.id)\">\n Photos\n </button>\n <pw-edit-portfolios [slug]=\"user?.slug\"\n [id]=\"project.id\"\n (successEvent)=\"getProjects()\">\n </pw-edit-portfolios>\n <span class=\"btn btn-link pb-0 delete-project actions\"\n (keydown.enter)=\"onDeleteProject(project)\"\n (click)=\"onDeleteProject(project)\">\n Delete\n </span>\n </div>\n }\n <!-- Recommendation -->\n @if (!isEdit) {\n <span class=\"pe-1 mt-3\"\n (click)=\"editRecommendation(project)\"\n (keydown.enter)=\"editRecommendation(project)\"\n >\n <a class=\"primary\"><span class=\"fa fa-commenting-o\"></span> Endorse\n </a></span>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n </li>\n }\n </ul>\n </div>\n }\n @if (projects?.length === 0 && isLoaded) {\n<pw-no-data [withImage]=\"true\" [message]=\"\n isEdit\n ? ('User.Profile.Projects.NoProjects' | transloco)\n : ('User.Profile.Projects.NoUserProjects' | transloco)\n \"\n >\n </pw-no-data>\n }\n </div>\n</div>\n<pw-edit-project-modal (saveEvent)=\"onSaveProject($event)\"></pw-edit-project-modal>\n<pw-edit-recommendation-modal [user]=\"user\"></pw-edit-recommendation-modal>\n", styles: ["@charset \"UTF-8\";:root{--first: rgb(23 105 225);--second: rgb(54 194 131);--third: rgb(255 171 0);--text: rgb(34 34 34);--tabs_bg: rgb(23 105 225);--tabs_sub_bg: rgb(70, 136, 236);--tabs_text: rgb(255 255 255);--titles: rgb(34 34 34);--sidebar_bg: rgb(0, 48, 63);--sidebar_text: rgb(255 255 255)}.project-card{position:relative}.project-card i.fa-times{color:#fff;display:none;font-size:20px;position:absolute;right:39px;top:14px}.project-card:hover i.fa-times{display:inline}.timeline-card.card{min-height:auto;border:1px solid #e2e5ea;border-radius:10px;box-shadow:0 1px 2px #1018280f}.timeline-card.card .card-header{padding:14px 16px 6px}.timeline-card.card .badge.bg-success{border-radius:9999px;background-color:#e7f5ee!important;color:#1f7a47!important;border:1px solid #c9e9d6;font-weight:600}.timeline-card.card .card-body.project-card{padding:0 20px 1rem}.timeline-card.card .card-body.project-card .card-body{padding:20px 0 0}@media only screen and (max-width:767px){.timeline-center{margin-top:30px}.timeline-center .project-actions .btn{padding:.375rem .5rem}}.actions{color:var(--first)!important}.timeline-badge .bg-red.bg-lighten-1{background-color:#eef0f3!important}.timeline-badge .bg-red.bg-lighten-1 .timeline-year{color:#3d4654}\n"], dependencies: [{ kind: "directive", type: i4.LazyImgDirective, selector: "img" }, { kind: "directive", type: i6.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "component", type: i4$1.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i5.NoDataComponent, selector: "pw-no-data", inputs: ["message", "description", "withImage"] }, { kind: "component", type: i6$5.Rating, selector: "p-rating", inputs: ["readonly", "stars", "iconOnClass", "iconOnStyle", "iconOffClass", "iconOffStyle", "autofocus"], outputs: ["onRate", "onFocus", "onBlur"] }, { kind: "component", type: EditPortfoliosComponent, selector: "pw-edit-portfolios", inputs: ["id", "slug"], outputs: ["successEvent"] }, { kind: "component", type: EditProjectModalComponent, selector: "pw-edit-project-modal", outputs: ["cancelEvent", "saveEvent"] }, { kind: "component", type: EditRecommendationModalComponent, selector: "pw-edit-recommendation-modal", inputs: ["user"] }, { kind: "component", type: EditSkillsModalComponent, selector: "pw-edit-skills-modal", inputs: ["userId", "slug", "entityType", "entityEntity"], outputs: ["saveEvent"] }, { kind: "pipe", type: i8.TranslocoPipe, name: "transloco" }] }); }
|
|
3462
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: UserProjectsComponent, deps: [{ token: i1$2.ProfileService }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }, { token: i5.ConfirmDialogService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3463
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: UserProjectsComponent, isStandalone: false, selector: "pw-user-projects", inputs: { user: "user", isEdit: "isEdit", slug: "slug" }, viewQueries: [{ propertyName: "projectModal", first: true, predicate: EditProjectModalComponent, descendants: true, static: true }, { propertyName: "skillModal", first: true, predicate: EditSkillsModalComponent, descendants: true }, { propertyName: "recommendationModal", first: true, predicate: EditRecommendationModalComponent, descendants: true, static: true }, { propertyName: "portfolios", first: true, predicate: EditPortfoliosComponent, descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"row\">\n <div class=\"col-sm-12 mt-2\">\n <h2>User's Projects</h2>\n @if (isEdit) {\n <div class=\"row\"\n >\n <div class=\"col-12\">\n <div class=\"content-header\">\n <button class=\"btn btn-primary float-end\"\n (click)=\"onEditProject(null)\">\n <i class=\"fa fa-plus-circle\" aria-hidden=\"true\"></i> {{'Create Project' | transloco}}\n </button>\n </div>\n </div>\n </div>\n }\n @if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\"\n >\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n @if (projects?.length) {\n <div id=\"timeline\"\n class=\"timeline-center timeline-wrapper\"\n >\n <ul class=\"timeline\">\n <li class=\"timeline-line\"></li>\n </ul>\n <ul class=\"timeline\">\n <li class=\"timeline-line\"></li>\n @for (\n project of projects; track trackByProject(i,\n project); let i = $index; let odd = $odd; let even = $even) {\n <li class=\"timeline-item\"\n [ngClass]=\"{ 'mt-5': odd }\"\n >\n <div class=\"timeline-badge\">\n <span class=\"bg-red bg-lighten-1\"\n data-bs-toggle=\"tooltip\"\n data-placement=\"right\"\n title=\"Portfolio project work\">\n <span class=\"timeline-year\"> {{ project.start_year }} </span>\n </span>\n </div>\n <div class=\"timeline-card card pb-0\">\n <div class=\"card-header\">\n <h4 class=\"mb-0 card-title\">\n <a>{{ project.title }}</a>\n </h4>\n <div class=\"card-subtitle text-muted mt-0\">\n <span class=\"font-small-3\">\n {{ project.start_year }} - {{ project.end_year }}</span>\n </div>\n </div>\n <div class=\"card-body project-card\">\n @if (project.project_pictures?.length) {\n <i\n class=\"fal fa-times\"\n (click)=\"deletePicture(project)\"\n (keydown.enter)=\"deletePicture(project)\"\n aria-hidden=\"true\"\n ></i>\n <img class=\"img-fluid project-picture\"\n [src]=\"project.project_pictures[0].picture.url\"\n alt=\"Project Cover\" />\n }\n <div class=\"card-body\">\n <div class=\"\">\n <p class=\"card-text\">{{ project.description }}</p>\n <div class=\"list-inline mb-1\">\n <!-- Skills -->\n @if (project.tags?.length) {\n <div>\n <div class=\"my-2\">\n <i class=\"fa fa-user-tag\" aria-hidden=\"true\"></i>\n Skills\n </div>\n @for (tag of project.tags; track tag) {\n <span class=\"badge bg-success me-2\">{{\n tag.name\n }}</span>\n }\n </div>\n }\n @if (project.project_recommendations?.length) {\n <div class=\"mt-2\"\n >\n <div class=\"my-2\">\n <i\n class=\"fa fa-clipboard-check me-2\"\n aria-hidden=\"true\"\n ></i>\n Recommendations\n </div>\n @for (\n recommendation of project.project_recommendations\n ; track\n recommendation) {\n <section class=\"mb-2\"\n >\n <div class=\"me-2\">\n Client: {{ recommendation?.client_name }}\n </div>\n <div class=\"me-2\">\n Message: {{ recommendation?.description }}\n </div>\n <div class=\"row recommendation\">\n <div class=\"col-4\">\n <span>Communication</span>\n <p-rating [(ngModel)]=\"\n recommendation.communication\n \"\n [cancel]=\"false\"\n [readonly]=\"true\">\n </p-rating>\n </div>\n <div class=\"col-4\">\n <span>Quality</span>\n <p-rating [(ngModel)]=\"recommendation.quality\"\n [cancel]=\"false\"\n [readonly]=\"true\">\n </p-rating>\n </div>\n <div class=\"col-4\">\n <span>Time</span>\n <p-rating [(ngModel)]=\"recommendation.time\"\n [cancel]=\"false\"\n [readonly]=\"true\">\n </p-rating>\n </div>\n </div>\n </section>\n }\n </div>\n }\n @if (isEdit) {\n <div class=\"text-end mt-3 d-flex justify-content-end project-actions\"\n >\n <!-- Project Edit -->\n <span class=\"btn btn-link pb-0 actions\"\n (keydown.enter)=\"onEditProject(project)\"\n (click)=\"onEditProject(project)\">\n Edit\n </span>\n <button class=\"btn btn-link pb-0 actions\"\n (click)=\"openSkills(project)\">\n Skills\n </button>\n <pw-edit-skills-modal [userId]=\"user?.id\"\n entityEntity=\"Project\"\n entityType=\"skills\"\n (saveEvent)=\"onSkillsSave()\"\n [slug]=\"project?.slug\">\n </pw-edit-skills-modal>\n <!-- Portfolios -->\n <button class=\"btn btn-link pb-0 actions\"\n (click)=\"openPortfolios(project.id)\">\n Photos\n </button>\n <pw-edit-portfolios [slug]=\"user?.slug\"\n [id]=\"project.id\"\n (successEvent)=\"getProjects()\">\n </pw-edit-portfolios>\n <span class=\"btn btn-link pb-0 delete-project actions\"\n (keydown.enter)=\"onDeleteProject(project)\"\n (click)=\"onDeleteProject(project)\">\n Delete\n </span>\n </div>\n }\n <!-- Recommendation -->\n @if (!isEdit) {\n <span class=\"pe-1 mt-3\"\n (click)=\"editRecommendation(project)\"\n (keydown.enter)=\"editRecommendation(project)\"\n >\n <a class=\"primary\"><span class=\"fa fa-commenting-o\"></span> Endorse\n </a></span>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n </li>\n }\n </ul>\n </div>\n }\n @if (projects?.length === 0 && isLoaded) {\n<pw-no-data [withImage]=\"true\" [message]=\"\n isEdit\n ? ('User.Profile.Projects.NoProjects' | transloco)\n : ('User.Profile.Projects.NoUserProjects' | transloco)\n \"\n >\n </pw-no-data>\n }\n </div>\n</div>\n<pw-edit-project-modal (saveEvent)=\"onSaveProject($event)\"></pw-edit-project-modal>\n<pw-edit-recommendation-modal [user]=\"user\"></pw-edit-recommendation-modal>\n", styles: ["@charset \"UTF-8\";:root{--first: rgb(23 105 225);--second: rgb(54 194 131);--third: rgb(255 171 0);--text: rgb(34 34 34);--tabs_bg: rgb(23 105 225);--tabs_sub_bg: rgb(70, 136, 236);--tabs_text: rgb(255 255 255);--titles: rgb(34 34 34);--sidebar_bg: rgb(0, 48, 63);--sidebar_text: rgb(255 255 255)}.project-card{position:relative}.project-card i.fa-times{color:#fff;display:none;font-size:20px;position:absolute;right:39px;top:14px}.project-card:hover i.fa-times{display:inline}.timeline-card.card{min-height:auto;border:1px solid #e2e5ea;border-radius:10px;box-shadow:0 1px 2px #1018280f}.timeline-card.card .card-header{padding:14px 16px 6px}.timeline-card.card .badge.bg-success{border-radius:9999px;background-color:#e7f5ee!important;color:#1f7a47!important;border:1px solid #c9e9d6;font-weight:600}.timeline-card.card .card-body.project-card{padding:0 20px 1rem}.timeline-card.card .card-body.project-card .card-body{padding:20px 0 0}@media only screen and (max-width:767px){.timeline-center{margin-top:30px}.timeline-center .project-actions .btn{padding:.375rem .5rem}}.actions{color:var(--first)!important}.timeline-badge .bg-red.bg-lighten-1{background-color:#eef0f3!important}.timeline-badge .bg-red.bg-lighten-1 .timeline-year{color:#3d4654}\n"], dependencies: [{ kind: "directive", type: i3.LazyImgDirective, selector: "img" }, { kind: "directive", type: i8.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: i5.NoDataComponent, selector: "pw-no-data", inputs: ["message", "description", "withImage"] }, { kind: "component", type: i6$2.Rating, selector: "p-rating", inputs: ["readonly", "stars", "iconOnClass", "iconOnStyle", "iconOffClass", "iconOffStyle", "autofocus"], outputs: ["onRate", "onFocus", "onBlur"] }, { kind: "component", type: EditPortfoliosComponent, selector: "pw-edit-portfolios", inputs: ["id", "slug"], outputs: ["successEvent"] }, { kind: "component", type: EditProjectModalComponent, selector: "pw-edit-project-modal", outputs: ["cancelEvent", "saveEvent"] }, { kind: "component", type: EditRecommendationModalComponent, selector: "pw-edit-recommendation-modal", inputs: ["user"] }, { kind: "component", type: EditSkillsModalComponent, selector: "pw-edit-skills-modal", inputs: ["userId", "slug", "entityType", "entityEntity"], outputs: ["saveEvent"] }, { kind: "pipe", type: i8$2.TranslocoPipe, name: "transloco" }] }); }
|
|
3369
3464
|
}
|
|
3370
3465
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: UserProjectsComponent, decorators: [{
|
|
3371
3466
|
type: Component,
|
|
3372
3467
|
args: [{ selector: 'pw-user-projects', standalone: false, template: "<div class=\"row\">\n <div class=\"col-sm-12 mt-2\">\n <h2>User's Projects</h2>\n @if (isEdit) {\n <div class=\"row\"\n >\n <div class=\"col-12\">\n <div class=\"content-header\">\n <button class=\"btn btn-primary float-end\"\n (click)=\"onEditProject(null)\">\n <i class=\"fa fa-plus-circle\" aria-hidden=\"true\"></i> {{'Create Project' | transloco}}\n </button>\n </div>\n </div>\n </div>\n }\n @if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\"\n >\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n @if (projects?.length) {\n <div id=\"timeline\"\n class=\"timeline-center timeline-wrapper\"\n >\n <ul class=\"timeline\">\n <li class=\"timeline-line\"></li>\n </ul>\n <ul class=\"timeline\">\n <li class=\"timeline-line\"></li>\n @for (\n project of projects; track trackByProject(i,\n project); let i = $index; let odd = $odd; let even = $even) {\n <li class=\"timeline-item\"\n [ngClass]=\"{ 'mt-5': odd }\"\n >\n <div class=\"timeline-badge\">\n <span class=\"bg-red bg-lighten-1\"\n data-bs-toggle=\"tooltip\"\n data-placement=\"right\"\n title=\"Portfolio project work\">\n <span class=\"timeline-year\"> {{ project.start_year }} </span>\n </span>\n </div>\n <div class=\"timeline-card card pb-0\">\n <div class=\"card-header\">\n <h4 class=\"mb-0 card-title\">\n <a>{{ project.title }}</a>\n </h4>\n <div class=\"card-subtitle text-muted mt-0\">\n <span class=\"font-small-3\">\n {{ project.start_year }} - {{ project.end_year }}</span>\n </div>\n </div>\n <div class=\"card-body project-card\">\n @if (project.project_pictures?.length) {\n <i\n class=\"fal fa-times\"\n (click)=\"deletePicture(project)\"\n (keydown.enter)=\"deletePicture(project)\"\n aria-hidden=\"true\"\n ></i>\n <img class=\"img-fluid project-picture\"\n [src]=\"project.project_pictures[0].picture.url\"\n alt=\"Project Cover\" />\n }\n <div class=\"card-body\">\n <div class=\"\">\n <p class=\"card-text\">{{ project.description }}</p>\n <div class=\"list-inline mb-1\">\n <!-- Skills -->\n @if (project.tags?.length) {\n <div>\n <div class=\"my-2\">\n <i class=\"fa fa-user-tag\" aria-hidden=\"true\"></i>\n Skills\n </div>\n @for (tag of project.tags; track tag) {\n <span class=\"badge bg-success me-2\">{{\n tag.name\n }}</span>\n }\n </div>\n }\n @if (project.project_recommendations?.length) {\n <div class=\"mt-2\"\n >\n <div class=\"my-2\">\n <i\n class=\"fa fa-clipboard-check me-2\"\n aria-hidden=\"true\"\n ></i>\n Recommendations\n </div>\n @for (\n recommendation of project.project_recommendations\n ; track\n recommendation) {\n <section class=\"mb-2\"\n >\n <div class=\"me-2\">\n Client: {{ recommendation?.client_name }}\n </div>\n <div class=\"me-2\">\n Message: {{ recommendation?.description }}\n </div>\n <div class=\"row recommendation\">\n <div class=\"col-4\">\n <span>Communication</span>\n <p-rating [(ngModel)]=\"\n recommendation.communication\n \"\n [cancel]=\"false\"\n [readonly]=\"true\">\n </p-rating>\n </div>\n <div class=\"col-4\">\n <span>Quality</span>\n <p-rating [(ngModel)]=\"recommendation.quality\"\n [cancel]=\"false\"\n [readonly]=\"true\">\n </p-rating>\n </div>\n <div class=\"col-4\">\n <span>Time</span>\n <p-rating [(ngModel)]=\"recommendation.time\"\n [cancel]=\"false\"\n [readonly]=\"true\">\n </p-rating>\n </div>\n </div>\n </section>\n }\n </div>\n }\n @if (isEdit) {\n <div class=\"text-end mt-3 d-flex justify-content-end project-actions\"\n >\n <!-- Project Edit -->\n <span class=\"btn btn-link pb-0 actions\"\n (keydown.enter)=\"onEditProject(project)\"\n (click)=\"onEditProject(project)\">\n Edit\n </span>\n <button class=\"btn btn-link pb-0 actions\"\n (click)=\"openSkills(project)\">\n Skills\n </button>\n <pw-edit-skills-modal [userId]=\"user?.id\"\n entityEntity=\"Project\"\n entityType=\"skills\"\n (saveEvent)=\"onSkillsSave()\"\n [slug]=\"project?.slug\">\n </pw-edit-skills-modal>\n <!-- Portfolios -->\n <button class=\"btn btn-link pb-0 actions\"\n (click)=\"openPortfolios(project.id)\">\n Photos\n </button>\n <pw-edit-portfolios [slug]=\"user?.slug\"\n [id]=\"project.id\"\n (successEvent)=\"getProjects()\">\n </pw-edit-portfolios>\n <span class=\"btn btn-link pb-0 delete-project actions\"\n (keydown.enter)=\"onDeleteProject(project)\"\n (click)=\"onDeleteProject(project)\">\n Delete\n </span>\n </div>\n }\n <!-- Recommendation -->\n @if (!isEdit) {\n <span class=\"pe-1 mt-3\"\n (click)=\"editRecommendation(project)\"\n (keydown.enter)=\"editRecommendation(project)\"\n >\n <a class=\"primary\"><span class=\"fa fa-commenting-o\"></span> Endorse\n </a></span>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n </li>\n }\n </ul>\n </div>\n }\n @if (projects?.length === 0 && isLoaded) {\n<pw-no-data [withImage]=\"true\" [message]=\"\n isEdit\n ? ('User.Profile.Projects.NoProjects' | transloco)\n : ('User.Profile.Projects.NoUserProjects' | transloco)\n \"\n >\n </pw-no-data>\n }\n </div>\n</div>\n<pw-edit-project-modal (saveEvent)=\"onSaveProject($event)\"></pw-edit-project-modal>\n<pw-edit-recommendation-modal [user]=\"user\"></pw-edit-recommendation-modal>\n", styles: ["@charset \"UTF-8\";:root{--first: rgb(23 105 225);--second: rgb(54 194 131);--third: rgb(255 171 0);--text: rgb(34 34 34);--tabs_bg: rgb(23 105 225);--tabs_sub_bg: rgb(70, 136, 236);--tabs_text: rgb(255 255 255);--titles: rgb(34 34 34);--sidebar_bg: rgb(0, 48, 63);--sidebar_text: rgb(255 255 255)}.project-card{position:relative}.project-card i.fa-times{color:#fff;display:none;font-size:20px;position:absolute;right:39px;top:14px}.project-card:hover i.fa-times{display:inline}.timeline-card.card{min-height:auto;border:1px solid #e2e5ea;border-radius:10px;box-shadow:0 1px 2px #1018280f}.timeline-card.card .card-header{padding:14px 16px 6px}.timeline-card.card .badge.bg-success{border-radius:9999px;background-color:#e7f5ee!important;color:#1f7a47!important;border:1px solid #c9e9d6;font-weight:600}.timeline-card.card .card-body.project-card{padding:0 20px 1rem}.timeline-card.card .card-body.project-card .card-body{padding:20px 0 0}@media only screen and (max-width:767px){.timeline-center{margin-top:30px}.timeline-center .project-actions .btn{padding:.375rem .5rem}}.actions{color:var(--first)!important}.timeline-badge .bg-red.bg-lighten-1{background-color:#eef0f3!important}.timeline-badge .bg-red.bg-lighten-1 .timeline-year{color:#3d4654}\n"] }]
|
|
3373
|
-
}], ctorParameters: () => [{ type: i1$2.ProfileService }, { type: i0.Injector }, { type: i0.ChangeDetectorRef }], propDecorators: { user: [{
|
|
3468
|
+
}], ctorParameters: () => [{ type: i1$2.ProfileService }, { type: i0.Injector }, { type: i0.ChangeDetectorRef }, { type: i5.ConfirmDialogService }], propDecorators: { user: [{
|
|
3374
3469
|
type: Input
|
|
3375
3470
|
}], isEdit: [{
|
|
3376
3471
|
type: Input
|
|
@@ -3583,7 +3678,7 @@ class UserProfilePageComponent extends AppBaseComponent {
|
|
|
3583
3678
|
super.ngOnDestroy();
|
|
3584
3679
|
}
|
|
3585
3680
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: UserProfilePageComponent, deps: [{ token: i0.Injector }, { token: i1$2.ProfileService }, { token: i1$1.NgbModal }, { token: i1$2.ScriptLoaderService }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3586
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: UserProfilePageComponent, isStandalone: false, selector: "pw-user-profile-page", usesInheritance: true, ngImport: i0, template: "<!-- User Profile Starts -->\n<!-- Basic User Details Starts -->\n@if (user) {\n <section id=\"user-profile\"\n >\n <div class=\"row\">\n <div class=\"col-12\">\n <div class=\"dashboard\">\n <div class=\"media row py-3 align-items-center\">\n <div class=\"col-3 col-sm-2\">\n <div class=\"align-self-center halfway-fab text-center\">\n <!-- User Avatar -->\n <a class=\"profile-image\">\n <img [src]=\"image\"\n width=\"100\"\n height=\"100\"\n class=\"rounded-circle img-border width-100\"\n alt=\"User Male\"\n (error)=\"handleImageError($event, 'assets/img/icons/male.png')\"\n (keydown.enter)=\"openModal(content)\"\n (click)=\"openModal(content)\" />\n @if (allowEdit) {\n <div class=\"overlay\"\n (keydown.enter)=\"openModal(content)\"\n (click)=\"openModal(content)\"\n >\n <div class=\"overlay-text\">\n <!-- Change Profile Pic -->\n <a aria-label=\"Navigate to Target\">\n {{ 'User.Profile.Change' | transloco }}\n </a>\n </div>\n </div>\n }\n </a>\n </div>\n </div>\n <div class=\"col-9 col-sm-5\">\n <div class=\"align-self-start halfway-fab ps-3 pt-2\">\n <div>\n @if (user?.last_name) {\n <strong class=\"font-medium-2 text-uppercase\"\n >\n {{\n user?.first_name\n ? user?.first_name + ' ' + user?.last_name\n : 'Update Profile'\n }}\n </strong>\n }\n @if (!user?.last_name) {\n <strong class=\"font-medium-2 text-uppercase\"\n >\n {{ user?.first_name ? user?.first_name : 'Update Profile' }}\n </strong>\n }\n <p class=\"font-small-4\">{{ userProfile?.headline }}</p>\n </div>\n </div>\n </div>\n <div class=\"col-12 col-sm-5\">\n @if (!allowEdit) {\n <div class=\"profile-cover-buttons\"\n >\n <div class=\"d-flex halfway-fab align-self-end\">\n <div class=\"text-end d-none d-sm-none d-md-none d-lg-block\">\n <button type=\"button\"\n (click)=\"followUser()\"\n class=\"btn btn-outline-primary btn-raised me-2\">\n <i class=\"fa fa-plus\" aria-hidden=\"true\"></i>\n {{ isFollowing ? 'Following' : 'Follow' }}\n </button>\n <button type=\"button\"\n class=\"btn btn-primary btn-raised me-3\"\n (click)=\"sendMessageSlug()\">\n <i class=\"fa fa-mail-bulk\" aria-hidden=\"true\"></i> Message\n </button>\n </div>\n <div class=\"text-end d-block d-sm-block d-md-block d-lg-none\">\n <button type=\"button\"\n class=\"btn btn-primary btn-raised me-2\">\n <i class=\"fa fa-plus\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\"\n class=\"btn btn-primary btn-raised me-3\">\n <i class=\"fa fa-mail-bulk\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n </section>\n}\n<!-- Basic User Details Ends -->\n<section>\n <div class=\"container-fluid pw-tab overflow-hidden\">\n <p-tabs [value]=\"activeTabValue\" (valueChange)=\"onTabChange($event)\">\n <p-tablist>\n @for (item of items; track item) {\n <p-tab [value]=\"item.id\">\n @if (item.icon) {\n <i [class]=\"item.icon\" aria-hidden=\"true\"></i>\n }\n <span>{{ item.label }}</span>\n </p-tab>\n }\n </p-tablist>\n </p-tabs>\n <div class=\"dashboard\">\n <div class=\"dashboard-body\">\n @if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\"\n >\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n @if (user && activeItem.id === 'about') {\n <pw-user-about [user]=\"user\"\n [isEdit]=\"allowEdit\"\n (saveEvent)=\"getUserBySlug()\">\n </pw-user-about>\n }\n @if (activeItem.id === 'projects') {\n <pw-user-projects [user]=\"user\"\n [slug]=\"slug\"\n [isEdit]=\"allowEdit\"></pw-user-projects>\n }\n @if (activeItem.id === 'portfolio') {\n <pw-portfolios [user]=\"user\"\n [isEdit]=\"allowEdit\"></pw-portfolios>\n }\n </div>\n </div>\n </div>\n</section>\n<ng-template #content\n let-modal>\n <div class=\"card m-0\">\n <div class=\"card-content\">\n <div class=\"card-title\">\n <h3 class=\"modal-title\">{{ 'User.Profile.ProfilePicture' | transloco }}</h3>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"card-header\">\n <small> {{ 'User.Profile.PictureMessage' | transloco }}</small>\n <pw-image-cropper #profile\n aspectRatio=\"auto\"\n [userAvatar]=\"image\"\n (imageSelectionEvent)=\"onImageSelection($event)\"\n (closeEvent)=\"onClose()\">\n </pw-image-cropper>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:root{--first: rgb(23 105 225);--second: rgb(54 194 131);--third: rgb(255 171 0);--text: rgb(34 34 34);--tabs_bg: rgb(23 105 225);--tabs_sub_bg: rgb(70, 136, 236);--tabs_text: rgb(255 255 255);--titles: rgb(34 34 34);--sidebar_bg: rgb(0, 48, 63);--sidebar_text: rgb(255 255 255)}.card-body{padding:10px!important}.py-3{padding-top:4rem!important;padding-bottom:0rem!important}.overlay-text{margin-top:5px;text-align:center}.profile-image img.rounded-circle{max-width:100%;height:auto;box-sizing:border-box}::ng-deep .pw-tab .p-tabs .p-tab.p-highlight,::ng-deep .pw-tab .p-tabs .p-tab[aria-selected=true]{background-color:#1769e1!important;box-shadow:none!important;color:#fff!important}::ng-deep .pw-tab .p-tabs .p-tab.p-highlight:hover,::ng-deep .pw-tab .p-tabs .p-tab[aria-selected=true]:hover{background-color:#1769e1!important;color:#fff!important}\n"], dependencies: [{ kind: "directive", type:
|
|
3681
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.6", type: UserProfilePageComponent, isStandalone: false, selector: "pw-user-profile-page", usesInheritance: true, ngImport: i0, template: "<!-- User Profile Starts -->\n<!-- Basic User Details Starts -->\n@if (user) {\n <section id=\"user-profile\"\n >\n <div class=\"row\">\n <div class=\"col-12\">\n <div class=\"dashboard\">\n <div class=\"media row py-3 align-items-center\">\n <div class=\"col-3 col-sm-2\">\n <div class=\"align-self-center halfway-fab text-center\">\n <!-- User Avatar -->\n <a class=\"profile-image\">\n <img [src]=\"image\"\n width=\"100\"\n height=\"100\"\n class=\"rounded-circle img-border width-100\"\n alt=\"User Male\"\n (error)=\"handleImageError($event, 'assets/img/icons/male.png')\"\n (keydown.enter)=\"openModal(content)\"\n (click)=\"openModal(content)\" />\n @if (allowEdit) {\n <div class=\"overlay\"\n (keydown.enter)=\"openModal(content)\"\n (click)=\"openModal(content)\"\n >\n <div class=\"overlay-text\">\n <!-- Change Profile Pic -->\n <a aria-label=\"Navigate to Target\">\n {{ 'User.Profile.Change' | transloco }}\n </a>\n </div>\n </div>\n }\n </a>\n </div>\n </div>\n <div class=\"col-9 col-sm-5\">\n <div class=\"align-self-start halfway-fab ps-3 pt-2\">\n <div>\n @if (user?.last_name) {\n <strong class=\"font-medium-2 text-uppercase\"\n >\n {{\n user?.first_name\n ? user?.first_name + ' ' + user?.last_name\n : 'Update Profile'\n }}\n </strong>\n }\n @if (!user?.last_name) {\n <strong class=\"font-medium-2 text-uppercase\"\n >\n {{ user?.first_name ? user?.first_name : 'Update Profile' }}\n </strong>\n }\n <p class=\"font-small-4\">{{ userProfile?.headline }}</p>\n </div>\n </div>\n </div>\n <div class=\"col-12 col-sm-5\">\n @if (!allowEdit) {\n <div class=\"profile-cover-buttons\"\n >\n <div class=\"d-flex halfway-fab align-self-end\">\n <div class=\"text-end d-none d-sm-none d-md-none d-lg-block\">\n <button type=\"button\"\n (click)=\"followUser()\"\n class=\"btn btn-outline-primary btn-raised me-2\">\n <i class=\"fa fa-plus\" aria-hidden=\"true\"></i>\n {{ isFollowing ? 'Following' : 'Follow' }}\n </button>\n <button type=\"button\"\n class=\"btn btn-primary btn-raised me-3\"\n (click)=\"sendMessageSlug()\">\n <i class=\"fa fa-mail-bulk\" aria-hidden=\"true\"></i> Message\n </button>\n </div>\n <div class=\"text-end d-block d-sm-block d-md-block d-lg-none\">\n <button type=\"button\"\n class=\"btn btn-primary btn-raised me-2\">\n <i class=\"fa fa-plus\" aria-hidden=\"true\"></i>\n </button>\n <button type=\"button\"\n class=\"btn btn-primary btn-raised me-3\">\n <i class=\"fa fa-mail-bulk\" aria-hidden=\"true\"></i>\n </button>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n </section>\n}\n<!-- Basic User Details Ends -->\n<section>\n <div class=\"container-fluid pw-tab overflow-hidden\">\n <p-tabs [value]=\"activeTabValue\" (valueChange)=\"onTabChange($event)\">\n <p-tablist>\n @for (item of items; track item) {\n <p-tab [value]=\"item.id\">\n @if (item.icon) {\n <i [class]=\"item.icon\" aria-hidden=\"true\"></i>\n }\n <span>{{ item.label }}</span>\n </p-tab>\n }\n </p-tablist>\n </p-tabs>\n <div class=\"dashboard\">\n <div class=\"dashboard-body\">\n @if (!isLoaded) {\n <div class=\"w-100 text-center mt-3\"\n >\n <p-progressSpinner strokeWidth=\"2\"> </p-progressSpinner>\n </div>\n }\n @if (user && activeItem.id === 'about') {\n <pw-user-about [user]=\"user\"\n [isEdit]=\"allowEdit\"\n (saveEvent)=\"getUserBySlug()\">\n </pw-user-about>\n }\n @if (activeItem.id === 'projects') {\n <pw-user-projects [user]=\"user\"\n [slug]=\"slug\"\n [isEdit]=\"allowEdit\"></pw-user-projects>\n }\n @if (activeItem.id === 'portfolio') {\n <pw-portfolios [user]=\"user\"\n [isEdit]=\"allowEdit\"></pw-portfolios>\n }\n </div>\n </div>\n </div>\n</section>\n<ng-template #content\n let-modal>\n <div class=\"card m-0\">\n <div class=\"card-content\">\n <div class=\"card-title\">\n <h3 class=\"modal-title\">{{ 'User.Profile.ProfilePicture' | transloco }}</h3>\n <button type=\"button\"\n class=\"btn-close float-end\"\n aria-label=\"Close\"\n (click)=\"modal.dismiss()\">\n\n </button>\n </div>\n <div class=\"card-header\">\n <small> {{ 'User.Profile.PictureMessage' | transloco }}</small>\n <pw-image-cropper #profile\n aspectRatio=\"auto\"\n [userAvatar]=\"image\"\n (imageSelectionEvent)=\"onImageSelection($event)\"\n (closeEvent)=\"onClose()\">\n </pw-image-cropper>\n </div>\n </div>\n </div>\n</ng-template>\n", styles: ["@charset \"UTF-8\";:root{--first: rgb(23 105 225);--second: rgb(54 194 131);--third: rgb(255 171 0);--text: rgb(34 34 34);--tabs_bg: rgb(23 105 225);--tabs_sub_bg: rgb(70, 136, 236);--tabs_text: rgb(255 255 255);--titles: rgb(34 34 34);--sidebar_bg: rgb(0, 48, 63);--sidebar_text: rgb(255 255 255)}.card-body{padding:10px!important}.py-3{padding-top:4rem!important;padding-bottom:0rem!important}.overlay-text{margin-top:5px;text-align:center}.profile-image img.rounded-circle{max-width:100%;height:auto;box-sizing:border-box}::ng-deep .pw-tab .p-tabs .p-tab.p-highlight,::ng-deep .pw-tab .p-tabs .p-tab[aria-selected=true]{background-color:#1769e1!important;box-shadow:none!important;color:#fff!important}::ng-deep .pw-tab .p-tabs .p-tab.p-highlight:hover,::ng-deep .pw-tab .p-tabs .p-tab[aria-selected=true]:hover{background-color:#1769e1!important;color:#fff!important}\n"], dependencies: [{ kind: "directive", type: i3.LazyImgDirective, selector: "img" }, { kind: "component", type: i4$4.Tabs, selector: "p-tabs", inputs: ["value", "scrollable", "lazy", "selectOnFocus", "showNavigators", "tabindex"], outputs: ["valueChange"] }, { kind: "component", type: i4$4.TabList, selector: "p-tablist" }, { kind: "component", type: i4$4.Tab, selector: "p-tab", inputs: ["value", "disabled"], outputs: ["valueChange"] }, { kind: "component", type: i4.ProgressSpinner, selector: "p-progressSpinner, p-progress-spinner, p-progressspinner", inputs: ["styleClass", "strokeWidth", "fill", "animationDuration", "ariaLabel"] }, { kind: "component", type: i10.ProfileImageCropperComponent, selector: "pw-image-cropper", inputs: ["aspectRatio", "dynamicData"], outputs: ["imageSelectionEvent", "closeEvent", "fileChangeEvent"] }, { kind: "component", type: UserAboutComponent, selector: "pw-user-about", inputs: ["user", "isEdit"], outputs: ["saveEvent"] }, { kind: "component", type: PortfoliosComponent, selector: "pw-portfolios", inputs: ["user", "isEdit"] }, { kind: "component", type: UserProjectsComponent, selector: "pw-user-projects", inputs: ["user", "isEdit", "slug"] }, { kind: "pipe", type: i8$2.TranslocoPipe, name: "transloco" }] }); }
|
|
3587
3682
|
}
|
|
3588
3683
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImport: i0, type: UserProfilePageComponent, decorators: [{
|
|
3589
3684
|
type: Component,
|
|
@@ -3609,6 +3704,10 @@ class UserModuleModule {
|
|
|
3609
3704
|
AddSubscriptionComponent,
|
|
3610
3705
|
SavedCardDetailsComponent,
|
|
3611
3706
|
SubscriptionCredentialComponent,
|
|
3707
|
+
HumanizeCredentialNamePipe,
|
|
3708
|
+
CredentialAvatarHuePipe,
|
|
3709
|
+
SubscriptionNameByIdPipe,
|
|
3710
|
+
ClearMaskedOnFocusDirective,
|
|
3612
3711
|
UpdatePaymentDetailsComponent,
|
|
3613
3712
|
UpgradeSubscriptionComponent,
|
|
3614
3713
|
UserSubscriptionDetailsComponent,
|
|
@@ -3631,6 +3730,7 @@ class UserModuleModule {
|
|
|
3631
3730
|
UserProfilePageComponent,
|
|
3632
3731
|
UserProjectsComponent,
|
|
3633
3732
|
SupportDetailsComponent], imports: [InputTextModule,
|
|
3733
|
+
AppLoaderModule,
|
|
3634
3734
|
DirectivesModule,
|
|
3635
3735
|
CommonModule,
|
|
3636
3736
|
RouterModule,
|
|
@@ -3654,6 +3754,10 @@ class UserModuleModule {
|
|
|
3654
3754
|
AddSubscriptionComponent,
|
|
3655
3755
|
SavedCardDetailsComponent,
|
|
3656
3756
|
SubscriptionCredentialComponent,
|
|
3757
|
+
HumanizeCredentialNamePipe,
|
|
3758
|
+
CredentialAvatarHuePipe,
|
|
3759
|
+
SubscriptionNameByIdPipe,
|
|
3760
|
+
ClearMaskedOnFocusDirective,
|
|
3657
3761
|
UpdatePaymentDetailsComponent,
|
|
3658
3762
|
UpgradeSubscriptionComponent,
|
|
3659
3763
|
UserSubscriptionDetailsComponent,
|
|
@@ -3688,6 +3792,7 @@ class UserModuleModule {
|
|
|
3688
3792
|
deps: [AppConfigService]
|
|
3689
3793
|
}
|
|
3690
3794
|
], imports: [InputTextModule,
|
|
3795
|
+
AppLoaderModule,
|
|
3691
3796
|
DirectivesModule,
|
|
3692
3797
|
CommonModule,
|
|
3693
3798
|
RouterModule,
|
|
@@ -3709,6 +3814,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
|
|
|
3709
3814
|
AddSubscriptionComponent,
|
|
3710
3815
|
SavedCardDetailsComponent,
|
|
3711
3816
|
SubscriptionCredentialComponent,
|
|
3817
|
+
HumanizeCredentialNamePipe,
|
|
3818
|
+
CredentialAvatarHuePipe,
|
|
3819
|
+
SubscriptionNameByIdPipe,
|
|
3820
|
+
ClearMaskedOnFocusDirective,
|
|
3712
3821
|
UpdatePaymentDetailsComponent,
|
|
3713
3822
|
UpgradeSubscriptionComponent,
|
|
3714
3823
|
UserSubscriptionDetailsComponent,
|
|
@@ -3734,6 +3843,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
|
|
|
3734
3843
|
],
|
|
3735
3844
|
imports: [
|
|
3736
3845
|
InputTextModule,
|
|
3846
|
+
AppLoaderModule,
|
|
3737
3847
|
DirectivesModule,
|
|
3738
3848
|
CommonModule,
|
|
3739
3849
|
RouterModule,
|
|
@@ -3754,6 +3864,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
|
|
|
3754
3864
|
AddSubscriptionComponent,
|
|
3755
3865
|
SavedCardDetailsComponent,
|
|
3756
3866
|
SubscriptionCredentialComponent,
|
|
3867
|
+
HumanizeCredentialNamePipe,
|
|
3868
|
+
CredentialAvatarHuePipe,
|
|
3869
|
+
SubscriptionNameByIdPipe,
|
|
3870
|
+
ClearMaskedOnFocusDirective,
|
|
3757
3871
|
UpdatePaymentDetailsComponent,
|
|
3758
3872
|
UpgradeSubscriptionComponent,
|
|
3759
3873
|
UserSubscriptionDetailsComponent,
|
|
@@ -3796,5 +3910,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.6", ngImpor
|
|
|
3796
3910
|
* Generated bundle index. Do not edit.
|
|
3797
3911
|
*/
|
|
3798
3912
|
|
|
3799
|
-
export { AccountComponent, AccountDetailsComponent, AddSubscriptionComponent, CommunicationTabComponent, EditPortfoliosComponent, EditProjectModalComponent, EditQualificationsModalComponent, EditRecommendationModalComponent, EditSkillsModalComponent, EditSocialLinksComponent, EditUserProfileModalComponent, OthersTabComponent, PortfoliosComponent, SavedCardDetailsComponent, SecurityTabComponent, SettingsComponent, SubscriptionCredentialComponent, SupportComponent, SupportDetailsComponent, UpdatePaymentDetailsComponent, UpgradeSubscriptionComponent, UserAboutComponent, UserInvoiceComponent, UserModuleModule, UserProfilePageComponent, UserProjectsComponent, UserSubscriptionDetailsComponent, UserSubscriptionListComponent };
|
|
3913
|
+
export { AccountComponent, AccountDetailsComponent, AddSubscriptionComponent, ClearMaskedOnFocusDirective, CommunicationTabComponent, CredentialAvatarHuePipe, EditPortfoliosComponent, EditProjectModalComponent, EditQualificationsModalComponent, EditRecommendationModalComponent, EditSkillsModalComponent, EditSocialLinksComponent, EditUserProfileModalComponent, HumanizeCredentialNamePipe, OthersTabComponent, PortfoliosComponent, SavedCardDetailsComponent, SecurityTabComponent, SettingsComponent, SubscriptionCredentialComponent, SubscriptionNameByIdPipe, SupportComponent, SupportDetailsComponent, UpdatePaymentDetailsComponent, UpgradeSubscriptionComponent, UserAboutComponent, UserInvoiceComponent, UserModuleModule, UserProfilePageComponent, UserProjectsComponent, UserSubscriptionDetailsComponent, UserSubscriptionListComponent };
|
|
3800
3914
|
//# sourceMappingURL=posiwise-user-module.mjs.map
|