Browse Source

feat(admin-ui): Add profile page to edit current admin details

Michael Bromley 5 years ago
parent
commit
e18304135d

+ 14 - 14
packages/admin-ui/i18n-coverage.json

@@ -1,44 +1,44 @@
 {
-  "generatedOn": "2020-11-19T13:33:04.322Z",
-  "lastCommit": "7a9ba233b74b9eaae0f100a19f7e84e2b7c35a0f",
+  "generatedOn": "2020-11-20T08:36:18.659Z",
+  "lastCommit": "73ab736f93c07f8e4580587ddc7aacd97a5769b2",
   "translationStatus": {
     "cs": {
-      "tokenCount": 693,
+      "tokenCount": 695,
       "translatedCount": 688,
       "percentage": 99
     },
     "de": {
-      "tokenCount": 693,
+      "tokenCount": 695,
       "translatedCount": 597,
       "percentage": 86
     },
     "en": {
-      "tokenCount": 693,
-      "translatedCount": 688,
-      "percentage": 99
+      "tokenCount": 695,
+      "translatedCount": 693,
+      "percentage": 100
     },
     "es": {
-      "tokenCount": 693,
+      "tokenCount": 695,
       "translatedCount": 455,
-      "percentage": 66
+      "percentage": 65
     },
     "pl": {
-      "tokenCount": 693,
+      "tokenCount": 695,
       "translatedCount": 552,
-      "percentage": 80
+      "percentage": 79
     },
     "pt_BR": {
-      "tokenCount": 693,
+      "tokenCount": 695,
       "translatedCount": 643,
       "percentage": 93
     },
     "zh_Hans": {
-      "tokenCount": 693,
+      "tokenCount": 695,
       "translatedCount": 536,
       "percentage": 77
     },
     "zh_Hant": {
-      "tokenCount": 693,
+      "tokenCount": 695,
       "translatedCount": 536,
       "percentage": 77
     }

+ 30 - 0
packages/admin-ui/src/lib/core/src/common/generated-types.ts

@@ -4342,6 +4342,14 @@ export type GetAdministratorsQuery = { administrators: (
     )> }
   ) };
 
+export type GetActiveAdministratorQueryVariables = Exact<{ [key: string]: never; }>;
+
+
+export type GetActiveAdministratorQuery = { activeAdministrator?: Maybe<(
+    { __typename?: 'Administrator' }
+    & AdministratorFragment
+  )> };
+
 export type GetAdministratorQueryVariables = Exact<{
   id: Scalars['ID'];
 }>;
@@ -4372,6 +4380,16 @@ export type UpdateAdministratorMutation = { updateAdministrator: (
     & AdministratorFragment
   ) };
 
+export type UpdateActiveAdministratorMutationVariables = Exact<{
+  input: UpdateActiveAdministratorInput;
+}>;
+
+
+export type UpdateActiveAdministratorMutation = { updateActiveAdministrator: (
+    { __typename?: 'Administrator' }
+    & AdministratorFragment
+  ) };
+
 export type DeleteAdministratorMutationVariables = Exact<{
   id: Scalars['ID'];
 }>;
@@ -7162,6 +7180,12 @@ export namespace GetAdministrators {
   export type Items = NonNullable<(NonNullable<(NonNullable<GetAdministratorsQuery['administrators']>)['items']>)[number]>;
 }
 
