1
0
Эх сурвалжийг харах

feat(admin-ui): Implement basic ShippingMethod list/detail components

Relates to #35
Michael Bromley 7 жил өмнө
parent
commit
1d2f3d8139
23 өөрчлөгдсөн 649 нэмэгдсэн , 11 устгасан
  1. 7 1
      admin-ui/angular.json
  2. 7 0
      admin-ui/src/app/core/components/main-nav/main-nav.component.html
  3. 71 0
      admin-ui/src/app/data/definitions/shipping-definitions.ts
  4. 1 1
      admin-ui/src/app/data/providers/data.service.mock.ts
  5. 3 0
      admin-ui/src/app/data/providers/data.service.ts
  6. 66 0
      admin-ui/src/app/data/providers/shipping-method-data.service.ts
  7. 1 1
      admin-ui/src/app/settings/components/role-detail/role-detail.component.html
  8. 1 1
      admin-ui/src/app/settings/components/role-list/role-list.component.html
  9. 78 0
      admin-ui/src/app/settings/components/shipping-method-detail/shipping-method-detail.component.html
  10. 0 0
      admin-ui/src/app/settings/components/shipping-method-detail/shipping-method-detail.component.scss
  11. 164 0
      admin-ui/src/app/settings/components/shipping-method-detail/shipping-method-detail.component.ts
  12. 29 0
      admin-ui/src/app/settings/components/shipping-method-list/shipping-method-list.component.html
  13. 0 0
      admin-ui/src/app/settings/components/shipping-method-list/shipping-method-list.component.scss
  14. 25 0
      admin-ui/src/app/settings/components/shipping-method-list/shipping-method-list.component.ts
  15. 28 0
      admin-ui/src/app/settings/providers/routing/shipping-method-resolver.ts
  16. 6 0
      admin-ui/src/app/settings/settings.module.ts
  17. 37 1
      admin-ui/src/app/settings/settings.routes.ts
  18. 2 2
      admin-ui/src/app/shared/components/adjustment-operation-input/adjustment-operation-input.component.html
  19. 8 3
      admin-ui/src/app/shared/components/adjustment-operation-input/adjustment-operation-input.component.ts
  20. 7 1
      admin-ui/src/i18n-messages/en.json
  21. 1 0
      admin-ui/src/polyfills.ts
  22. 0 0
      schema.json
  23. 107 0
      shared/generated-types.ts

+ 7 - 1
admin-ui/angular.json

@@ -137,5 +137,11 @@
       }
     }
   },
-  "defaultProject": "vendure-admin"
+  "defaultProject": "vendure-admin",
+  "schematics": {
+    "@schematics/angular:component": {
+      "spec": false,
+      "changeDetection": "OnPush"
+    }
+  }
 }

+ 7 - 0
admin-ui/src/app/core/components/main-nav/main-nav.component.html

@@ -95,6 +95,13 @@
                         <clr-icon shape="users" size="20"></clr-icon>{{ 'nav.roles' | translate }}
                     </a>
                 </li>
+                <li>
+                    <a class="nav-link"
+                       [routerLink]="['/settings', 'shipping-methods']"
+                       routerLinkActive="active">
+                        <clr-icon shape="truck" size="20"></clr-icon>{{ 'nav.shipping-methods' | translate }}
+                    </a>
+                </li>
                 <li>
                     <a class="nav-link"
                        [routerLink]="['/settings', 'tax-categories']"

+ 71 - 0
admin-ui/src/app/data/definitions/shipping-definitions.ts

