diff --git a/projects/account/src/app/modules/profile/components/cards/membership/membership.component.html b/projects/account/src/app/modules/profile/components/cards/membership/membership.component.html index c6fef63..fb05305 100644 --- a/projects/account/src/app/modules/profile/components/cards/membership/membership.component.html +++ b/projects/account/src/app/modules/profile/components/cards/membership/membership.component.html @@ -7,7 +7,7 @@ diff --git a/projects/account/src/app/modules/profile/components/cards/membership/membership.component.ts b/projects/account/src/app/modules/profile/components/cards/membership/membership.component.ts index a5c748f..10aea56 100644 --- a/projects/account/src/app/modules/profile/components/cards/membership/membership.component.ts +++ b/projects/account/src/app/modules/profile/components/cards/membership/membership.component.ts @@ -1,12 +1,15 @@ import { Component, Input, OnDestroy } from '@angular/core'; import { MediaChange, MediaObserver } from '@angular/flex-layout'; -import { MatBottomSheet } from '@angular/material'; +import { MatSnackBar } from '@angular/material'; import { Subscription } from 'rxjs'; import { AccountMembership } from '@account/models/account-membership.model'; import { MembershipType } from '@account/models/membership.model'; +import { MembershipUpdate } from '@account/models/membership-update.model'; import { ProfileService } from '@account/http/profile.service'; -import { PaymentComponent } from '../../views/payment/payment.component'; + +const twoSeconds = 2000; + @Component({ selector: 'account-membership-edit', @@ -15,14 +18,14 @@ import { PaymentComponent } from '../../views/payment/payment.component'; }) export class MembershipComponent implements OnDestroy { @Input() accountMembership: AccountMembership; - public alignVertical: boolean; @Input() membershipTypes: MembershipType[]; + public alignVertical: boolean; private mediaWatcher: Subscription; constructor( - public bottomSheet: MatBottomSheet, public mediaObserver: MediaObserver, private profileService: ProfileService, + private snackbar: MatSnackBar ) { this.mediaWatcher = mediaObserver.media$.subscribe( (change: MediaChange) => { @@ -35,43 +38,15 @@ export class MembershipComponent implements OnDestroy { this.mediaWatcher.unsubscribe(); } - onMembershipChange(membershipType: string) { - const selectedMembership = this.membershipTypes.find( - (membership) => membership.type === membershipType - ); - if (selectedMembership) { - if (this.accountMembership) { - // We have the user's credit card info but they decide to change plans - this.profileService.updateAccount( - {membership: {paymentMethod: 'Stripe', newMembership: false, membershipType: membershipType}} - ); - } else { - // No credit card info. Go to payment screen to collect - this.openBottomSheet(membershipType); - } - } else { - // Membership termination - this.profileService.updateAccount( - {membership: {paymentMethod: 'Stripe', newMembership: false, membershipType: null}} + updateAccount(membershipUpdate: MembershipUpdate) { + const accountUpdate = {membership: membershipUpdate}; + this.profileService.updateAccount(accountUpdate).subscribe( + () => { + this.snackbar.open( + 'Membership updated', + null, + {panelClass: 'mycroft-no-action-snackbar', duration: twoSeconds} ); - } - } - - openBottomSheet(membershipType: string) { - const bottomSheetConfig = { - data: {newAccount: false, membershipType: membershipType}, - disableClose: true, - restoreFocus: true - }; - const bottomSheetRef = this.bottomSheet.open(PaymentComponent, bottomSheetConfig); - bottomSheetRef.afterDismissed().subscribe( - (dismissValue) => { - if (dismissValue === 'cancel') { - this.profileService.setSelectedMembershipType( - this.accountMembership, - this.membershipTypes - ); - } } ); } diff --git a/projects/account/src/app/modules/profile/components/controls/membership-options/membership-options.component.ts b/projects/account/src/app/modules/profile/components/controls/membership-options/membership-options.component.ts index f1e1954..6580054 100644 --- a/projects/account/src/app/modules/profile/components/controls/membership-options/membership-options.component.ts +++ b/projects/account/src/app/modules/profile/components/controls/membership-options/membership-options.component.ts @@ -1,12 +1,14 @@ import { Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; import { MediaChange, MediaObserver } from '@angular/flex-layout'; -import { MatButtonToggleChange } from '@angular/material'; +import { MatButtonToggleChange, MatDialog, MatDialogConfig, MatSnackBar } from '@angular/material'; import { Subscription } from 'rxjs'; -import { AccountMembership } from '../../../../../shared/models/account-membership.model'; -import { MembershipType } from '../../../../../shared/models/membership.model'; -import { ProfileService } from '../../../../../core/http/profile.service'; +import { AccountMembership } from '@account/models/account-membership.model'; +import { MembershipType } from '@account/models/membership.model'; +import { ProfileService } from '@account/http/profile.service'; +import { PaymentComponent } from '@account/app/modules/profile/components/views/payment/payment.component'; +import { MembershipUpdate } from '@account/models/membership-update.model'; @Component({ @@ -16,13 +18,18 @@ import { ProfileService } from '../../../../../core/http/profile.service'; }) export class MembershipOptionsComponent implements OnInit, OnDestroy { @Input() accountMembership: AccountMembership; - public alignVertical: boolean; @Input() membershipTypes: MembershipType[]; + @Output() membershipChange = new EventEmitter(); + public alignVertical: boolean; public mediaWatcher: Subscription; - @Output() membershipChange = new EventEmitter(); public selectedMembershipType: string; - constructor(public mediaObserver: MediaObserver, private profileService: ProfileService) { + constructor( + public mediaObserver: MediaObserver, + private profileService: ProfileService, + public paymentDialog: MatDialog, + private snackbar: MatSnackBar + ) { this.mediaWatcher = mediaObserver.media$.subscribe( (change: MediaChange) => { this.alignVertical = ['xs', 'sm'].includes(change.mqAlias); @@ -45,9 +52,49 @@ export class MembershipOptionsComponent implements OnInit, OnDestroy { this.mediaWatcher.unsubscribe(); } - onMembershipSelect(newMembershipType: MatButtonToggleChange) { - this.profileService.selectedMembershipType.next(newMembershipType.value); - this.membershipChange.emit(newMembershipType.value); + onMembershipSelect(membershipType: MatButtonToggleChange) { + const selectedMembership = this.membershipTypes.find( + (membership) => membership.type === membershipType.value + ); + let membershipUpdate; + if (selectedMembership) { + if (this.accountMembership) { + // We have the user's credit card info but they decide to change plans + membershipUpdate = { + paymentMethod: 'Stripe', + newMembership: false, + membershipType: membershipType + }; + this.membershipChange.emit(membershipUpdate); + } else { + // No credit card info. Go to payment dialog to collect + this.openPaymentDialog(membershipType.value); + } + } else { + // Membership termination + membershipUpdate = {newMembership: false, membershipType: null}; + this.membershipChange.emit(membershipUpdate); + } } + openPaymentDialog(membershipType: string) { + const dialogConfig = new MatDialogConfig(); + dialogConfig.data = {newAccount: false, membershipType: membershipType}; + dialogConfig.disableClose = true; + dialogConfig.restoreFocus = true; + const dialogRef = this.paymentDialog.open(PaymentComponent, dialogConfig); + dialogRef.afterClosed().subscribe( + (stripeToken) => { + if (stripeToken) { + const membershipUpdate: MembershipUpdate = { + newMembership: true, + membershipType: membershipType, + paymentMethod: 'Stripe', + paymentToken: stripeToken + }; + this.membershipChange.emit(membershipUpdate); + } + } + ); + } } diff --git a/projects/account/src/app/modules/profile/components/views/payment/payment.component.html b/projects/account/src/app/modules/profile/components/views/payment/payment.component.html index bcd02e8..898de12 100644 --- a/projects/account/src/app/modules/profile/components/views/payment/payment.component.html +++ b/projects/account/src/app/modules/profile/components/views/payment/payment.component.html @@ -8,7 +8,7 @@ - - + + diff --git a/projects/account/src/app/modules/profile/components/views/payment/payment.component.scss b/projects/account/src/app/modules/profile/components/views/payment/payment.component.scss index 4660d16..b387061 100644 --- a/projects/account/src/app/modules/profile/components/views/payment/payment.component.scss +++ b/projects/account/src/app/modules/profile/components/views/payment/payment.component.scss @@ -1,13 +1,12 @@ -@import "../../../../../../../../../node_modules/@angular/material/theming"; +@import "~@angular/material/theming"; @import "mycroft-colors"; -@import "../../../../../../../../../src/stylesheets/components/buttons"; +@import "components/buttons"; mat-card { margin-right: auto; margin-left: auto; - margin-bottom: 16px; max-width: 500px; - padding: 32px; + padding: 0; mat-card-title { color: mat-color($mycroft-primary, 700); @@ -28,12 +27,18 @@ mat-card { border-width: 1px; border-color: mat-color($mycroft-accent, 200); padding: 16px; + margin-bottom: 40px; width: 320px; } } - #submit-button { - @include action-button-primary; - margin-top: 16px + .mat-card-actions.mat-card-actions { + padding: 0; + margin: 0; + + .submit-button { + @include action-button-primary; + } } + } diff --git a/projects/account/src/app/modules/profile/components/views/payment/payment.component.ts b/projects/account/src/app/modules/profile/components/views/payment/payment.component.ts index 3691bef..229c4af 100644 --- a/projects/account/src/app/modules/profile/components/views/payment/payment.component.ts +++ b/projects/account/src/app/modules/profile/components/views/payment/payment.component.ts @@ -1,7 +1,6 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, Inject, OnInit, ViewChild } from '@angular/core'; import { - MatBottomSheetRef, - MatDialog, + MAT_DIALOG_DATA, MatDialogRef, MatSnackBar } from '@angular/material'; @@ -9,7 +8,6 @@ import { import { ElementOptions, StripeCardComponent, StripeService } from 'ngx-stripe'; import { ProfileService } from '@account/http/profile.service'; -import { VerifyCardDialogComponent } from './verify-card-dialog.component'; const twoSeconds = 2000; @@ -32,14 +30,13 @@ export class PaymentComponent implements OnInit { } } }; - private dialogRef: MatDialogRef; constructor( - private bottomSheetRef: MatBottomSheetRef, - private paymentSnackbar: MatSnackBar, + public dialogRef: MatDialogRef, + private snackbar: MatSnackBar, private profileService: ProfileService, private stripeService: StripeService, - public verifyCardDialog: MatDialog + @Inject(MAT_DIALOG_DATA) public dialogData: any ) { } @@ -47,60 +44,23 @@ export class PaymentComponent implements OnInit { ngOnInit() { } - submitPayment() { - this.openDialog(); + submitPaymentInfo() { this.stripeService.createToken(this.card.getCard(), {}).subscribe( result => { if (result.token) { - const configData = this.bottomSheetRef.containerInstance.bottomSheetConfig.data; - if (configData.newAccount) { - this.showStripeSuccess(result.token.id); - } else { - this.updateAccount(configData.membershipType, result.token.id); - } + this.dialogRef.close(result.token.id); } else if (result.error) { this.showStripeError(result.error.message); } - } + }, + (result) => { this.showStripeError(result.toString()); } ); - } - openDialog(): void { - this.dialogRef = this.verifyCardDialog.open( - VerifyCardDialogComponent, - {width: '250px'} - ); - } - - updateAccount(membershipType: string, stripeToken: string) { - const newMembership = { - membership: { - newMembership: true, - membershipType: membershipType, - paymentMethod: 'Stripe', - paymentToken: stripeToken - } - }; - this.profileService.updateAccount(newMembership).subscribe( - () => { this.showStripeSuccess(stripeToken); } - ); - } - - showStripeSuccess(stripeToken: string) { - this.dialogRef.close(); - const paymentSnackbarRef = this.paymentSnackbar.open( - 'Card verification successful', - null, - {panelClass: 'mycroft-no-action-snackbar', duration: twoSeconds} - ); - paymentSnackbarRef.afterDismissed().subscribe( - () => { this.bottomSheetRef.dismiss(stripeToken); } - ); } showStripeError(errorMessage: string) { this.dialogRef.close(); - this.paymentSnackbar.open( + this.snackbar.open( errorMessage, null, {panelClass: 'mycroft-no-action-snackbar', duration: twoSeconds} @@ -108,6 +68,6 @@ export class PaymentComponent implements OnInit { } onCancel() { - this.bottomSheetRef.dismiss('cancel'); + this.dialogRef.close(); } } diff --git a/projects/account/src/app/modules/profile/components/views/support-step/support-step.component.html b/projects/account/src/app/modules/profile/components/views/support-step/support-step.component.html index 99604b4..1d0acfc 100644 --- a/projects/account/src/app/modules/profile/components/views/support-step/support-step.component.html +++ b/projects/account/src/app/modules/profile/components/views/support-step/support-step.component.html @@ -5,7 +5,7 @@

diff --git a/projects/account/src/app/modules/profile/components/views/support-step/support-step.component.ts b/projects/account/src/app/modules/profile/components/views/support-step/support-step.component.ts index 8006034..ec9377b 100644 --- a/projects/account/src/app/modules/profile/components/views/support-step/support-step.component.ts +++ b/projects/account/src/app/modules/profile/components/views/support-step/support-step.component.ts @@ -2,8 +2,9 @@ import { Component, Input, OnInit } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { MatBottomSheet } from '@angular/material'; -import { MembershipType } from '../../../../../shared/models/membership.model'; -import { ProfileService } from '../../../../../core/http/profile.service'; +import { MembershipType } from '@account/models/membership.model'; +import { MembershipUpdate } from '@account/models/membership-update.model'; +import { ProfileService } from '@account/http/profile.service'; import { PaymentComponent } from '../payment/payment.component'; @Component({ @@ -17,9 +18,9 @@ export class SupportStepComponent implements OnInit { public openDatasetDescription: string[]; public membershipDescription: string[]; - constructor(public bottomSheet: MatBottomSheet, private profileService: ProfileService) { } + constructor() { } - ngOnInit() { + ngOnInit(): void { this.openDatasetDescription = [ 'Mycroft\'s voices and services can only improve with your help. ' + 'By joining our open dataset, you agree to allow Mycroft AI to collect data related ' + @@ -48,51 +49,21 @@ export class SupportStepComponent implements OnInit { ]; } - onOptIn() { + onOptIn(): void { this.newAcctForm.patchValue({support: {openDataset: true}}); } - onOptOut() { + onOptOut(): void { this.newAcctForm.patchValue({support: {openDataset: false}}); } - onMembershipSelection(membershipType: string) { - const selectedMembership = this.membershipTypes.find( - (membership) => membership.type === membershipType - ); - if (selectedMembership) { - this.openBottomSheet(selectedMembership.type); - } else { - this.newAcctForm.patchValue({support: {membership: null}}); - } - } - - openBottomSheet(selectedMembership: string) { - const bottomSheetConfig = { - data: {newAccount: true}, - disableClose: true, - restoreFocus: true - }; - const bottomSheetRef = this.bottomSheet.open(PaymentComponent, bottomSheetConfig); - bottomSheetRef.afterDismissed().subscribe( - (dismissValue) => { - if (dismissValue === 'cancel') { - this.profileService.selectedMembershipType.next('Maybe Later'); - } else { - this.updateNewAccountForm(selectedMembership, dismissValue); - } - } - ); - } - - updateNewAccountForm(selectedMembership: string, stripeToken: string) { - console.log(stripeToken); + updateNewAccountForm(membershipUpdate: MembershipUpdate): void { this.newAcctForm.patchValue( { support: { - membership: selectedMembership, - paymentMethod: 'Stripe', - paymentToken: stripeToken + membership: membershipUpdate.membershipType, + paymentMethod: membershipUpdate.paymentMethod, + paymentToken: membershipUpdate.paymentToken } } ); diff --git a/projects/account/src/app/shared/models/membership-update.model.ts b/projects/account/src/app/shared/models/membership-update.model.ts new file mode 100644 index 0000000..ec4eb57 --- /dev/null +++ b/projects/account/src/app/shared/models/membership-update.model.ts @@ -0,0 +1,6 @@ +export interface MembershipUpdate { + membershipType?: string; + newMembership: boolean; + paymentMethod?: string; + paymentToken?: string; +}