Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add email event UI triggers for resend option in emails #3017

Open
wants to merge 23 commits into
base: minor
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
338e7f8
feat(email-plugin): Added email event ui options
monrostar Aug 17, 2024
dfbd766
feat(email-plugin): Added email event ui options
monrostar Aug 17, 2024
79e51d7
feat(email-plugin): Added email api handler and processing
monrostar Aug 18, 2024
2a3f4a0
Merge branch 'refs/heads/master' into feat/add-email-event-UI-triggers
monrostar Aug 20, 2024
3874629
feat(email-plugin): Update typings and rename properties and functions
monrostar Aug 20, 2024
de75a35
feat(email-plugin): Update typings and rename properties and functions
monrostar Aug 21, 2024
6872f58
@sphade has signed the CLA in vendure-ecommerce/vendure#3027
github-actions[bot] Aug 22, 2024
2fe5009
docs: Fix grammatical error (#3027)
sphade Aug 22, 2024
98918a2
feat(email-plugin): Update typings and rename properties and function…
monrostar Aug 22, 2024
d3a4f13
feat(email-plugin): Add ui component for email event resend
monrostar Aug 23, 2024
dc9a5c2
feat(email-plugin): Add ui component for email event resend
monrostar Aug 23, 2024
c28eb98
Merge branch 'refs/heads/master' into feat/add-email-event-UI-triggers
monrostar Aug 23, 2024
b195d83
feat(email-plugin): Fix component and add more translations
monrostar Aug 26, 2024
142e676
feat(email-plugin): Add tests for resend api and events and change types
monrostar Aug 27, 2024
5d168b6
Merge branch 'minor' into feat/add-email-event-UI-triggers
monrostar Aug 27, 2024
2ff6c38
feat(email-plugin): Changed the description of Resend example UI func…
monrostar Aug 27, 2024
16684bd
feat(email-plugin): Fix build
monrostar Aug 28, 2024
7477e61
feat(email-plugin): Fix build
monrostar Aug 28, 2024
21e1055
feat(email-plugin): Fix imports
monrostar Aug 28, 2024
fd909aa
feat(email-plugin): Fix tests
monrostar Aug 28, 2024
9ce8980
feat(email-plugin): Fix tests
monrostar Aug 28, 2024
9d8d1c2
feat(email-plugin): Tests were added for resend-email into the build
monrostar Aug 28, 2024
816fdd7
feat(email-plugin): Updated email-plugin package.json
monrostar Aug 28, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/docs/guides/storefront/checkout-flow/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ query GetShippingMethods {
The results can then be displayed to the customer so they can choose the desired shipping method. If there is only a single
result, then it can be automatically selected.

The desired shipping method's id is the passed to the [`setOrderShippingMethod`](/reference/graphql-api/shop/mutations/#setordershippingmethod) mutation.
The desired shipping method's id is then passed to the [`setOrderShippingMethod`](/reference/graphql-api/shop/mutations/#setordershippingmethod) mutation.

```graphql
mutation SetShippingMethod($id: [ID!]!) {
Expand Down
8 changes: 8 additions & 0 deletions license/signatures/version1/cla.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,14 @@
"created_at": "2024-08-13T15:47:42Z",
"repoId": 136938012,
"pullRequestNo": 3009
},
{
"name": "sphade",
"id": 85949974,
"comment_id": 2304127063,
"created_at": "2024-08-22T08:51:51Z",
"repoId": 136938012,
"pullRequestNo": 3027
}
]
}
49 changes: 49 additions & 0 deletions packages/admin-ui/src/lib/core/src/common/generated-types.ts

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions packages/admin-ui/src/lib/core/src/public_api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,9 @@ export * from './shared/components/dropdown/dropdown.component';
export * from './shared/components/duplicate-entity-dialog/duplicate-entity-dialog.component';
export * from './shared/components/duplicate-entity-dialog/duplicate-entity-dialog.graphql';
export * from './shared/components/edit-note-dialog/edit-note-dialog.component';
export * from './shared/components/email-configurable-input/email-event-configurable-input.component';
export * from './shared/components/email-event-list/email-event-list.component';
export * from './shared/components/email-event-list/email-event-list.graphql';
export * from './shared/components/empty-placeholder/empty-placeholder.component';
export * from './shared/components/entity-info/entity-info.component';
export * from './shared/components/extension-host/extension-host-config';
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<div class="card" *ngIf="operation">
<div class="card-block" *ngIf="hideDescription !== true">{{ interpolateDescription() }}</div>
<div class="card-block" *ngIf="operation.args?.length">
<form [formGroup]="form" *ngIf="operation" class="operation-inputs">
<div *ngFor="let arg of operation.args; trackBy: trackByName" class="arg-row">
<ng-container *ngIf="form.get(arg.name) && getArgDef(arg) as argDef">
<label class="clr-control-label">{{ argDef.label || (arg.name | sentenceCase) }}</label>
<vdr-help-tooltip
class="mr3"
*ngIf="argDef.description"
[content]="argDef.description"
></vdr-help-tooltip>
<vdr-dynamic-form-input
[def]="getArgDef(arg)"
[readonly]="readonly"
[control]="form.get(arg.name)"
[formControlName]="arg.name"
></vdr-dynamic-form-input>
</ng-container>
</div>
</form>
</div>
<div class="card-footer">
<button class="button-small" *ngIf="canSubmit()" (click)="resend.emit(operation)">
<clr-icon shape="email"></clr-icon>
{{ 'common.resend' | translate }}
</button>
</div>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
:host {
display: block;
margin-bottom: 12px;

> .card {
margin-top: 6px;
}
}

.operation-inputs {
padding-top: 0;

.arg-row:not(:last-child) {
margin-bottom: 12px;
}

.arg-row {
display: flex;
flex-wrap: wrap;
align-items: center;
label {
margin-inline-end: 6px;
}
}

.hidden {
display: none;
}
label {
min-width: 130px;
display: inline-block;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,186 @@
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
forwardRef,
Input,
OnChanges,
OnDestroy,
OnInit,
Output,
SimpleChanges,
} from '@angular/core';
import {
AbstractControl,
ControlValueAccessor,
NG_VALIDATORS,
NG_VALUE_ACCESSOR,
UntypedFormControl,
UntypedFormGroup,
ValidationErrors,
Validator,
Validators,
} from '@angular/forms';
import { BehaviorSubject, Observable, Subscription } from 'rxjs';
import { configurableOperationValueIsValid, getDefaultConfigArgValue } from '@vendure/admin-ui/core';
import {
ConfigArg,
ConfigArgDefinition,
ConfigurableOperation,
ConfigurableOperationDefinition,
} from '../../../common/generated-types';
import { CurrencyService } from '../../../providers/currency/currency.service';
import { interpolateDescription } from '../../../common/utilities/interpolate-description';

/**
* A form input which renders a card with the internal form fields of the given ConfigurableOperation.
*/
@Component({
selector: 'vdr-email-event-configurable-input',
templateUrl: './email-event-configurable-input.component.html',
styleUrls: ['./email-event-configurable-input.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: EmailEventConfigurableInputComponent,
multi: true,
},
{
provide: NG_VALIDATORS,
useExisting: forwardRef(() => EmailEventConfigurableInputComponent),
multi: true,
},
],
})
export class EmailEventConfigurableInputComponent
implements OnInit, OnChanges, OnDestroy, ControlValueAccessor, Validator
{
@Input() operation?: ConfigurableOperation;
@Input() operationDefinition?: ConfigurableOperationDefinition;
@Input() readonly = false;
@Input() removable = true;
@Input() position = 0;
@Input() hideDescription = false;
@Output() resend = new EventEmitter<ConfigurableOperation>();
argValues: { [name: string]: any } = {};
onChange: (val: any) => void;
onTouch: () => void;
form = new UntypedFormGroup({});
positionChange$: Observable<number>;
private positionChangeSubject = new BehaviorSubject<number>(0);
private subscription: Subscription;

constructor(private currencyService: CurrencyService) {}

interpolateDescription(): string {
if (this.operationDefinition) {
return interpolateDescription(
this.operationDefinition,
this.form.value,
this.currencyService.precisionFactor,
);
} else {
return '';
}
}

ngOnInit() {
this.positionChange$ = this.positionChangeSubject.asObservable();
}

ngOnChanges(changes: SimpleChanges) {
if ('operation' in changes || 'operationDefinition' in changes) {
console.log('operation/operationDefinition changes', changes);
this.createForm();
}
if ('position' in changes) {
console.log('position changes', changes);
this.positionChangeSubject.next(this.position);
}
}

ngOnDestroy() {
if (this.subscription) {
this.subscription.unsubscribe();
}
}

registerOnChange(fn: any) {
this.onChange = fn;
}

registerOnTouched(fn: any) {
this.onTouch = fn;
}

setDisabledState(isDisabled: boolean) {
if (isDisabled) {
this.form.disable();
} else {
this.form.enable();
}
}

writeValue(value: any): void {
if (value) {
console.log('writeValue', value);
this.form.patchValue(value);
}
}

trackByName(index: number, arg: ConfigArg): string {
return arg.name;
}

getArgDef(arg: ConfigArg): ConfigArgDefinition | undefined {
return this.operationDefinition?.args.find(a => a.name === arg.name);
}

private createForm() {
if (!this.operation) {
return;
}
if (this.subscription) {
this.subscription.unsubscribe();
}
this.form = new UntypedFormGroup({});
(this.form as any).__id = Math.random().toString(36).substr(10);

if (this.operation.args) {
for (const arg of this.operationDefinition?.args || []) {
let value: any = this.operation.args.find(a => a.name === arg.name)?.value;
if (value === undefined) {
value = getDefaultConfigArgValue(arg);
}
const validators = arg.list ? undefined : arg.required ? Validators.required : undefined;
this.form.addControl(arg.name, new UntypedFormControl(value, validators));
}
}

this.subscription = this.form.valueChanges.subscribe(value => {
if (this.onChange) {
this.onChange({
code: this.operation && this.operation.code,
args: value,
});
}
if (this.onTouch) {
this.onTouch();
}
});
}

async canSubmit(): Promise<boolean> {
return configurableOperationValueIsValid(this.operationDefinition, this.form.value);
}

validate(c: AbstractControl): ValidationErrors | null {
if (this.form.invalid) {
return {
required: true,
};
}
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<vdr-card class="mb-3" [formGroup]="emailEventFormGroup" *ngIf="(emailEvents$ | async) as emailEvents">
<div *ngFor="let emailEvent of emailEvents">
<vdr-email-event-configurable-input
class="card-span"
[hideDescription]="false"
[operation]="emailEventsOperations.get(emailEvent.type)"
[operationDefinition]="emailEvent.operationDefinitions"
[formControlName]="emailEvent.type"
(resend)="onResend(emailEvent.type)"
></vdr-email-event-configurable-input>
</div>
</vdr-card>
Loading
Loading