@@ -0,0 +1,71 @@
+import gql from 'graphql-tag';
+
+import { ADJUSTMENT_OPERATION_FRAGMENT } from './promotion-definitions';
+
+export const SHIPPING_METHOD_FRAGMENT = gql`
+    fragment ShippingMethod on ShippingMethod {
+        id
+        createdAt
+        updatedAt
+        code
+        description
+        checker {
+            ...AdjustmentOperation
+        }
+        calculator {
+            ...AdjustmentOperation
+        }
+    }
+    ${ADJUSTMENT_OPERATION_FRAGMENT}
+`;
+
+export const GET_SHIPPING_METHOD_LIST = gql`
+    query GetShippingMethodList($options: ShippingMethodListOptions) {
+        shippingMethods(options: $options) {
+            items {
+                ...ShippingMethod
+            }
+            totalItems
+        }
+    }
+    ${SHIPPING_METHOD_FRAGMENT}
+`;
+
+export const GET_SHIPPING_METHOD = gql`
+    query GetShippingMethod($id: ID!) {
+        shippingMethod(id: $id) {
+            ...ShippingMethod
+        }
+    }
+    ${SHIPPING_METHOD_FRAGMENT}
+`;
+
+export const GET_SHIPPING_METHOD_OPERATIONS = gql`
+    query GetShippingMethodOperations {
+        shippingEligibilityCheckers {
+            ...AdjustmentOperation
+        }
+        shippingCalculators {
+            ...AdjustmentOperation
+        }
+    }
+    ${ADJUSTMENT_OPERATION_FRAGMENT}
+`;
+
+export const CREATE_SHIPPING_METHOD = gql`
+    mutation CreateShippingMethod($input: CreateShippingMethodInput!) {
+        createShippingMethod(input: $input) {
+            ...ShippingMethod
+        }
+    }
+    ${SHIPPING_METHOD_FRAGMENT}
+`;
+
+export const UPDATE_SHIPPING_METHOD = gql`
+    mutation UpdateShippingMethod($input: UpdateShippingMethodInput!) {
+        updateShippingMethod(input: $input) {
+            ...ShippingMethod
+        }
+    }
+    ${SHIPPING_METHOD_FRAGMENT}
+`;

+ 1 - 1
admin-ui/src/app/data/providers/data.service.mock.ts

@@ -6,7 +6,7 @@ import { DataService } from './data.service';
 
 export type DataServiceSectionMock<T> = { [K in keyof T]: jasmine.Spy };
 
-export type DataServiceMock = { [K in keyof DataService]: DataServiceSectionMock<DataService[K]> };
+export type DataServiceMock = { [K in keyof DataService]?: DataServiceSectionMock<DataService[K]> };
 
 export type MockQueryResult = { [K in keyof QueryResult<any>]: any };
 

+ 3 - 0
admin-ui/src/app/data/providers/data.service.ts

@@ -10,6 +10,7 @@ import { OrderDataService } from './order-data.service';
 import { ProductDataService } from './product-data.service';
 import { PromotionDataService } from './promotion-data.service';
 import { SettingsDataService } from './settings-data.service';