+export namespace GetActiveAdministrator {
+  export type Variables = GetActiveAdministratorQueryVariables;
+  export type Query = GetActiveAdministratorQuery;
+  export type ActiveAdministrator = (NonNullable<GetActiveAdministratorQuery['activeAdministrator']>);
+}
+
 export namespace GetAdministrator {
   export type Variables = GetAdministratorQueryVariables;
   export type Query = GetAdministratorQuery;
@@ -7180,6 +7204,12 @@ export namespace UpdateAdministrator {
   export type UpdateAdministrator = (NonNullable<UpdateAdministratorMutation['updateAdministrator']>);
 }
 
+export namespace UpdateActiveAdministrator {
+  export type Variables = UpdateActiveAdministratorMutationVariables;
+  export type Mutation = UpdateActiveAdministratorMutation;
+  export type UpdateActiveAdministrator = (NonNullable<UpdateActiveAdministratorMutation['updateActiveAdministrator']>);
+}
+
 export namespace DeleteAdministrator {
   export type Variables = DeleteAdministratorMutationVariables;
   export type Mutation = DeleteAdministratorMutation;

+ 3 - 0
packages/admin-ui/src/lib/core/src/components/user-menu/user-menu.component.html

@@ -5,6 +5,9 @@
         <clr-icon shape="caret down"></clr-icon>
     </button>
     <vdr-dropdown-menu vdrPosition="bottom-right">
+        <a [routerLink]="['/settings', 'profile']" vdrDropdownItem>
+            <clr-icon shape="user" class="is-solid"></clr-icon> {{ 'settings.profile' | translate }}
+        </a>
         <ng-container *ngIf="1 < availableLanguages.length">
             <button
                 type="button"

+ 18 - 0
packages/admin-ui/src/lib/core/src/data/definitions/administrator-definitions.ts

@@ -48,6 +48,15 @@ export const GET_ADMINISTRATORS = gql`
     ${ADMINISTRATOR_FRAGMENT}
 `;
 
+export const GET_ACTIVE_ADMINISTRATOR = gql`
+    query GetActiveAdministrator {
+        activeAdministrator {
+            ...Administrator
+        }
+    }
+    ${ADMINISTRATOR_FRAGMENT}
+`;
+
 export const GET_ADMINISTRATOR = gql`
     query GetAdministrator($id: ID!) {
         administrator(id: $id) {
@@ -75,6 +84,15 @@ export const UPDATE_ADMINISTRATOR = gql`
     ${ADMINISTRATOR_FRAGMENT}
 `;
 
+export const UPDATE_ACTIVE_ADMINISTRATOR = gql`
+    mutation UpdateActiveAdministrator($input: UpdateActiveAdministratorInput!) {
+        updateActiveAdministrator(input: $input) {
+            ...Administrator
+        }
+    }
+    ${ADMINISTRATOR_FRAGMENT}
+`;
+
 export const DELETE_ADMINISTRATOR = gql`
     mutation DeleteAdministrator($id: ID!) {
         deleteAdministrator(id: $id) {

+ 16 - 0
packages/admin-ui/src/lib/core/src/data/providers/administrator-data.service.ts

@@ -5,10 +5,13 @@ import {
     CreateRoleInput,
     DeleteAdministrator,
     DeleteRole,
+    GetActiveAdministrator,
     GetAdministrator,
     GetAdministrators,
     GetRole,
     GetRoles,
+    UpdateActiveAdministrator,
+    UpdateActiveAdministratorInput,
     UpdateAdministrator,
     UpdateAdministratorInput,
     UpdateRole,
@@ -19,10 +22,12 @@ import {
     CREATE_ROLE,
     DELETE_ADMINISTRATOR,
     DELETE_ROLE,
+    GET_ACTIVE_ADMINISTRATOR,
     GET_ADMINISTRATOR,
     GET_ADMINISTRATORS,
     GET_ROLE,
     GET_ROLES,
+    UPDATE_ACTIVE_ADMINISTRATOR,
     UPDATE_ADMINISTRATOR,
     UPDATE_ROLE,
 } from '../definitions/administrator-definitions';
@@ -44,6 +49,10 @@ export class AdministratorDataService {
         );
     }
 
+    getActiveAdministrator() {
+        return this.baseDataService.query<GetActiveAdministrator.Query>(GET_ACTIVE_ADMINISTRATOR);
+    }
+
     getAdministrator(id: string) {
         return this.baseDataService.query<GetAdministrator.Query, GetAdministrator.Variables>(
             GET_ADMINISTRATOR,
@@ -67,6 +76,13 @@ export class AdministratorDataService {
         );
     }
 
+    updateActiveAdministrator(input: UpdateActiveAdministratorInput) {
+        return this.baseDataService.mutate<
+            UpdateActiveAdministrator.Mutation,
+            UpdateActiveAdministrator.Variables
+        >(UPDATE_ACTIVE_ADMINISTRATOR, { input });
+    }
+
     deleteAdministrator(id: string) {
         return this.baseDataService.mutate<DeleteAdministrator.Mutation, DeleteAdministrator.Variables>(
             DELETE_ADMINISTRATOR,

+ 33 - 0
packages/admin-ui/src/lib/settings/src/components/profile/profile.component.html

@@ -0,0 +1,33 @@
+<vdr-action-bar>
+    <vdr-ab-left>
+        <vdr-entity-info [entity]="entity$ | async"></vdr-entity-info>
+    </vdr-ab-left>
+    <vdr-ab-right>
+        <vdr-action-bar-items locationId="administrator-detail"></vdr-action-bar-items>
+        <button
+            class="btn btn-primary"
+            (click)="save()"
+            [disabled]="detailForm.invalid || detailForm.pristine"
+        >
+            {{ 'common.update' | translate }}
+        </button>
+    </vdr-ab-right>
+</vdr-action-bar>
+
+<form class="form" [formGroup]="detailForm">
+    <vdr-form-field [label]="'settings.email-address' | translate" for="emailAddress">
+        <input id="emailAddress" type="text" formControlName="emailAddress" />
+    </vdr-form-field>
+    <vdr-form-field [label]="'settings.first-name' | translate" for="firstName">
+        <input id="firstName" type="text" formControlName="firstName" />
+    </vdr-form-field>
+    <vdr-form-field [label]="'settings.last-name' | translate" for="lastName">
+        <input id="lastName" type="text" formControlName="lastName" />
+    </vdr-form-field>
+    <vdr-form-field *ngIf="isNew$ | async" [label]="'settings.password' | translate" for="password">
+        <input id="password" type="password" formControlName="password" />
+    </vdr-form-field>
+    <vdr-form-field [label]="'settings.password' | translate" for="password" [readOnlyToggle]="true">
+        <input id="password" type="password" formControlName="password" />
+    </vdr-form-field>
+</form>

+ 0 - 0
packages/admin-ui/src/lib/settings/src/components/profile/profile.component.scss


+ 92 - 0
packages/admin-ui/src/lib/settings/src/components/profile/profile.component.ts

@@ -0,0 +1,92 @@
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { ActivatedRoute, Router } from '@angular/router';
+import { marker as _ } from '@biesbjerg/ngx-translate-extract-marker';
+import {
+    Administrator,
+    BaseDetailComponent,
+    DataService,
+    GetActiveAdministrator,
+    LanguageCode,
+    NotificationService,
+    ServerConfigService,
+    UpdateActiveAdministratorInput,
+} from '@vendure/admin-ui/core';
+import { mergeMap, take } from 'rxjs/operators';
+
+@Component({
+    selector: 'vdr-profile',
+    templateUrl: './profile.component.html',
+    styleUrls: ['./profile.component.scss'],
+    changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class ProfileComponent
+    extends BaseDetailComponent<GetActiveAdministrator.ActiveAdministrator>
+    implements OnInit, OnDestroy {
+    detailForm: FormGroup;
+
+    constructor(
+        router: Router,
+        route: ActivatedRoute,
+        serverConfigService: ServerConfigService,
+        private changeDetector: ChangeDetectorRef,
+        protected dataService: DataService,
+        private formBuilder: FormBuilder,
+        private notificationService: NotificationService,
+    ) {
+        super(route, router, serverConfigService, dataService);
+        this.detailForm = this.formBuilder.group({
+            emailAddress: ['', Validators.required],
+            firstName: ['', Validators.required],
+            lastName: ['', Validators.required],
+            password: [''],
+        });
+    }
+
+    ngOnInit() {
+        this.init();
+    }
+
+    ngOnDestroy(): void {
+        this.destroy();
+    }
+
+    save() {
+        this.entity$
+            .pipe(
+                take(1),
+                mergeMap(({ id }) => {
+                    const formValue = this.detailForm.value;
+                    const administrator: UpdateActiveAdministratorInput = {
+                        emailAddress: formValue.emailAddress,
+                        firstName: formValue.firstName,
+                        lastName: formValue.lastName,
+                        password: formValue.password,
+                    };
+                    return this.dataService.administrator.updateActiveAdministrator(administrator);
+                }),
+            )
+            .subscribe(
+                data => {
+                    this.notificationService.success(_('common.notify-update-success'), {
+                        entity: 'Administrator',
+                    });
+                    this.detailForm.markAsPristine();
+                    this.changeDetector.markForCheck();
+                },
+                err => {
+                    this.notificationService.error(_('common.notify-update-error'), {
+                        entity: 'Administrator',
+                    });
+                },
+            );
+    }
+
+    protected setFormValues(administrator: Administrator, languageCode: LanguageCode): void {
+        this.detailForm.patchValue({
+            emailAddress: administrator.emailAddress,
+            firstName: administrator.firstName,
+            lastName: administrator.lastName,
+        });
+    }
+}

+ 30 - 0
packages/admin-ui/src/lib/settings/src/providers/routing/profile-resolver.ts

@@ -0,0 +1,30 @@
+import { Injectable } from '@angular/core';
+import { Router } from '@angular/router';
+import { BaseEntityResolver } from '@vendure/admin-ui/core';
+import { Administrator, Role } from '@vendure/admin-ui/core';
+import { DataService } from '@vendure/admin-ui/core';
+
+@Injectable({
+    providedIn: 'root',
+})
+export class ProfileResolver extends BaseEntityResolver<Administrator.Fragment> {
+    constructor(router: Router, dataService: DataService) {
+        super(
+            router,
+            {
+                __typename: 'Administrator' as 'Administrator',
+                id: '',
+                createdAt: '',
+                updatedAt: '',
+                emailAddress: '',
+                firstName: '',
+                lastName: '',
+                user: { roles: [] } as any,
+            },
+            id =>
+                dataService.administrator
+                    .getActiveAdministrator()
+                    .mapStream(data => data.activeAdministrator),
+        );
+    }
+}

+ 2 - 0
packages/admin-ui/src/lib/settings/src/settings.module.ts

@@ -13,6 +13,7 @@ import { GlobalSettingsComponent } from './components/global-settings/global-set
 import { PaymentMethodDetailComponent } from './components/payment-method-detail/payment-method-detail.component';
 import { PaymentMethodListComponent } from './components/payment-method-list/payment-method-list.component';
 import { PermissionGridComponent } from './components/permission-grid/permission-grid.component';
+import { ProfileComponent } from './components/profile/profile.component';
 import { RoleDetailComponent } from './components/role-detail/role-detail.component';
 import { RoleListComponent } from './components/role-list/role-list.component';
 import { ShippingEligibilityTestResultComponent } from './components/shipping-eligibility-test-result/shipping-eligibility-test-result.component';
@@ -63,6 +64,7 @@ import { settingsRoutes } from './settings.routes';
         ZoneMemberListHeaderDirective,
         ZoneMemberControlsDirective,
         ZoneDetailDialogComponent,
+        ProfileComponent,
     ],
 })
 export class SettingsModule {}

+ 11 - 0
packages/admin-ui/src/lib/settings/src/settings.routes.ts

@@ -22,6 +22,7 @@ import { CountryListComponent } from './components/country-list/country-list.com
 import { GlobalSettingsComponent } from './components/global-settings/global-settings.component';
 import { PaymentMethodDetailComponent } from './components/payment-method-detail/payment-method-detail.component';
 import { PaymentMethodListComponent } from './components/payment-method-list/payment-method-list.component';
+import { ProfileComponent } from './components/profile/profile.component';
 import { RoleDetailComponent } from './components/role-detail/role-detail.component';
 import { RoleListComponent } from './components/role-list/role-list.component';
 import { ShippingMethodDetailComponent } from './components/shipping-method-detail/shipping-method-detail.component';
@@ -36,12 +37,22 @@ import { ChannelResolver } from './providers/routing/channel-resolver';
 import { CountryResolver } from './providers/routing/country-resolver';
 import { GlobalSettingsResolver } from './providers/routing/global-settings-resolver';
 import { PaymentMethodResolver } from './providers/routing/payment-method-resolver';
+import { ProfileResolver } from './providers/routing/profile-resolver';
 import { RoleResolver } from './providers/routing/role-resolver';
 import { ShippingMethodResolver } from './providers/routing/shipping-method-resolver';
 import { TaxCategoryResolver } from './providers/routing/tax-category-resolver';
 import { TaxRateResolver } from './providers/routing/tax-rate-resolver';
 
 export const settingsRoutes: Route[] = [
+    {
+        path: 'profile',
+        component: ProfileComponent,
+        resolve: createResolveData(ProfileResolver),
+        canDeactivate: [CanDeactivateDetailGuard],
+        data: {
+            breadcrumb: _('breadcrumb.profile'),
+        },
+    },
     {
         path: 'administrators',
         component: AdministratorListComponent,

+ 2 - 0
packages/admin-ui/src/lib/static/i18n-messages/cs.json

@@ -40,6 +40,7 @@
     "orders": "Objednávky",
     "payment-methods": "Platební metody",
     "products": "Produkty",
+    "profile": "",
     "promotions": "Propagace",
     "roles": "Role",
     "shipping-methods": "Dopravní metody",
@@ -666,6 +667,7 @@
     "payment-method-config-options": "Konfigurace platební metody",
     "permissions": "Oprávnění",
     "prices-include-tax": "Zadávané ceny jsou včetně daně pro výchozí zónu",
+    "profile": "",
     "rate": "Sazba",
     "remove-countries-from-zone-success": "Odebráno: { countryCount } {countryCount, plural, one {země} other {země}} ze zóny \"{ zoneName }\"",
     "remove-from-zone": "Odebrat ze zóny",

+ 2 - 0
packages/admin-ui/src/lib/static/i18n-messages/de.json

@@ -40,6 +40,7 @@
     "orders": "Bestellungen",
     "payment-methods": "Zahlungsarten",
     "products": "Produkte",
+    "profile": "",
     "promotions": "Promotionen",
     "roles": "Rollen",
     "shipping-methods": "Versandarten",
@@ -666,6 +667,7 @@
     "payment-method-config-options": "Konfiguration der Zahlungsart",
     "permissions": "Berechtigungen",
     "prices-include-tax": "Preise enthalten die Steuer für die Standardzone",
+    "profile": "",
     "rate": "Steuersatz",
     "remove-countries-from-zone-success": "{ countryCount } {countryCount, plural, one {Land} other {Länder}} entfernt aus \"{ zoneName }\"",
     "remove-from-zone": "Aus Zone entfernen",

+ 2 - 0
packages/admin-ui/src/lib/static/i18n-messages/en.json

@@ -40,6 +40,7 @@
     "orders": "Orders",
     "payment-methods": "Payment methods",
     "products": "Products",
+    "profile": "Profile",
     "promotions": "Promotions",
     "roles": "Roles",
     "shipping-methods": "Shipping methods",
@@ -666,6 +667,7 @@
     "payment-method-config-options": "Payment method configuration",
     "permissions": "Permissions",
     "prices-include-tax": "Prices include tax for the default Zone",
+    "profile": "Profile",
     "rate": "Rate",
     "remove-countries-from-zone-success": "Removed { countryCount } {countryCount, plural, one {country} other {countries}} from zone \"{ zoneName }\"",
     "remove-from-zone": "Remove from zone",

+ 2 - 0
packages/admin-ui/src/lib/static/i18n-messages/es.json

@@ -40,6 +40,7 @@
     "orders": "Pedidos",
     "payment-methods": "Métodos de pago",
     "products": "Productos",
+    "profile": "",
     "promotions": "Promociones",
     "roles": "Roles",
     "shipping-methods": "Métodos de envío",
@@ -666,6 +667,7 @@
     "payment-method-config-options": "Configuración método de pago",
     "permissions": "Permisos",
     "prices-include-tax": "Los precios incluyen impuestos para la zona por defecto.",
+    "profile": "",
     "rate": "Tasa",
     "remove-countries-from-zone-success": "Eliminados { countryCount } {countryCount, plural, one {país} other {países}} de la zona \"{ zoneName }\"",
     "remove-from-zone": "Eliminar de la zona",

+ 2 - 0
packages/admin-ui/src/lib/static/i18n-messages/pl.json

@@ -40,6 +40,7 @@
     "orders": "Zamówienia",
     "payment-methods": "Metody płatności",
     "products": "Produkty",
+    "profile": "",
     "promotions": "Promocje",
     "roles": "Role",
     "shipping-methods": "Metody wysyłki",
@@ -666,6 +667,7 @@
     "payment-method-config-options": "Konfiguracja metody płatności",
     "permissions": "Uprawnienia",
     "prices-include-tax": "Ceny zawierają podatek dla domyślnej strefy",
+    "profile": "",
     "rate": "Stawka",
     "remove-countries-from-zone-success": "Usunięto { countryCount } {countryCount, plural, one {kraj} other {kraje}} ze strefy \"{ zoneName }\"",
     "remove-from-zone": "",

+ 2 - 0
packages/admin-ui/src/lib/static/i18n-messages/pt_BR.json

@@ -40,6 +40,7 @@
     "orders": "Pedidos",
     "payment-methods": "Métodos de pagamentos",
     "products": "Produtos",
+    "profile": "",
     "promotions": "Promoções",
     "roles": "Regras",
     "shipping-methods": "Métodos de envio",
@@ -666,6 +667,7 @@
     "payment-method-config-options": "Configuração do método de pagamento",
     "permissions": "Permissões",
     "prices-include-tax": "Os preços incluem impostos para a Zona padrão",
+    "profile": "",
     "rate": "Taxa",
     "remove-countries-from-zone-success": "Excluído { countryCount } {countryCount, plural, one {country} other {countries}} da zona \"{ zoneName }\"",
     "remove-from-zone": "Excluir da zona",

+ 2 - 0
packages/admin-ui/src/lib/static/i18n-messages/zh_Hans.json

@@ -40,6 +40,7 @@
     "orders": "订单管理",
     "payment-methods": "支付管理",
     "products": "商品列表",
+    "profile": "",
     "promotions": "优惠券管理",
     "roles": "角色管理",
     "shipping-methods": "配送方式管理",
@@ -666,6 +667,7 @@
     "payment-method-config-options": "支付方式选项配置",
     "permissions": "权限",
     "prices-include-tax": "设置默认销售区域价格含税",
+    "profile": "",
     "rate": "税率",
     "remove-countries-from-zone-success": "{ countryCount }个国际已从\"{ zoneName }\"中移除",
     "remove-from-zone": "",

+ 2 - 0
packages/admin-ui/src/lib/static/i18n-messages/zh_Hant.json

@@ -40,6 +40,7 @@
     "orders": "訂單管理",
     "payment-methods": "支付方式",
     "products": "商品",
+    "profile": "",
     "promotions": "優惠",
     "roles": "角色管理",
     "shipping-methods": "配送方式管理",
@@ -666,6 +667,7 @@
     "payment-method-config-options": "支付方式選項配置",
     "permissions": "權限",
     "prices-include-tax": "設定默認銷售區域價格連税",
+    "profile": "",
     "rate": "税率",
     "remove-countries-from-zone-success": "{ countryCount }個國際已從\"{ zoneName }\"中移除",
     "remove-from-zone": "",