From 16c6f1f1b0d8c35531cbeec64b1081208687e600 Mon Sep 17 00:00:00 2001 From: Danilo Hoffmann Date: Wed, 18 Dec 2019 16:46:43 +0100 Subject: [PATCH] feat: remove promotion from basket (#71) --- src/app/core/facades/checkout.facade.ts | 5 ++ .../services/basket/basket.service.spec.ts | 9 +++ .../core/services/basket/basket.service.ts | 11 +++ .../basket-promotion-code.effects.spec.ts | 71 +++++++++++++++++-- .../basket/basket-promotion-code.effects.ts | 25 +++++++ .../store/checkout/basket/basket.actions.ts | 20 ++++++ .../checkout/basket/basket.reducer.spec.ts | 32 +++++++++ .../store/checkout/basket/basket.reducer.ts | 3 + .../basket-promotion.component.html | 5 +- .../basket-promotion.component.spec.ts | 12 +++- .../promotion-remove.component.html | 6 ++ .../promotion-remove.component.spec.ts | 46 ++++++++++++ .../promotion-remove.component.ts | 27 +++++++ src/app/shared/shared.module.ts | 4 +- src/assets/i18n/de_DE.json | 2 + src/assets/i18n/en_US.json | 2 + src/assets/i18n/fr_FR.json | 2 + src/theme/global/promotions.scss | 13 ++++ 18 files changed, 287 insertions(+), 8 deletions(-) create mode 100644 src/app/shared/components/promotion/promotion-remove/promotion-remove.component.html create mode 100644 src/app/shared/components/promotion/promotion-remove/promotion-remove.component.spec.ts create mode 100644 src/app/shared/components/promotion/promotion-remove/promotion-remove.component.ts diff --git a/src/app/core/facades/checkout.facade.ts b/src/app/core/facades/checkout.facade.ts index 6d9f074eba..de90badb79 100644 --- a/src/app/core/facades/checkout.facade.ts +++ b/src/app/core/facades/checkout.facade.ts @@ -18,6 +18,7 @@ import { DeleteBasketShippingAddress, LoadBasketEligiblePaymentMethods, LoadBasketEligibleShippingMethods, + RemovePromotionCodeFromBasket, SetBasketPayment, UpdateBasketAddress, UpdateBasketItems, @@ -163,4 +164,8 @@ export class CheckoutFacade { addPromotionCodeToBasket(code: string) { this.store.dispatch(new AddPromotionCodeToBasket({ code })); } + + removePromotionCodeFromBasket(code: string) { + this.store.dispatch(new RemovePromotionCodeFromBasket({ code })); + } } diff --git a/src/app/core/services/basket/basket.service.spec.ts b/src/app/core/services/basket/basket.service.spec.ts index 0c00e1629a..080515a97c 100644 --- a/src/app/core/services/basket/basket.service.spec.ts +++ b/src/app/core/services/basket/basket.service.spec.ts @@ -199,6 +199,15 @@ describe('Basket Service', () => { }); }); + it("should remove a promotion code from a specific basket when 'removePromotionCodeFromBasket' is called", done => { + when(apiService.delete(anyString(), anything())).thenReturn(of({})); + + basketService.removePromotionCodeFromBasket(basketMockData.data.id, 'promoCode').subscribe(() => { + verify(apiService.delete(`baskets/${basketMockData.data.id}/promotioncodes/promoCode`, anything())).once(); + done(); + }); + }); + it("should create a basket address when 'createBasketAddress' is called", done => { when(apiService.post(anyString(), anything(), anything())).thenReturn(of({ data: {} as Address })); diff --git a/src/app/core/services/basket/basket.service.ts b/src/app/core/services/basket/basket.service.ts index 098bb9b091..13643c5a7c 100644 --- a/src/app/core/services/basket/basket.service.ts +++ b/src/app/core/services/basket/basket.service.ts @@ -299,6 +299,17 @@ export class BasketService { .pipe(map(({ infos }) => infos && infos[0] && infos[0].message)); } + /** + * Remove a promotion code from basket. + * @param basketId The id of the basket where the promotion code should be removed. + * @param codeStr The code string of the promotion code that should be removed from basket. + */ + removePromotionCodeFromBasket(basketId: string = 'current', codeStr: string): Observable { + return this.apiService.delete(`baskets/${basketId}/promotioncodes/${codeStr}`, { + headers: this.basketHeaders, + }); + } + /** * Updates specific line items (quantity/shipping method) for the given basket. * @param basketId The id of the basket in which the item should be updated. diff --git a/src/app/core/store/checkout/basket/basket-promotion-code.effects.spec.ts b/src/app/core/store/checkout/basket/basket-promotion-code.effects.spec.ts index 183de831af..88bfe60e49 100644 --- a/src/app/core/store/checkout/basket/basket-promotion-code.effects.spec.ts +++ b/src/app/core/store/checkout/basket/basket-promotion-code.effects.spec.ts @@ -45,6 +45,17 @@ describe('Basket Promotion Code Effects', () => { store$ = TestBed.get(Store); }); + describe('loadBasketAfterAddPromotionCodeToBasket$', () => { + it('should map to action of type LoadBasket if AddPromotionCodeToBasketSuccess action triggered', () => { + const action = new basketActions.AddPromotionCodeToBasketSuccess(); + const completion = new basketActions.LoadBasket(); + actions$ = hot('-a-a-a', { a: action }); + const expected$ = cold('-c-c-c', { c: completion }); + + expect(effects.loadBasketAfterAddPromotionCodeToBasketChangeSuccess$).toBeObservable(expected$); + }); + }); + describe('addPromotionCodeToBasket$', () => { beforeEach(() => { when(basketServiceMock.addPromotionCodeToBasket(anyString(), anyString())).thenReturn(of(undefined)); @@ -95,14 +106,66 @@ describe('Basket Promotion Code Effects', () => { }); }); - describe('loadBasketAfterAddPromotionCodeToBasket$', () => { - it('should map to action of type LoadBasket if AddPromotionCodeToBasketSuccess action triggered', () => { - const action = new basketActions.AddPromotionCodeToBasketSuccess(); + describe('removePromotionCodeFromBasket$', () => { + beforeEach(() => { + when(basketServiceMock.removePromotionCodeFromBasket(anyString(), anyString())).thenReturn(of(undefined)); + + store$.dispatch( + new basketActions.LoadBasketSuccess({ + basket: { + id: 'BID', + lineItems: [], + } as Basket, + }) + ); + }); + + it('should call the basketService for RemovePromotionCodeFromBasket action', done => { + const code = 'CODE'; + const action = new basketActions.RemovePromotionCodeFromBasket({ code }); + actions$ = of(action); + + effects.removePromotionCodeFromBasket$.subscribe(() => { + verify(basketServiceMock.removePromotionCodeFromBasket('BID', 'CODE')).once(); + done(); + }); + }); + + it('should map to action of type RemovePromotionCodeFromBasketSuccess', () => { + const code = 'CODE'; + const action = new basketActions.RemovePromotionCodeFromBasket({ code }); + const completion = new basketActions.RemovePromotionCodeFromBasketSuccess(); + actions$ = hot('-a-a-a', { a: action }); + const expected$ = cold('-c-c-c', { c: completion }); + + expect(effects.removePromotionCodeFromBasket$).toBeObservable(expected$); + }); + + it('should map invalid request to action of type RemovePromotionCodeFromBasketFail', () => { + when(basketServiceMock.removePromotionCodeFromBasket(anyString(), anyString())).thenReturn( + throwError({ message: 'invalid' }) + ); + + const code = 'CODE'; + const action = new basketActions.RemovePromotionCodeFromBasket({ code }); + const completion = new basketActions.RemovePromotionCodeFromBasketFail({ + error: { message: 'invalid' } as HttpError, + }); + actions$ = hot('-a-a-a', { a: action }); + const expected$ = cold('-c-c-c', { c: completion }); + + expect(effects.removePromotionCodeFromBasket$).toBeObservable(expected$); + }); + }); + + describe('loadBasketAfterRemovePromotionCodeFromBasket$', () => { + it('should map to action of type LoadBasket if RemovePromotionCodeFromBasketSuccess action triggered', () => { + const action = new basketActions.RemovePromotionCodeFromBasketSuccess(); const completion = new basketActions.LoadBasket(); actions$ = hot('-a-a-a', { a: action }); const expected$ = cold('-c-c-c', { c: completion }); - expect(effects.loadBasketAfterAddPromotionCodeToBasketChangeSuccess$).toBeObservable(expected$); + expect(effects.loadBasketAfterRemovePromotionCodeFromBasketChangeSuccess$).toBeObservable(expected$); }); }); }); diff --git a/src/app/core/store/checkout/basket/basket-promotion-code.effects.ts b/src/app/core/store/checkout/basket/basket-promotion-code.effects.ts index 23dfede8cb..0b8ffcee48 100644 --- a/src/app/core/store/checkout/basket/basket-promotion-code.effects.ts +++ b/src/app/core/store/checkout/basket/basket-promotion-code.effects.ts @@ -37,4 +37,29 @@ export class BasketPromotionCodeEffects { ofType(basketActions.BasketActionTypes.AddPromotionCodeToBasketSuccess), mapTo(new basketActions.LoadBasket()) ); + + /** + * Remove promotion code from the current basket. + */ + @Effect() + removePromotionCodeFromBasket$ = this.actions$.pipe( + ofType(basketActions.BasketActionTypes.RemovePromotionCodeFromBasket), + mapToPayloadProperty('code'), + withLatestFrom(this.store.pipe(select(getCurrentBasketId))), + concatMap(([code, basketId]) => + this.basketService.removePromotionCodeFromBasket(basketId, code).pipe( + mapTo(new basketActions.RemovePromotionCodeFromBasketSuccess()), + mapErrorToAction(basketActions.RemovePromotionCodeFromBasketFail) + ) + ) + ); + + /** + * Reload basket after successfully removing a promo code + */ + @Effect() + loadBasketAfterRemovePromotionCodeFromBasketChangeSuccess$ = this.actions$.pipe( + ofType(basketActions.BasketActionTypes.RemovePromotionCodeFromBasketSuccess), + mapTo(new basketActions.LoadBasket()) + ); } diff --git a/src/app/core/store/checkout/basket/basket.actions.ts b/src/app/core/store/checkout/basket/basket.actions.ts index 134189489e..c62c5ee7de 100644 --- a/src/app/core/store/checkout/basket/basket.actions.ts +++ b/src/app/core/store/checkout/basket/basket.actions.ts @@ -40,6 +40,9 @@ export enum BasketActionTypes { AddPromotionCodeToBasket = '[Basket Internal] Add Promotion Code To Basket', AddPromotionCodeToBasketFail = '[Basket API] Add Promotion Code To Basket Fail', AddPromotionCodeToBasketSuccess = '[Basket API] Add Promotion Code To Basket Success', + RemovePromotionCodeFromBasket = '[Basket Internal] Remove Promotion Code From Basket', + RemovePromotionCodeFromBasketFail = '[Basket API] Remove Promotion Code From Basket Fail', + RemovePromotionCodeFromBasketSuccess = '[Basket API] Remove Promotion Code From Basket Success', UpdateBasketItems = '[Basket] Update Basket Items', UpdateBasketItemsFail = '[Basket API] Update Basket Items Fail', UpdateBasketItemsSuccess = '[Basket API] Update Basket Items Success', @@ -218,6 +221,20 @@ export class DeleteBasketItemSuccess implements Action { constructor(public payload: { info: BasketInfo[] }) {} } +export class RemovePromotionCodeFromBasket implements Action { + readonly type = BasketActionTypes.RemovePromotionCodeFromBasket; + constructor(public payload: { code: string }) {} +} + +export class RemovePromotionCodeFromBasketFail implements Action { + readonly type = BasketActionTypes.RemovePromotionCodeFromBasketFail; + constructor(public payload: { error: HttpError }) {} +} + +export class RemovePromotionCodeFromBasketSuccess implements Action { + readonly type = BasketActionTypes.RemovePromotionCodeFromBasketSuccess; +} + export class AddPromotionCodeToBasket implements Action { readonly type = BasketActionTypes.AddPromotionCodeToBasket; constructor(public payload: { code: string }) {} @@ -351,6 +368,9 @@ export type BasketAction = | AddPromotionCodeToBasket | AddPromotionCodeToBasketFail | AddPromotionCodeToBasketSuccess + | RemovePromotionCodeFromBasket + | RemovePromotionCodeFromBasketFail + | RemovePromotionCodeFromBasketSuccess | UpdateBasketItems | UpdateBasketItemsFail | UpdateBasketItemsSuccess diff --git a/src/app/core/store/checkout/basket/basket.reducer.spec.ts b/src/app/core/store/checkout/basket/basket.reducer.spec.ts index 2a5fb3ea6a..4d526057df 100644 --- a/src/app/core/store/checkout/basket/basket.reducer.spec.ts +++ b/src/app/core/store/checkout/basket/basket.reducer.spec.ts @@ -309,6 +309,38 @@ describe('Basket Reducer', () => { }); }); + describe('RemovePromotionCodeFromBasket actions', () => { + describe('RemovePromotionCodeFromBasket action', () => { + it('should set loading to true', () => { + const action = new fromActions.RemovePromotionCodeFromBasket({ code: 'test' }); + const state = basketReducer(initialState, action); + + expect(state.loading).toBeTrue(); + }); + }); + + describe('RemovePromotionCodeFromBasketFail action', () => { + it('should set loading to false', () => { + const error = undefined as HttpError; + const action = new fromActions.RemovePromotionCodeFromBasketFail({ error }); + const state = basketReducer(initialState, action); + + expect(state.loading).toBeFalse(); + expect(state.promotionError).toEqual(error); + }); + }); + + describe('RemovePromotionCodeFromBasketSuccess action', () => { + it('should set loading to false', () => { + const action = new fromActions.RemovePromotionCodeFromBasketSuccess(); + const state = basketReducer(initialState, action); + + expect(state.loading).toBeFalse(); + expect(state.error).toBeUndefined(); + }); + }); + }); + describe('ResetBasket action', () => { it('should reset to initial state', () => { const oldState = { diff --git a/src/app/core/store/checkout/basket/basket.reducer.ts b/src/app/core/store/checkout/basket/basket.reducer.ts index 27678af2b4..bc80ae7f90 100644 --- a/src/app/core/store/checkout/basket/basket.reducer.ts +++ b/src/app/core/store/checkout/basket/basket.reducer.ts @@ -46,6 +46,7 @@ export function basketReducer(state = initialState, action: BasketAction | Order case BasketActionTypes.UpdateBasket: case BasketActionTypes.AddProductToBasket: case BasketActionTypes.AddPromotionCodeToBasket: + case BasketActionTypes.RemovePromotionCodeFromBasket: case BasketActionTypes.AddItemsToBasket: case BasketActionTypes.MergeBasket: case BasketActionTypes.ContinueCheckout: @@ -68,6 +69,7 @@ export function basketReducer(state = initialState, action: BasketAction | Order case BasketActionTypes.UpdateBasketFail: case BasketActionTypes.ContinueCheckoutFail: case BasketActionTypes.AddItemsToBasketFail: + case BasketActionTypes.RemovePromotionCodeFromBasketFail: case BasketActionTypes.UpdateBasketItemsFail: case BasketActionTypes.DeleteBasketItemFail: case BasketActionTypes.LoadBasketEligibleShippingMethodsFail: @@ -114,6 +116,7 @@ export function basketReducer(state = initialState, action: BasketAction | Order }; } + case BasketActionTypes.RemovePromotionCodeFromBasketSuccess: case BasketActionTypes.SetBasketPaymentSuccess: case BasketActionTypes.CreateBasketPaymentSuccess: case BasketActionTypes.UpdateBasketPaymentSuccess: diff --git a/src/app/shared/components/basket/basket-promotion/basket-promotion.component.html b/src/app/shared/components/basket/basket-promotion/basket-promotion.component.html index fb6805430a..59697bd386 100644 --- a/src/app/shared/components/basket/basket-promotion/basket-promotion.component.html +++ b/src/app/shared/components/basket/basket-promotion/basket-promotion.component.html @@ -1,6 +1,9 @@
- +
diff --git a/src/app/shared/components/basket/basket-promotion/basket-promotion.component.spec.ts b/src/app/shared/components/basket/basket-promotion/basket-promotion.component.spec.ts index 7141c06fd8..15d51c4694 100644 --- a/src/app/shared/components/basket/basket-promotion/basket-promotion.component.spec.ts +++ b/src/app/shared/components/basket/basket-promotion/basket-promotion.component.spec.ts @@ -11,6 +11,7 @@ import { BasketRebate } from 'ish-core/models/basket-rebate/basket-rebate.model' import { Promotion } from 'ish-core/models/promotion/promotion.model'; import { getICMBaseURL } from 'ish-core/store/configuration'; import { PromotionDetailsComponent } from 'ish-shared/components/promotion/promotion-details/promotion-details.component'; +import { PromotionRemoveComponent } from 'ish-shared/components/promotion/promotion-remove/promotion-remove.component'; import { BasketPromotionComponent } from './basket-promotion.component'; @@ -24,7 +25,12 @@ describe('Basket Promotion Component', () => { shoppingFacade = mock(ShoppingFacade); TestBed.configureTestingModule({ - declarations: [BasketPromotionComponent, MockComponent(PromotionDetailsComponent), ServerHtmlDirective], + declarations: [ + BasketPromotionComponent, + MockComponent(PromotionDetailsComponent), + MockComponent(PromotionRemoveComponent), + ServerHtmlDirective, + ], imports: [RouterTestingModule], providers: [ { provide: ShoppingFacade, useFactory: () => instance(shoppingFacade) }, @@ -64,7 +70,9 @@ describe('Basket Promotion Component', () => { expect(element).toMatchInlineSnapshot(`
MyPromotionTitle
- +
`); }); diff --git a/src/app/shared/components/promotion/promotion-remove/promotion-remove.component.html b/src/app/shared/components/promotion/promotion-remove/promotion-remove.component.html new file mode 100644 index 0000000000..f3509815ae --- /dev/null +++ b/src/app/shared/components/promotion/promotion-remove/promotion-remove.component.html @@ -0,0 +1,6 @@ + + | + {{ + 'promotion.removelink.text' | translate + }} + diff --git a/src/app/shared/components/promotion/promotion-remove/promotion-remove.component.spec.ts b/src/app/shared/components/promotion/promotion-remove/promotion-remove.component.spec.ts new file mode 100644 index 0000000000..26bc9e39b1 --- /dev/null +++ b/src/app/shared/components/promotion/promotion-remove/promotion-remove.component.spec.ts @@ -0,0 +1,46 @@ +import { ComponentFixture, TestBed, async } from '@angular/core/testing'; +import { TranslateModule } from '@ngx-translate/core'; +import { of } from 'rxjs'; +import { instance, mock, when } from 'ts-mockito'; + +import { CheckoutFacade } from 'ish-core/facades/checkout.facade'; +import { BasketView } from 'ish-core/models/basket/basket.model'; + +import { PromotionRemoveComponent } from './promotion-remove.component'; + +describe('Promotion Remove Component', () => { + let component: PromotionRemoveComponent; + let fixture: ComponentFixture; + let element: HTMLElement; + let checkoutFacade: CheckoutFacade; + + beforeEach(async(() => { + checkoutFacade = mock(CheckoutFacade); + when(checkoutFacade.basket$).thenReturn(of({} as BasketView)); + + TestBed.configureTestingModule({ + declarations: [PromotionRemoveComponent], + imports: [TranslateModule.forRoot()], + providers: [{ provide: CheckoutFacade, useFactory: () => instance(checkoutFacade) }], + }).compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(PromotionRemoveComponent); + component = fixture.componentInstance; + element = fixture.nativeElement; + component.code = 'test'; + }); + + it('should be created', () => { + expect(component).toBeTruthy(); + expect(element).toBeTruthy(); + expect(() => fixture.detectChanges()).not.toThrow(); + }); + + it('should display the link and input field on component', () => { + expect(() => fixture.detectChanges()).not.toThrow(); + + expect(element.querySelector('[data-testing-id=promo-remove-link]')).toBeTruthy(); + }); +}); diff --git a/src/app/shared/components/promotion/promotion-remove/promotion-remove.component.ts b/src/app/shared/components/promotion/promotion-remove/promotion-remove.component.ts new file mode 100644 index 0000000000..a6b16cae8e --- /dev/null +++ b/src/app/shared/components/promotion/promotion-remove/promotion-remove.component.ts @@ -0,0 +1,27 @@ +import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; +import { Observable } from 'rxjs'; + +import { CheckoutFacade } from 'ish-core/facades/checkout.facade'; +import { BasketView } from 'ish-core/models/basket/basket.model'; + +@Component({ + selector: 'ish-promotion-remove', + templateUrl: './promotion-remove.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +// tslint:disable-next-line: ccp-no-intelligence-in-components +export class PromotionRemoveComponent implements OnInit { + basket$: Observable; + + @Input() code: string; + + constructor(private checkoutFacade: CheckoutFacade) {} + + ngOnInit() { + this.basket$ = this.checkoutFacade.basket$; + } + + removePromotion() { + this.checkoutFacade.removePromotionCodeFromBasket(this.code); + } +} diff --git a/src/app/shared/shared.module.ts b/src/app/shared/shared.module.ts index b888be690f..f566eb2656 100644 --- a/src/app/shared/shared.module.ts +++ b/src/app/shared/shared.module.ts @@ -97,6 +97,7 @@ import { ProductTileComponent } from './components/product/product-tile/product- import { ProductVariationDisplayComponent } from './components/product/product-variation-display/product-variation-display.component'; import { ProductVariationSelectComponent } from './components/product/product-variation-select/product-variation-select.component'; import { PromotionDetailsComponent } from './components/promotion/promotion-details/promotion-details.component'; +import { PromotionRemoveComponent } from './components/promotion/promotion-remove/promotion-remove.component'; import { RecentlyViewedComponent } from './components/recently/recently-viewed/recently-viewed.component'; import { FormsDynamicModule } from './forms-dynamic/forms-dynamic.module'; import { FormsSharedModule } from './forms/forms.module'; @@ -205,12 +206,13 @@ const exportedComponents = [ ProductVariationDisplayComponent, ProductVariationSelectComponent, PromotionDetailsComponent, + PromotionRemoveComponent, RecentlyViewedComponent, ]; @NgModule({ imports: [...importExportModules], - declarations: [...declaredComponents, ...exportedComponents], + declarations: [...declaredComponents, ...exportedComponents, PromotionRemoveComponent], exports: [...exportedComponents, ...importExportModules], entryComponents: [ CMSCarouselComponent, diff --git a/src/assets/i18n/de_DE.json b/src/assets/i18n/de_DE.json index 0e4ed45ce5..4722b9cb79 100644 --- a/src/assets/i18n/de_DE.json +++ b/src/assets/i18n/de_DE.json @@ -2047,6 +2047,8 @@ "promotion.detaillist.title": "Angewendete Aktion", "promotion.detailslink.label": "Aktionsdetails", "promotion.detailslink.text": "Details", + "promotion.removelink.label": "Aktion entfernen", + "promotion.removelink.text": "Entfernen", "promotion.status.applied": "verwendet", "promotion.status.notapplied": "nicht verwendet", "promotion.viewEligibleItemsLink": "Wählbare Artikel anzeigen", diff --git a/src/assets/i18n/en_US.json b/src/assets/i18n/en_US.json index 7555b7552b..fcf2d134d5 100644 --- a/src/assets/i18n/en_US.json +++ b/src/assets/i18n/en_US.json @@ -2047,6 +2047,8 @@ "promotion.detaillist.title": "Applied Promotion", "promotion.detailslink.label": "Promotion Details", "promotion.detailslink.text": "Details", + "promotion.removelink.label": "Remove Promotion", + "promotion.removelink.text": "Remove", "promotion.status.applied": "applied", "promotion.status.notapplied": "not applied", "promotion.viewEligibleItemsLink": "View Eligible Items", diff --git a/src/assets/i18n/fr_FR.json b/src/assets/i18n/fr_FR.json index 12594f8c53..108f5aa995 100644 --- a/src/assets/i18n/fr_FR.json +++ b/src/assets/i18n/fr_FR.json @@ -1967,6 +1967,8 @@ "promotion.status.applied": "appliqué", "promotion.detailslink.text": "Détails", "promotion.status.notapplied": "non appliqué", + "promotion.removelink.label": "Supprimer promotion", + "promotion.removelink.text": "Supprimer", "promotion.viewEligibleItemsLink": "Afficher les articles eligibles", "rest.account.product.notification.email.error": "erreur.e-mail.de.notification.de.produits.nonvalide", "rest.account.product.notification.price.error": "erreur.prix.de.notification.de.produits.nonvalide", diff --git a/src/theme/global/promotions.scss b/src/theme/global/promotions.scss index 0753a31e96..109ade77bd 100644 --- a/src/theme/global/promotions.scss +++ b/src/theme/global/promotions.scss @@ -30,10 +30,23 @@ padding-right: $space-default/2; } +.promotion-details-and-remove-links { + white-space: nowrap; +} + .promotion-details-link { padding-left: 0; } +.promotion-links-seperator { + padding-right: 7.5px; + padding-left: 7.5px; +} + +.promotion-remove-link { + padding-left: 0; +} + .modal-body { .product-info { .promotion-list {