+import { ShippingMethodDataService } from './shipping-method-data.service';
 
 @Injectable()
 export class DataService {
@@ -22,6 +23,7 @@ export class DataService {
     order: OrderDataService;
     settings: SettingsDataService;
     customer: CustomerDataService;
+    shippingMethod: ShippingMethodDataService;
 
     constructor(baseDataService: BaseDataService) {
         this.promotion = new PromotionDataService(baseDataService);
@@ -33,5 +35,6 @@ export class DataService {
         this.order = new OrderDataService(baseDataService);
         this.settings = new SettingsDataService(baseDataService);
         this.customer = new CustomerDataService(baseDataService);
+        this.shippingMethod = new ShippingMethodDataService(baseDataService);
     }
 }

+ 66 - 0
admin-ui/src/app/data/providers/shipping-method-data.service.ts

@@ -0,0 +1,66 @@
+import {
+    CreateShippingMethod,
+    CreateShippingMethodInput,
+    GetShippingMethod,
+    GetShippingMethodList,
+    GetShippingMethodOperations,
+    UpdateShippingMethod,
+    UpdateShippingMethodInput,
+} from 'shared/generated-types';
+
+import {
+    CREATE_SHIPPING_METHOD,
+    GET_SHIPPING_METHOD,
+    GET_SHIPPING_METHOD_LIST,
+    GET_SHIPPING_METHOD_OPERATIONS,
+    UPDATE_SHIPPING_METHOD,
+} from '../definitions/shipping-definitions';
+
+import { BaseDataService } from './base-data.service';
+
+export class ShippingMethodDataService {
+    constructor(private baseDataService: BaseDataService) {}
+
+    getShippingMethods(take: number = 10, skip: number = 0) {
+        return this.baseDataService.query<GetShippingMethodList.Query, GetShippingMethodList.Variables>(
+            GET_SHIPPING_METHOD_LIST,
+            {
+                options: {
+                    take,
+                    skip,
+                },
+            },
+        );
+    }
+
+    getShippingMethod(id: string) {
+        return this.baseDataService.query<GetShippingMethod.Query, GetShippingMethod.Variables>(
+            GET_SHIPPING_METHOD,
+            {
+                id,
+            },
+        );
+    }
+
+    getShippingMethodOperations() {
+        return this.baseDataService.query<GetShippingMethodOperations.Query>(GET_SHIPPING_METHOD_OPERATIONS);
+    }
+
+    createShippingMethod(input: CreateShippingMethodInput) {
+        return this.baseDataService.mutate<CreateShippingMethod.Mutation, CreateShippingMethod.Variables>(
+            CREATE_SHIPPING_METHOD,
+            {
+                input,
+            },
+        );
+    }
+
+    updateShippingMethod(input: UpdateShippingMethodInput) {
+        return this.baseDataService.mutate<UpdateShippingMethod.Mutation, UpdateShippingMethod.Variables>(
+            UPDATE_SHIPPING_METHOD,
+            {
+                input,
+            },
+        );
+    }
+}

+ 1 - 1
admin-ui/src/app/settings/components/role-detail/role-detail.component.html

@@ -16,7 +16,7 @@
 <form class="form" [formGroup]="roleForm" >
     <section class="form-block">
         <label>{{ 'settings.role' | translate }}</label>
-        <vdr-form-field [label]="'settings.description' | translate" for="description">
+        <vdr-form-field [label]="'common.description' | translate" for="description">
             <input id="description" type="text" formControlName="description" (input)="updateCode($event.target.value)">
         </vdr-form-field>
         <vdr-form-field [label]="'common.code' | translate" for="code" [readOnlyToggle]="true">

+ 1 - 1
admin-ui/src/app/settings/components/role-list/role-list.component.html

@@ -15,7 +15,7 @@
                 (itemsPerPageChange)="setItemsPerPage($event)">
     <vdr-dt-column>{{ 'common.ID' | translate }}</vdr-dt-column>
     <vdr-dt-column>{{ 'common.code' | translate }}</vdr-dt-column>
-    <vdr-dt-column>{{ 'settings.description' | translate }}</vdr-dt-column>
+    <vdr-dt-column>{{ 'common.description' | translate }}</vdr-dt-column>
     <vdr-dt-column>{{ 'settings.permissions' | translate }}</vdr-dt-column>
     <vdr-dt-column></vdr-dt-column>
     <ng-template let-role="item">

+ 78 - 0
admin-ui/src/app/settings/components/shipping-method-detail/shipping-method-detail.component.html

@@ -0,0 +1,78 @@
+<vdr-action-bar>
+    <vdr-ab-left>
+    </vdr-ab-left>
+
+    <vdr-ab-right>
+        <button class="btn btn-primary"
+                *ngIf="isNew$ | async; else updateButton"
+                (click)="create()"
+                [disabled]="shippingMethodForm.pristine || shippingMethodForm.invalid">{{ 'common.create' | translate }}</button>
+        <ng-template #updateButton>
+            <button class="btn btn-primary"
+                    (click)="save()"
+                    [disabled]="shippingMethodForm.pristine || shippingMethodForm.invalid">{{ 'common.update' | translate }}</button>
+        </ng-template>
+    </vdr-ab-right>
+</vdr-action-bar>
+
+<form class="form" [formGroup]="shippingMethodForm" >
+    <section class="form-block">
+        <vdr-form-field [label]="'common.code' | translate" for="code">
+            <input id="code" type="text" formControlName="code">
+        </vdr-form-field>
+    </section>
+    <section class="form-block">
+        <vdr-form-field [label]="'common.description' | translate" for="description">
+            <input id="description" type="text" formControlName="description">
+        </vdr-form-field>
+    </section>
+
+    <div class="clr-row">
+        <div class="clr-col">
+            <label>{{ 'settings.shipping-eligibility-checker' | translate }}</label>
+            <vdr-adjustment-operation-input *ngIf="selectedChecker"
+                                            [operation]="selectedChecker"
+                                            (remove)="selectedChecker = null"
+                                            formControlName="checker"></vdr-adjustment-operation-input>
+            <div *ngIf="!selectedChecker">
+                <clr-dropdown>
+                    <div clrDropdownTrigger>
+                        <button class="btn btn-outline">
+                            <clr-icon shape="plus"></clr-icon> {{ 'common.select' | translate }}
+                        </button>
+                    </div>
+                    <clr-dropdown-menu clrPosition="top-right" *clrIfOpen>
+                        <button *ngFor="let checker of checkers"
+                                type="button"
+                                clrDropdownItem (click)="selectedChecker = checker">
+                            {{ checker.description }}
+                        </button>
+                    </clr-dropdown-menu>
+                </clr-dropdown>
+            </div>
+        </div>
+        <div class="clr-col">
+            <label>{{ 'settings.shipping-calculator' | translate }}</label>
+            <vdr-adjustment-operation-input *ngIf="selectedCalculator"
+                                            [operation]="selectedCalculator"
+                                            (remove)="selectedCalculator = null"
+                                            formControlName="calculator"></vdr-adjustment-operation-input>
+            <div *ngIf="!selectedCalculator">
+                <clr-dropdown>
+                    <div clrDropdownTrigger>
+                        <button class="btn btn-outline">
+                            <clr-icon shape="plus"></clr-icon> {{ 'common.select' | translate }}
+                        </button>
+                    </div>
+                    <clr-dropdown-menu clrPosition="top-right" *clrIfOpen>
+                        <button *ngFor="let calculator of calculators"
+                                type="button"
+                                clrDropdownItem (click)="selectedCalculator = calculator">
+                            {{ calculator.description }}
+                        </button>
+                    </clr-dropdown-menu>
+                </clr-dropdown>
+            </div>
+        </div>
+    </div>
+</form>

+ 0 - 0
admin-ui/src/app/settings/components/shipping-method-detail/shipping-method-detail.component.scss


+ 164 - 0
admin-ui/src/app/settings/components/shipping-method-detail/shipping-method-detail.component.ts

@@ -0,0 +1,164 @@
+import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
+import { FormBuilder, FormGroup, Validators } from '@angular/forms';
+import { ActivatedRoute, Router } from '@angular/router';
+import { mergeMap, take } from 'rxjs/operators';
+import {
+    AdjustmentOperation,
+    AdjustmentOperationInput,
+    CreateShippingMethodInput,
+    ShippingMethod,
+    UpdateShippingMethodInput,
+} from 'shared/generated-types';
+import { normalizeString } from 'shared/normalize-string';
+
+import { BaseDetailComponent } from '../../../common/base-detail.component';
+import { _ } from '../../../core/providers/i18n/mark-for-extraction';
+import { NotificationService } from '../../../core/providers/notification/notification.service';
+import { DataService } from '../../../data/providers/data.service';
+import { ServerConfigService } from '../../../data/server-config';
+
+@Component({
+    selector: 'vdr-shipping-method-detail',
+    templateUrl: './shipping-method-detail.component.html',
+    styleUrls: ['./shipping-method-detail.component.scss'],
+    changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class ShippingMethodDetailComponent extends BaseDetailComponent<ShippingMethod.Fragment>
+    implements OnInit, OnDestroy {
+    shippingMethodForm: FormGroup;
+    checkers: AdjustmentOperation[] = [];
+    calculators: AdjustmentOperation[] = [];
+    selectedChecker?: AdjustmentOperation;
+    selectedCalculator?: AdjustmentOperation;
+
+    constructor(
+        router: Router,
+        route: ActivatedRoute,
+        serverConfigService: ServerConfigService,
+        private changeDetector: ChangeDetectorRef,
+        private dataService: DataService,
+        private formBuilder: FormBuilder,
+        private notificationService: NotificationService,
+    ) {
+        super(route, router, serverConfigService);
+        this.shippingMethodForm = this.formBuilder.group({
+            code: ['', Validators.required],
+            description: ['', Validators.required],
+            checker: {},
+            calculator: {},
+        });
+    }
+
+    ngOnInit() {
+        this.init();
+        this.dataService.shippingMethod.getShippingMethodOperations().single$.subscribe(data => {
+            this.checkers = data.shippingEligibilityCheckers;
+            this.calculators = data.shippingCalculators;
+            this.changeDetector.markForCheck();
+        });
+    }
+
+    ngOnDestroy(): void {
+        this.destroy();
+    }
+
+    selectChecker(checker: AdjustmentOperation) {
+        this.selectedChecker = checker;
+    }
+
+    selectCalculator(calculator: AdjustmentOperation) {
+        this.selectedCalculator = calculator;
+    }
+
+    create() {
+        if (!this.selectedChecker || !this.selectedCalculator) {
+            return;
+        }
+        const formValue = this.shippingMethodForm.value;
+        const input: CreateShippingMethodInput = {
+            code: formValue.code,
+            description: formValue.description,
+            checker: this.toAdjustmentOperationInput(this.selectedChecker, formValue.checker),
+            calculator: this.toAdjustmentOperationInput(this.selectedCalculator, formValue.calculator),
+        };
+        this.dataService.shippingMethod.createShippingMethod(input).subscribe(
+            data => {
+                this.notificationService.success(_('common.notify-create-success'), {
+                    entity: 'ShippingMethod',
+                });
+                this.shippingMethodForm.markAsPristine();
+                this.changeDetector.markForCheck();
+                this.router.navigate(['../', data.createShippingMethod.id], { relativeTo: this.route });
+            },
+            err => {
+                this.notificationService.error(_('common.notify-create-error'), {
+                    entity: 'ShippingMethod',
+                });
+            },
+        );
+    }
+
+    save() {
+        const selectedChecker = this.selectedChecker;
+        const selectedCalculator = this.selectedCalculator;
+        if (!selectedChecker || !selectedCalculator) {
+            return;
+        }
+        this.entity$
+            .pipe(
+                take(1),
+                mergeMap(({ id }) => {
+                    const formValue = this.shippingMethodForm.value;
+                    const input: UpdateShippingMethodInput = {
+                        id,
+                        code: formValue.code,
+                        description: formValue.description,
+                        checker: this.toAdjustmentOperationInput(selectedChecker, formValue.checker),
+                        calculator: this.toAdjustmentOperationInput(selectedCalculator, formValue.calculator),
+                    };
+                    return this.dataService.shippingMethod.updateShippingMethod(input);
+                }),
+            )
+            .subscribe(
+                data => {
+                    this.notificationService.success(_('common.notify-update-success'), {
+                        entity: 'ShippingMethod',
+                    });
+                    this.shippingMethodForm.markAsPristine();
+                    this.changeDetector.markForCheck();
+                },
+                err => {
+                    this.notificationService.error(_('common.notify-update-error'), {
+                        entity: 'ShippingMethod',
+                    });
+                },
+            );
+    }
+
+    /**
+     * Maps an array of conditions or actions to the input format expected by the GraphQL API.
+     */
+    private toAdjustmentOperationInput(
+        operation: AdjustmentOperation,
+        formValueOperations: any,
+    ): AdjustmentOperationInput {
+        return {
+            code: operation.code,
+            arguments: Object.values(formValueOperations.args).map((value, j) => ({
+                name: operation.args[j].name,
+                value: value.toString(),
+            })),
+        };
+    }
+
+    protected setFormValues(shippingMethod: ShippingMethod.Fragment): void {
+        this.shippingMethodForm.patchValue({
+            description: shippingMethod.description,
+            code: shippingMethod.code,
+            checker: shippingMethod.checker,
+            calculator: shippingMethod.calculator,
+        });
+        this.selectedChecker = shippingMethod.checker;
+        this.selectedCalculator = shippingMethod.calculator;
+    }
+}

+ 29 - 0
admin-ui/src/app/settings/components/shipping-method-list/shipping-method-list.component.html

@@ -0,0 +1,29 @@
+<vdr-action-bar>
+    <vdr-ab-right>
+        <a class="btn btn-primary" [routerLink]="['./create']">
+            <clr-icon shape="plus"></clr-icon>
+            {{ 'settings.create-new-shipping-method' | translate }}
+        </a>
+    </vdr-ab-right>
+</vdr-action-bar>
+
+<vdr-data-table [items]="items$ | async"
+                [itemsPerPage]="itemsPerPage$ | async"
+                [totalItems]="totalItems$ | async"
+                [currentPage]="currentPage$ | async"
+                (pageChange)="setPageNumber($event)"
+                (itemsPerPageChange)="setItemsPerPage($event)">
+    <vdr-dt-column>{{ 'common.code' | translate }}</vdr-dt-column>
+    <vdr-dt-column>{{ 'common.description' | translate }}</vdr-dt-column>
+    <vdr-dt-column></vdr-dt-column>
+    <ng-template let-shippingMethod="item">
+        <td class="left">{{ shippingMethod.code }}</td>
+        <td class="left">{{ shippingMethod.description }}</td>
+        <td class="right">
+            <vdr-table-row-action iconShape="edit"
+                                  [label]="'common.edit' | translate"
+                                  [linkTo]="['./', shippingMethod.id]">
+            </vdr-table-row-action>
+        </td>
+    </ng-template>
+</vdr-data-table>

+ 0 - 0
admin-ui/src/app/settings/components/shipping-method-list/shipping-method-list.component.scss


+ 25 - 0
admin-ui/src/app/settings/components/shipping-method-list/shipping-method-list.component.ts

@@ -0,0 +1,25 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { ActivatedRoute, Router } from '@angular/router';
+import { GetShippingMethodList } from 'shared/generated-types';
+
+import { BaseListComponent } from '../../../common/base-list.component';
+import { DataService } from '../../../data/providers/data.service';
+
+@Component({
+    selector: 'vdr-shipping-method-list',
+    templateUrl: './shipping-method-list.component.html',
+    styleUrls: ['./shipping-method-list.component.scss'],
+    changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class ShippingMethodListComponent extends BaseListComponent<
+    GetShippingMethodList.Query,
+    GetShippingMethodList.Items
+> {
+    constructor(private dataService: DataService, router: Router, route: ActivatedRoute) {
+        super(router, route);
+        super.setQueryFn(
+            (...args: any[]) => this.dataService.shippingMethod.getShippingMethods(...args),
+            data => data.shippingMethods,
+        );
+    }
+}

+ 28 - 0
admin-ui/src/app/settings/providers/routing/shipping-method-resolver.ts

@@ -0,0 +1,28 @@
+import { Injectable } from '@angular/core';
+import { ShippingMethod } from 'shared/generated-types';
+
+import { BaseEntityResolver } from '../../../common/base-entity-resolver';
+import { DataService } from '../../../data/providers/data.service';
+
+/**
+ * Resolves the id from the path into a Customer entity.
+ */
+@Injectable()
+export class ShippingMethodResolver extends BaseEntityResolver<ShippingMethod.Fragment> {
+    constructor(private dataService: DataService) {
+        super(
+            {
+                __typename: 'ShippingMethod',
+                createdAt: '',
+                updatedAt: '',
+                id: '',
+                code: '',
+                description: '',
+                checker: undefined as any,
+                calculator: undefined as any,
+            },
+            id =>
+                this.dataService.shippingMethod.getShippingMethod(id).mapStream(data => data.shippingMethod),
+        );
+    }
+}

+ 6 - 0
admin-ui/src/app/settings/settings.module.ts

@@ -12,6 +12,8 @@ import { CountryListComponent } from './components/country-list/country-list.com
 import { PermissionGridComponent } from './components/permission-grid/permission-grid.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';
+import { ShippingMethodListComponent } from './components/shipping-method-list/shipping-method-list.component';
 import { TaxCategoryDetailComponent } from './components/tax-category-detail/tax-category-detail.component';
 import { TaxCategoryListComponent } from './components/tax-category-list/tax-category-list.component';
 import { TaxRateDetailComponent } from './components/tax-rate-detail/tax-rate-detail.component';
@@ -21,6 +23,7 @@ import { AdministratorResolver } from './providers/routing/administrator-resolve
 import { ChannelResolver } from './providers/routing/channel-resolver';
 import { CountryResolver } from './providers/routing/country-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';
 import { settingsRoutes } from './settings.routes';
@@ -42,6 +45,8 @@ import { settingsRoutes } from './settings.routes';
         TaxRateDetailComponent,
         ChannelListComponent,
         ChannelDetailComponent,
+        ShippingMethodListComponent,
+        ShippingMethodDetailComponent,
     ],
     entryComponents: [ZoneSelectorDialogComponent],
     providers: [
@@ -51,6 +56,7 @@ import { settingsRoutes } from './settings.routes';
         CountryResolver,
         TaxRateResolver,
         ChannelResolver,
+        ShippingMethodResolver,
     ],
 })
 export class SettingsModule {}

+ 37 - 1
admin-ui/src/app/settings/settings.routes.ts

@@ -1,5 +1,13 @@
 import { Route } from '@angular/router';
-import { Administrator, Channel, Country, Role, TaxCategory, TaxRate } from 'shared/generated-types';
+import {
+    Administrator,
+    Channel,
+    Country,
+    Role,
+    ShippingMethod,
+    TaxCategory,
+    TaxRate,
+} from 'shared/generated-types';
 
 import { createResolveData } from '../common/base-entity-resolver';
 import { detailBreadcrumb } from '../common/detail-breadcrumb';
@@ -13,6 +21,8 @@ import { CountryDetailComponent } from './components/country-detail/country-deta
 import { CountryListComponent } from './components/country-list/country-list.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';
+import { ShippingMethodListComponent } from './components/shipping-method-list/shipping-method-list.component';
 import { TaxCategoryDetailComponent } from './components/tax-category-detail/tax-category-detail.component';
 import { TaxCategoryListComponent } from './components/tax-category-list/tax-category-list.component';
 import { TaxRateDetailComponent } from './components/tax-rate-detail/tax-rate-detail.component';
@@ -21,6 +31,7 @@ import { AdministratorResolver } from './providers/routing/administrator-resolve
 import { ChannelResolver } from './providers/routing/channel-resolver';
 import { CountryResolver } from './providers/routing/country-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';
 
@@ -109,6 +120,21 @@ export const settingsRoutes: Route[] = [
             breadcrumb: countryBreadcrumb,
         },
     },
+    {
+        path: 'shipping-methods',
+        component: ShippingMethodListComponent,
+        data: {
+            breadcrumb: _('breadcrumb.shipping-methods'),
+        },
+    },
+    {
+        path: 'shipping-methods/:id',
+        component: ShippingMethodDetailComponent,
+        resolve: createResolveData(ShippingMethodResolver),
+        data: {
+            breadcrumb: shippingMethodBreadcrumb,
+        },
+    },
 ];
 
 export function administratorBreadcrumb(data: any, params: any) {
@@ -170,3 +196,13 @@ export function countryBreadcrumb(data: any, params: any) {
         route: 'countries',
     });
 }
