Explorar el Código

feat(admin-ui): Implement deletion of addresses from customer detail

Michael Bromley hace 3 años
padre
commit
4a81f7c57d

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

@@ -5893,6 +5893,16 @@ export type UpdateCustomerAddressMutation = { updateCustomerAddress: (
     & AddressFragment
   ) };
 
+export type DeleteCustomerAddressMutationVariables = Exact<{
+  id: Scalars['ID'];
+}>;
+
+
+export type DeleteCustomerAddressMutation = { deleteCustomerAddress: (
+    { __typename?: 'Success' }
+    & Pick<Success, 'success'>
+  ) };
+
 export type CreateCustomerGroupMutationVariables = Exact<{
   input: CreateCustomerGroupInput;
 }>;
@@ -9366,6 +9376,12 @@ export namespace UpdateCustomerAddress {
   export type UpdateCustomerAddress = (NonNullable<UpdateCustomerAddressMutation['updateCustomerAddress']>);
 }
 
+export namespace DeleteCustomerAddress {
+  export type Variables = DeleteCustomerAddressMutationVariables;
+  export type Mutation = DeleteCustomerAddressMutation;
+  export type DeleteCustomerAddress = (NonNullable<DeleteCustomerAddressMutation['deleteCustomerAddress']>);
+}
+
 export namespace CreateCustomerGroup {
   export type Variables = CreateCustomerGroupMutationVariables;
   export type Mutation = CreateCustomerGroupMutation;

+ 8 - 0
packages/admin-ui/src/lib/core/src/data/definitions/customer-definitions.ts

@@ -151,6 +151,14 @@ export const UPDATE_CUSTOMER_ADDRESS = gql`
     ${ADDRESS_FRAGMENT}
 `;
 
+export const DELETE_CUSTOMER_ADDRESS = gql`
+    mutation DeleteCustomerAddress($id: ID!) {
+        deleteCustomerAddress(id: $id) {
+            success
+        }
+    }
+`;
+
 export const CREATE_CUSTOMER_GROUP = gql`
     mutation CreateCustomerGroup($input: CreateCustomerGroupInput!) {
         createCustomerGroup(input: $input) {

+ 10 - 1
packages/admin-ui/src/lib/core/src/data/providers/customer-data.service.ts

@@ -10,6 +10,7 @@ import {
     CustomerGroupListOptions,
     CustomerListOptions,
     DeleteCustomer,
+    DeleteCustomerAddress,
     DeleteCustomerGroup,
     DeleteCustomerNote,
     GetCustomer,
@@ -36,11 +37,12 @@ import {
     CREATE_CUSTOMER_ADDRESS,
     CREATE_CUSTOMER_GROUP,
     DELETE_CUSTOMER,
+    DELETE_CUSTOMER_ADDRESS,
     DELETE_CUSTOMER_GROUP,
     DELETE_CUSTOMER_NOTE,
     GET_CUSTOMER,
-    GET_CUSTOMER_GROUP_WITH_CUSTOMERS,
     GET_CUSTOMER_GROUPS,
+    GET_CUSTOMER_GROUP_WITH_CUSTOMERS,
     GET_CUSTOMER_HISTORY,
     GET_CUSTOMER_LIST,
     REMOVE_CUSTOMERS_FROM_GROUP,
@@ -129,6 +131,13 @@ export class CustomerDataService {
         );
     }
 
+    deleteCustomerAddress(id: string) {
+        return this.baseDataService.mutate<DeleteCustomerAddress.Mutation, DeleteCustomerAddress.Variables>(
+            DELETE_CUSTOMER_ADDRESS,
+            { id },
+        );
+    }
+
     createCustomerGroup(input: CreateCustomerGroupInput) {
         return this.baseDataService.mutate<CreateCustomerGroup.Mutation, CreateCustomerGroup.Variables>(
             CREATE_CUSTOMER_GROUP,

+ 10 - 0
packages/admin-ui/src/lib/customer/src/components/address-card/address-card.component.html

@@ -48,6 +48,16 @@
                     >
                         {{ 'customer.set-as-default-billing-address' | translate }}
                     </button>
+                    <div class="dropdown-divider"></div>
+                    <button
+                        type="button"
+                        class="delete-button"
+                        (click)="delete()"
+                        vdrDropdownItem
+                    >
+                        <clr-icon shape="trash" class="is-danger"></clr-icon>
+                        {{ 'common.delete' | translate }}
+                    </button>
                 </vdr-dropdown-menu>
             </vdr-dropdown>
         </ng-container>

+ 6 - 0
packages/admin-ui/src/lib/customer/src/components/address-card/address-card.component.ts

@@ -31,6 +31,7 @@ export class AddressCardComponent implements OnInit, OnChanges {
     @Input() editable = true;
     @Output() setAsDefaultShipping = new EventEmitter<string>();
     @Output() setAsDefaultBilling = new EventEmitter<string>();
+    @Output() deleteAddress = new EventEmitter<string>();
     private dataDependenciesPopulated = new BehaviorSubject<boolean>(false);
 
     constructor(private modalService: ModalService, private changeDetector: ChangeDetectorRef) {}
@@ -75,6 +76,11 @@ export class AddressCardComponent implements OnInit, OnChanges {
         this.addressForm.markAsDirty();
     }
 
+    delete() {
+        this.deleteAddress.emit(this.addressForm.value.id);
+        this.addressForm.markAsDirty();
+    }
+
     editAddress() {
         this.modalService
             .fromComponent(AddressDetailDialogComponent, {

+ 3 - 1
packages/admin-ui/src/lib/customer/src/components/customer-detail/customer-detail.component.html

@@ -118,14 +118,16 @@
         <h3>{{ 'customer.addresses' | translate }}</h3>
         <vdr-address-card
             *ngFor="let addressForm of getAddressFormControls()"
+            [class.to-delete]="addressesToDeleteIds.has(addressForm.value.id)"
             [availableCountries]="availableCountries$ | async"
             [isDefaultBilling]="defaultBillingAddressId === addressForm.value.id"
             [isDefaultShipping]="defaultShippingAddressId === addressForm.value.id"
             [addressForm]="addressForm"
             [customFields]="addressCustomFields"
-            [editable]="['UpdateCustomer'] | hasPermission"
+            [editable]="(['UpdateCustomer'] | hasPermission) && !addressesToDeleteIds.has(addressForm.value.id)"
             (setAsDefaultBilling)="setDefaultBillingAddressId($event)"
             (setAsDefaultShipping)="setDefaultShippingAddressId($event)"
+            (deleteAddress)="toggleDeleteAddress($event)"
         ></vdr-address-card>
         <button class="btn btn-secondary" (click)="addAddress()" *vdrIfPermissions="'UpdateCustomer'">
             <clr-icon shape="plus"></clr-icon>

+ 4 - 0
packages/admin-ui/src/lib/customer/src/components/customer-detail/customer-detail.component.scss

@@ -3,3 +3,7 @@
     margin-left: 6px;
     color: var(--color-grey-500);
 }
+
+.to-delete {
+    opacity: 0.5;
+}

+ 41 - 16
packages/admin-ui/src/lib/customer/src/components/customer-detail/customer-detail.component.ts

@@ -11,6 +11,7 @@ import {
     Customer,
     CustomFieldConfig,
     DataService,
+    DeleteCustomerAddress,
     EditNoteDialogComponent,
     GetAvailableCountries,
     GetCustomer,
@@ -27,7 +28,7 @@ import {
     UpdateCustomerInput,
     UpdateCustomerMutation,
 } from '@vendure/admin-ui/core';
-import { notNullOrUndefined } from '@vendure/common/lib/shared-utils';
+import { assertNever, notNullOrUndefined } from '@vendure/common/lib/shared-utils';
 import { EMPTY, forkJoin, from, Observable, Subject } from 'rxjs';
 import {
     concatMap,
@@ -65,6 +66,7 @@ export class CustomerDetailComponent
     fetchHistory = new Subject<void>();
     defaultShippingAddressId: string;
     defaultBillingAddressId: string;
+    addressesToDeleteIds = new Set<string>();
     addressDefaultsUpdated = false;
     ordersPerPage = 10;
     currentOrdersPage = 1;
@@ -144,6 +146,14 @@ export class CustomerDetailComponent
         this.addressDefaultsUpdated = true;
     }
 
+    toggleDeleteAddress(id: string) {
+        if (this.addressesToDeleteIds.has(id)) {
+            this.addressesToDeleteIds.delete(id);
+        } else {
+            this.addressesToDeleteIds.add(id);
+        }
+    }
+
     addAddress() {
         const addressFormArray = this.detailForm.get('addresses') as FormArray;
         const newAddress = this.formBuilder.group({
@@ -231,6 +241,7 @@ export class CustomerDetailComponent
                             | UpdateCustomer.UpdateCustomer
                             | CreateCustomerAddress.CreateCustomerAddress
                             | UpdateCustomerAddress.UpdateCustomerAddress
+                            | DeleteCustomerAddress.DeleteCustomerAddress
                         >
                     > = [];
                     const customerForm = this.detailForm.get('customer');
@@ -278,14 +289,22 @@ export class CustomerDetailComponent
                                             .pipe(map(res => res.createCustomerAddress)),
                                     );
                                 } else {
-                                    saveOperations.push(
-                                        this.dataService.customer
-                                            .updateCustomerAddress({
-                                                ...input,
-                                                id: address.id,
-                                            })
-                                            .pipe(map(res => res.updateCustomerAddress)),
-                                    );
+                                    if (this.addressesToDeleteIds.has(address.id)) {
+                                        saveOperations.push(
+                                            this.dataService.customer
+                                                .deleteCustomerAddress(address.id)
+                                                .pipe(map(res => res.deleteCustomerAddress)),
+                                        );
+                                    } else {
+                                        saveOperations.push(
+                                            this.dataService.customer
+                                                .updateCustomerAddress({
+                                                    ...input,
+                                                    id: address.id,
+                                                })
+                                                .pipe(map(res => res.updateCustomerAddress)),
+                                        );
+                                    }
                                 }
                             }
                         }
@@ -295,17 +314,23 @@ export class CustomerDetailComponent
             )
             .subscribe(
                 data => {
+                    let notified = false;
                     for (const result of data) {
                         switch (result.__typename) {
                             case 'Customer':
                             case 'Address':
-                                this.notificationService.success(_('common.notify-update-success'), {
-                                    entity: 'Customer',
-                                });
-                                this.detailForm.markAsPristine();
-                                this.addressDefaultsUpdated = false;
-                                this.changeDetector.markForCheck();
-                                this.fetchHistory.next();
+                            case 'Success':
+                                if (!notified) {
+                                    this.notificationService.success(_('common.notify-update-success'), {
+                                        entity: 'Customer',
+                                    });
+                                    notified = true;
+                                    this.detailForm.markAsPristine();
+                                    this.addressDefaultsUpdated = false;
+                                    this.changeDetector.markForCheck();
+                                    this.fetchHistory.next();
+                                    this.dataService.customer.getCustomer(this.id).single$.subscribe();
+                                }
                                 break;
                             case 'EmailAddressConflictError':
                                 this.notificationService.error(result.message);

+ 2 - 2
packages/common/src/generated-shop-types.ts

@@ -1622,7 +1622,7 @@ export type Mutation = {
     /**
      * Verify a Customer email address with the token sent to that address. Only applicable if `authOptions.requireVerification` is set to true.
      *
-     * If the Customer was not registered with a password in the `registerCustomerAccount` mutation, the a password _must_ be
+     * If the Customer was not registered with a password in the `registerCustomerAccount` mutation, the password _must_ be
      * provided here.
      */
     verifyCustomerAccount: VerifyCustomerAccountResult;
@@ -2834,7 +2834,7 @@ export type SearchResult = {
     facetValueIds: Array<Scalars['ID']>;
     /** An array of ids of the Collections in which this result appears */
     collectionIds: Array<Scalars['ID']>;
-    /** A relevence score for the result. Differs between database implementations */
+    /** A relevance score for the result. Differs between database implementations */
     score: Scalars['Float'];
 };
 

+ 2 - 2
packages/core/e2e/graphql/generated-e2e-shop-types.ts

@@ -1568,7 +1568,7 @@ export type Mutation = {
     /**
      * Verify a Customer email address with the token sent to that address. Only applicable if `authOptions.requireVerification` is set to true.
      *
-     * If the Customer was not registered with a password in the `registerCustomerAccount` mutation, the a password _must_ be
+     * If the Customer was not registered with a password in the `registerCustomerAccount` mutation, the password _must_ be
      * provided here.
      */
     verifyCustomerAccount: VerifyCustomerAccountResult;
@@ -2736,7 +2736,7 @@ export type SearchResult = {
     facetValueIds: Array<Scalars['ID']>;
     /** An array of ids of the Collections in which this result appears */
     collectionIds: Array<Scalars['ID']>;
-    /** A relevence score for the result. Differs between database implementations */
+    /** A relevance score for the result. Differs between database implementations */
     score: Scalars['Float'];
 };
 

+ 2 - 2
packages/payments-plugin/e2e/graphql/generated-shop-types.ts

@@ -1568,7 +1568,7 @@ export type Mutation = {
     /**
      * Verify a Customer email address with the token sent to that address. Only applicable if `authOptions.requireVerification` is set to true.
      *
-     * If the Customer was not registered with a password in the `registerCustomerAccount` mutation, the a password _must_ be
+     * If the Customer was not registered with a password in the `registerCustomerAccount` mutation, the password _must_ be
      * provided here.
      */
     verifyCustomerAccount: VerifyCustomerAccountResult;
@@ -2736,7 +2736,7 @@ export type SearchResult = {
     facetValueIds: Array<Scalars['ID']>;
     /** An array of ids of the Collections in which this result appears */
     collectionIds: Array<Scalars['ID']>;
-    /** A relevence score for the result. Differs between database implementations */
+    /** A relevance score for the result. Differs between database implementations */
     score: Scalars['Float'];
 };