Skip to content

Commit

Permalink
feat(admin-ui): Implement deletion of addresses from customer detail
Browse files Browse the repository at this point in the history
  • Loading branch information
michaelbromley committed Feb 24, 2022
1 parent 67f60ac commit 4a81f7c
Show file tree
Hide file tree
Showing 11 changed files with 104 additions and 24 deletions.
16 changes: 16 additions & 0 deletions packages/admin-ui/src/lib/core/src/common/generated-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}>;
Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
CustomerGroupListOptions,
CustomerListOptions,
DeleteCustomer,
DeleteCustomerAddress,
DeleteCustomerGroup,
DeleteCustomerNote,
GetCustomer,
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {}
Expand Down Expand Up @@ -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, {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,7 @@
margin-left: 6px;
color: var(--color-grey-500);
}

.to-delete {
opacity: 0.5;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
Customer,
CustomFieldConfig,
DataService,
DeleteCustomerAddress,
EditNoteDialogComponent,
GetAvailableCountries,
GetCustomer,
Expand All @@ -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,
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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({
Expand Down Expand Up @@ -231,6 +241,7 @@ export class CustomerDetailComponent
| UpdateCustomer.UpdateCustomer
| CreateCustomerAddress.CreateCustomerAddress
| UpdateCustomerAddress.UpdateCustomerAddress
| DeleteCustomerAddress.DeleteCustomerAddress
>
> = [];
const customerForm = this.detailForm.get('customer');
Expand Down Expand Up @@ -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)),
);
}
}
}
}
Expand All @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions packages/common/src/generated-shop-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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'];
};

Expand Down
4 changes: 2 additions & 2 deletions packages/core/e2e/graphql/generated-e2e-shop-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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'];
};

Expand Down
4 changes: 2 additions & 2 deletions packages/payments-plugin/e2e/graphql/generated-shop-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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'];
};

Expand Down

0 comments on commit 4a81f7c

Please sign in to comment.