+
+export function shippingMethodBreadcrumb(data: any, params: any) {
+    return detailBreadcrumb<ShippingMethod.Fragment>({
+        entity: data.entity,
+        id: params.id,
+        breadcrumbKey: 'breadcrumb.shipping-methods',
+        getName: method => method.description,
+        route: 'shipping-methods',
+    });
+}

+ 2 - 2
admin-ui/src/app/shared/components/adjustment-operation-input/adjustment-operation-input.component.html

@@ -1,8 +1,8 @@
-<div class="card">
+<div class="card" *ngIf="operation">
     <div class="card-block">
         {{ interpolateDescription() }}
     </div>
-    <div class="card-block">
+    <div class="card-block" *ngIf="operation.args?.length">
         <form clrForm
               [formGroup]="form"
               *ngIf="operation"

+ 8 - 3
admin-ui/src/app/shared/components/adjustment-operation-input/adjustment-operation-input.component.ts

@@ -89,7 +89,9 @@ export class AdjustmentOperationInputComponent
     }
 
     writeValue(value: any): void {
-        this.form.patchValue(value);
+        if (value) {
+            this.form.patchValue(value);
+        }
     }
 
     private createForm() {
@@ -97,9 +99,12 @@ export class AdjustmentOperationInputComponent
             this.subscription.unsubscribe();
         }
         this.form = new FormGroup({});
