Skip to content

Commit

Permalink
feat(admin-ui): Add date range & coupon code controls to PromotionDetail
Browse files Browse the repository at this point in the history
Relates to #174
  • Loading branch information
michaelbromley committed Oct 10, 2019
1 parent d9f5c41 commit 48def65
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 16 deletions.
12 changes: 11 additions & 1 deletion packages/admin-ui/src/app/common/generated-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -527,6 +527,7 @@ export type CreatePromotionInput = {
startsAt?: Maybe<Scalars['DateTime']>,
endsAt?: Maybe<Scalars['DateTime']>,
couponCode?: Maybe<Scalars['String']>,
perCustomerUsageLimit?: Maybe<Scalars['Int']>,
conditions: Array<ConfigurableOperationInput>,
actions: Array<ConfigurableOperationInput>,
};
Expand Down Expand Up @@ -2183,18 +2184,23 @@ export type Order = Node & {
id: Scalars['ID'],
createdAt: Scalars['DateTime'],
updatedAt: Scalars['DateTime'],
/** A unique code for the Order */
code: Scalars['String'],
state: Scalars['String'],
/** An order is active as long as the payment process has not been completed */
active: Scalars['Boolean'],
customer?: Maybe<Customer>,
shippingAddress?: Maybe<OrderAddress>,
billingAddress?: Maybe<OrderAddress>,
lines: Array<OrderLine>,
/** Order-level adjustments to the order total, such as discounts from promotions */
adjustments: Array<Adjustment>,
couponCodes: Array<Scalars['String']>,
promotions: Array<Promotion>,
payments?: Maybe<Array<Payment>>,
fulfillments?: Maybe<Array<Fulfillment>>,
subTotalBeforeTax: Scalars['Int'],
/** The subTotal is the total of the OrderLines, before order-level promotions and shipping has been applied. */
subTotal: Scalars['Int'],
currencyCode: CurrencyCode,
shipping: Scalars['Int'],
Expand Down Expand Up @@ -2636,6 +2642,7 @@ export type Promotion = Node & {
startsAt?: Maybe<Scalars['DateTime']>,
endsAt?: Maybe<Scalars['DateTime']>,
couponCode?: Maybe<Scalars['String']>,
perCustomerUsageLimit?: Maybe<Scalars['Int']>,
name: Scalars['String'],
enabled: Scalars['Boolean'],
conditions: Array<ConfigurableOperation>,
Expand All @@ -2648,6 +2655,7 @@ export type PromotionFilterParameter = {
startsAt?: Maybe<DateOperators>,
endsAt?: Maybe<DateOperators>,
couponCode?: Maybe<StringOperators>,
perCustomerUsageLimit?: Maybe<NumberOperators>,
name?: Maybe<StringOperators>,
enabled?: Maybe<BooleanOperators>,
};
Expand All @@ -2672,6 +2680,7 @@ export type PromotionSortParameter = {
startsAt?: Maybe<SortOrder>,
endsAt?: Maybe<SortOrder>,
couponCode?: Maybe<SortOrder>,
perCustomerUsageLimit?: Maybe<SortOrder>,
name?: Maybe<SortOrder>,
};

Expand Down Expand Up @@ -3419,6 +3428,7 @@ export type UpdatePromotionInput = {
startsAt?: Maybe<Scalars['DateTime']>,
endsAt?: Maybe<Scalars['DateTime']>,
couponCode?: Maybe<Scalars['String']>,
perCustomerUsageLimit?: Maybe<Scalars['Int']>,
conditions?: Maybe<Array<ConfigurableOperationInput>>,
actions?: Maybe<Array<ConfigurableOperationInput>>,
};
Expand Down Expand Up @@ -4009,7 +4019,7 @@ export type GetProductVariantOptionsQueryVariables = {

export type GetProductVariantOptionsQuery = ({ __typename?: 'Query' } & { product: Maybe<({ __typename?: 'Product' } & Pick<Product, 'id' | 'createdAt' | 'updatedAt' | 'name'> & { optionGroups: Array<({ __typename?: 'ProductOptionGroup' } & Pick<ProductOptionGroup, 'id' | 'name' | 'code'> & { options: Array<({ __typename?: 'ProductOption' } & Pick<ProductOption, 'id' | 'createdAt' | 'updatedAt' | 'name' | 'code'>)> })>, variants: Array<({ __typename?: 'ProductVariant' } & Pick<ProductVariant, 'id' | 'createdAt' | 'updatedAt' | 'enabled' | 'name' | 'sku' | 'price' | 'stockOnHand' | 'enabled'> & { options: Array<({ __typename?: 'ProductOption' } & Pick<ProductOption, 'id' | 'createdAt' | 'updatedAt' | 'name' | 'code' | 'groupId'>)> })> })> });

export type PromotionFragment = ({ __typename?: 'Promotion' } & Pick<Promotion, 'id' | 'createdAt' | 'updatedAt' | 'name' | 'enabled'> & { conditions: Array<({ __typename?: 'ConfigurableOperation' } & ConfigurableOperationFragment)>, actions: Array<({ __typename?: 'ConfigurableOperation' } & ConfigurableOperationFragment)> });
export type PromotionFragment = ({ __typename?: 'Promotion' } & Pick<Promotion, 'id' | 'createdAt' | 'updatedAt' | 'name' | 'enabled' | 'couponCode' | 'perCustomerUsageLimit' | 'startsAt' | 'endsAt'> & { conditions: Array<({ __typename?: 'ConfigurableOperation' } & ConfigurableOperationFragment)>, actions: Array<({ __typename?: 'ConfigurableOperation' } & ConfigurableOperationFragment)> });

export type GetPromotionListQueryVariables = {
options?: Maybe<PromotionListOptions>
Expand Down
6 changes: 3 additions & 3 deletions packages/admin-ui/src/app/common/introspection-result.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,9 @@ const result: IntrospectionResultData = {
{
name: 'Address',
},
{
name: 'Promotion',
},
{
name: 'Payment',
},
Expand Down Expand Up @@ -166,9 +169,6 @@ const result: IntrospectionResultData = {
{
name: 'Product',
},
{
name: 'Promotion',
},
],
},
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ export const PROMOTION_FRAGMENT = gql`
updatedAt
name
enabled
couponCode
perCustomerUsageLimit
startsAt
endsAt
conditions {
...ConfigurableOperation
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,7 @@
<div class="flex clr-align-items-center">
<vdr-entity-info [entity]="entity$ | async"></vdr-entity-info>
<clr-toggle-wrapper *vdrIfPermissions="'UpdatePromotion'">
<input
type="checkbox"
clrToggle
name="enabled"
[formControl]="detailForm.get(['enabled'])"
/>
<input type="checkbox" clrToggle name="enabled" [formControl]="detailForm.get(['enabled'])" />
<label>{{ 'common.enabled' | translate }}</label>
</clr-toggle-wrapper>
</div>
Expand Down Expand Up @@ -46,6 +41,42 @@
formControlName="name"
/>
</vdr-form-field>
<vdr-form-field [label]="'marketing.starts-at' | translate" for="startsAt">
<input
type="datetime-local"
name="startsAt"
[value]="detailForm.get('startsAt')?.value | date: 'yyyy-MM-ddTHH:mm:ss'"
(change)="updateDateTime(detailForm.get('startsAt')!, $event)"
[readonly]="!('UpdatePromotion' | hasPermission)"
/>
</vdr-form-field>
<vdr-form-field [label]="'marketing.ends-at' | translate" for="endsAt">
<input
type="datetime-local"
name="endsAt"
[value]="detailForm.get('endsAt')?.value | date: 'yyyy-MM-ddTHH:mm:ss'"
(change)="updateDateTime(detailForm.get('endsAt')!, $event)"
[readonly]="!('UpdatePromotion' | hasPermission)"
/>
</vdr-form-field>
<vdr-form-field [label]="'marketing.coupon-code' | translate" for="couponCode">
<input
id="couponCode"
[readonly]="!('UpdatePromotion' | hasPermission)"
type="text"
formControlName="couponCode"
/>
</vdr-form-field>
<vdr-form-field [label]="'marketing.per-customer-limit' | translate" for="perCustomerUsageLimit">
<input
id="perCustomerUsageLimit"
[readonly]="!('UpdatePromotion' | hasPermission)"
type="number"
min="1"
max="999"
formControlName="perCustomerUsageLimit"
/>
</vdr-form-field>

<div class="clr-row">
<div class="clr-col" formArrayName="conditions">
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit } from '@angular/core';
import { FormArray, FormBuilder, FormGroup, Validators } from '@angular/forms';
import { AbstractControl, FormArray, FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { mergeMap, shareReplay, take } from 'rxjs/operators';
Expand Down Expand Up @@ -53,6 +53,10 @@ export class PromotionDetailComponent extends BaseDetailComponent<Promotion.Frag
this.detailForm = this.formBuilder.group({
name: ['', Validators.required],
enabled: true,
couponCode: null,
perCustomerUsageLimit: null,
startsAt: null,
endsAt: null,
conditions: this.formBuilder.array([]),
actions: this.formBuilder.array([]),
});
Expand Down Expand Up @@ -103,7 +107,7 @@ export class PromotionDetailComponent extends BaseDetailComponent<Promotion.Frag
return (
this.detailForm.dirty &&
this.detailForm.valid &&
this.conditions.length !== 0 &&
(this.conditions.length !== 0 || this.detailForm.value.couponCode) &&
this.actions.length !== 0
);
}
Expand Down Expand Up @@ -132,6 +136,14 @@ export class PromotionDetailComponent extends BaseDetailComponent<Promotion.Frag
return this.detailForm.get(key) as FormArray;
}

// TODO: Remove this once a dedicated cross-browser datetime picker
// exists. See https://github.com/vendure-ecommerce/vendure/issues/181
updateDateTime(formControl: AbstractControl, event: Event) {
const value = (event.target as HTMLInputElement).value;
formControl.setValue(value ? new Date(value).toISOString() : null, { emitEvent: true });
formControl.parent.markAsDirty();
}

create() {
if (!this.detailForm.dirty) {
return;
Expand All @@ -140,6 +152,10 @@ export class PromotionDetailComponent extends BaseDetailComponent<Promotion.Frag
const input: CreatePromotionInput = {
name: formValue.name,
enabled: true,
couponCode: formValue.couponCode,
perCustomerUsageLimit: formValue.perCustomerUsageLimit,
startsAt: formValue.startsAt,
endsAt: formValue.endsAt,
conditions: this.mapOperationsToInputs(this.conditions, formValue.conditions),
actions: this.mapOperationsToInputs(this.actions, formValue.actions),
};
Expand Down Expand Up @@ -171,6 +187,10 @@ export class PromotionDetailComponent extends BaseDetailComponent<Promotion.Frag
id: promotion.id,
name: formValue.name,
enabled: formValue.enabled,
couponCode: formValue.couponCode,
perCustomerUsageLimit: formValue.perCustomerUsageLimit,
startsAt: formValue.startsAt,
endsAt: formValue.endsAt,
conditions: this.mapOperationsToInputs(this.conditions, formValue.conditions),
actions: this.mapOperationsToInputs(this.actions, formValue.actions),
};
Expand All @@ -197,7 +217,14 @@ export class PromotionDetailComponent extends BaseDetailComponent<Promotion.Frag
* Update the form values when the entity changes.
*/
protected setFormValues(entity: Promotion.Fragment, languageCode: LanguageCode): void {
this.detailForm.patchValue({ name: entity.name, enabled: entity.enabled });
this.detailForm.patchValue({
name: entity.name,
enabled: entity.enabled,
couponCode: entity.couponCode,
perCustomerUsageLimit: entity.perCustomerUsageLimit,
startsAt: entity.startsAt,
endsAt: entity.endsAt,
});
entity.conditions.forEach(o => {
this.addOperation('conditions', o);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<div
class="form-group"
[class.no-label]="!label"
[class.clr-error]="formFieldControl?.formControlName.invalid"
[class.clr-error]="formFieldControl?.formControlName?.invalid"
>
<label *ngIf="label" [for]="for" class="clr-control-label">
{{ label }}
Expand Down
7 changes: 5 additions & 2 deletions packages/admin-ui/src/i18n-messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@
"select": "Select...",
"there-are-unsaved-changes": "There are unsaved changes. Navigating away will cause these changes to be lost.",
"update": "Update",
"updated": "Updated",
"updated-at": "Updated at",
"username": "Username"
},
Expand Down Expand Up @@ -384,7 +383,11 @@
"add-action": "Add action",
"add-condition": "Add condition",
"conditions": "Conditions",
"create-new-promotion": "Create new promotion"
"coupon-code": "Coupon code",
"create-new-promotion": "Create new promotion",
"ends-at": "Ends at",
"per-customer-limit": "Per-customer limit",
"starts-at": "Starts at"
},
"nav": {
"administrators": "Administrators",
Expand Down
13 changes: 13 additions & 0 deletions packages/admin-ui/src/styles/theme/_forms.scss
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,19 @@ input, select {
max-height: none !important;
}

.clr-input-wrapper {
max-height: none !important;
}

.clr-input-group {
height: initial !important;
border-bottom: none;
&:focus, &.clr-focus {
background: none;
border-bottom: none;
}
}

.tooltip.tooltip-validation::before {
top: 10px !important;
}
Expand Down

0 comments on commit 48def65

Please sign in to comment.