-        for (const arg of this.operation.args) {
-            this.form.addControl(arg.name, new FormControl(arg.value, Validators.required));
+        if (this.operation.args) {
+            for (const arg of this.operation.args) {
+                this.form.addControl(arg.name, new FormControl(arg.value, Validators.required));
+            }
         }
+
         this.subscription = this.form.valueChanges.subscribe(value => {
             if (this.onChange) {
                 this.onChange({

+ 7 - 1
admin-ui/src/i18n-messages/en.json

@@ -14,6 +14,7 @@
     "products": "Products",
     "promotions": "Promotions",
     "roles": "Roles",
+    "shipping-methods": "Shipping methods",
     "tax-categories": "Tax categories",
     "tax-rates": "Tax rates"
   },
@@ -94,6 +95,7 @@
     "password": "Password",
     "remember-me": "Remember me",
     "remove": "Remove",
+    "select": "Select...",
     "update": "Update",
     "updated": "Updated",
     "updated-at": "Updated at",
@@ -142,6 +144,7 @@
     "roles": "Roles",
     "sales": "Sales",
     "settings": "Settings",
+    "shipping-methods": "Shipping methods",
     "tax-categories": "Tax categories",
     "tax-rates": "Tax Rates"
   },
@@ -165,6 +168,7 @@
     "create-new-channel": "Create new channel",
     "create-new-country": "Create new country",
     "create-new-role": "Create new role",
+    "create-new-shipping-method": "Create new shipping method",
     "create-new-tax-category": "Create tax category",
     "create-new-tax-rate": "Create new tax rate",
     "create-zone": "Create zone",
@@ -188,9 +192,11 @@
     "section": "Section",
     "select-zone": "Select zone",
     "settings": "Settings",
+    "shipping-calculator": "Shipping calculator",
+    "shipping-eligibility-checker": "Shipping eligibility checker",
     "tax-category": "Tax category",
     "tax-rate": "Tax rate",
     "update": "Update",
     "zone": "Zone"
   }
-}
+}

+ 1 - 0
admin-ui/src/polyfills.ts

@@ -80,6 +80,7 @@ import '@clr/icons/shapes/commerce-shapes';
 import '@clr/icons/shapes/essential-shapes';
 import '@clr/icons/shapes/media-shapes';
 import '@clr/icons/shapes/technology-shapes';
+import '@clr/icons/shapes/travel-shapes';
 import '@webcomponents/custom-elements/custom-elements.min.js';
 // TODO: remove this shim once the newer version of graphql-js is released (14.0.0)
 // and check that the codegen still works (may need to upgrade apollo package).

Файлын зөрүү хэтэрхий том тул дарагдсан байна
+ 0 - 0
schema.json


+ 107 - 0
shared/generated-types.ts

@@ -72,6 +72,8 @@ export interface Query {
     role?: Role | null;
     shippingMethods: ShippingMethodList;
     shippingMethod?: ShippingMethod | null;
+    shippingEligibilityCheckers: AdjustmentOperation[];
+    shippingCalculators: AdjustmentOperation[];
     taxCategories: TaxCategory[];
     taxCategory?: TaxCategory | null;
     taxRates: TaxRateList;
@@ -1771,6 +1773,12 @@ export namespace QueryResolvers {
         role?: RoleResolver<Role | null, any, Context>;
         shippingMethods?: ShippingMethodsResolver<ShippingMethodList, any, Context>;
         shippingMethod?: ShippingMethodResolver<ShippingMethod | null, any, Context>;
+        shippingEligibilityCheckers?: ShippingEligibilityCheckersResolver<
+            AdjustmentOperation[],
+            any,
+            Context
+        >;
+        shippingCalculators?: ShippingCalculatorsResolver<AdjustmentOperation[], any, Context>;
         taxCategories?: TaxCategoriesResolver<TaxCategory[], any, Context>;
         taxCategory?: TaxCategoryResolver<TaxCategory | null, any, Context>;
         taxRates?: TaxRatesResolver<TaxRateList, any, Context>;
@@ -2064,6 +2072,16 @@ export namespace QueryResolvers {
         id: string;
     }
 
+    export type ShippingEligibilityCheckersResolver<
+        R = AdjustmentOperation[],
+        Parent = any,
+        Context = any
+    > = Resolver<R, Parent, Context>;
+    export type ShippingCalculatorsResolver<
+        R = AdjustmentOperation[],
+        Parent = any,
+        Context = any
+    > = Resolver<R, Parent, Context>;
     export type TaxCategoriesResolver<R = TaxCategory[], Parent = any, Context = any> = Resolver<
         R,
         Parent,
@@ -5071,6 +5089,78 @@ export namespace UpdateChannel {
     export type UpdateChannel = Channel.Fragment;
 }
 
+export namespace GetShippingMethodList {
+    export type Variables = {
+        options?: ShippingMethodListOptions | null;
+    };
+
+    export type Query = {
+        __typename?: 'Query';
+        shippingMethods: ShippingMethods;
+    };
+
+    export type ShippingMethods = {
+        __typename?: 'ShippingMethodList';
+        items: Items[];
+        totalItems: number;
+    };
+
+    export type Items = ShippingMethod.Fragment;
+}
+
+export namespace GetShippingMethod {
+    export type Variables = {
+        id: string;
+    };
+
+    export type Query = {
+        __typename?: 'Query';
+        shippingMethod?: ShippingMethod | null;
+    };
+
+    export type ShippingMethod = ShippingMethod.Fragment;
+}
+
+export namespace GetShippingMethodOperations {
+    export type Variables = {};
+
+    export type Query = {
+        __typename?: 'Query';
+        shippingEligibilityCheckers: ShippingEligibilityCheckers[];
+        shippingCalculators: ShippingCalculators[];
+    };
+
+    export type ShippingEligibilityCheckers = AdjustmentOperation.Fragment;
+
+    export type ShippingCalculators = AdjustmentOperation.Fragment;
+}
+
+export namespace CreateShippingMethod {
+    export type Variables = {
+        input: CreateShippingMethodInput;
+    };
+
+    export type Mutation = {
+        __typename?: 'Mutation';
+        createShippingMethod: CreateShippingMethod;
+    };
+
+    export type CreateShippingMethod = ShippingMethod.Fragment;
+}
+
+export namespace UpdateShippingMethod {
+    export type Variables = {
+        input: UpdateShippingMethodInput;
+    };
+
+    export type Mutation = {
+        __typename?: 'Mutation';
+        updateShippingMethod: UpdateShippingMethod;
+    };
+
+    export type UpdateShippingMethod = ShippingMethod.Fragment;
+}
+
 export namespace Administrator {
     export type Fragment = {
         __typename?: 'Administrator';
@@ -5544,3 +5634,20 @@ export namespace Channel {
         name: string;
     };
 }
+
+export namespace ShippingMethod {
+    export type Fragment = {
+        __typename?: 'ShippingMethod';
+        id: string;
+        createdAt: DateTime;
+        updatedAt: DateTime;
+        code: string;
+        description: string;
+        checker: Checker;
+        calculator: Calculator;
+    };
+
+    export type Checker = AdjustmentOperation.Fragment;
+
+    export type Calculator = AdjustmentOperation.Fragment;
+}

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно