diff --git a/libs/cart/README.md b/libs/cart/README.md index 15dafb2406..9422559823 100644 --- a/libs/cart/README.md +++ b/libs/cart/README.md @@ -3,113 +3,23 @@ Building and maintaining a model and code for an ecommerce store is complex and provides clear interfaces, models, and factories for the frontend of an ecommerce store so that you don't have to. ## Installation -To install `@daffodil/cart` and its dependencies, use the following commands in the terminal. +To install `@daffodil/cart`, use the following commands in your terminal. Install with npm: ``` -npm install @daffodil/cart @daffodil/core @ngrx/store @ngrx/effects --save +npm install @daffodil/cart --save ``` Install with yarn: ``` -yarn add @daffodil/cart @daffodil/core @ngrx/store @ngrx/effects +yarn add @daffodil/cart ``` ## Getting started -`@daffodil/cart` includes multiple layers of functionality that build on each other. The models can be used on their own. The driver layers can be used with the models but also allow custom extensions to those models to be passed as generics. A state layer sits on top of the driver layer. Individual drivers can be overridden through driver injection tokens and custom extensions to models can be passed into the state layer's generics. +`@daffodil/cart` includes multiple layers of functionality that build on each other. The models can be used on their own. The recommended way to use Daffodil is with the state layer. -The recommended way to use Daffodil is with the state layer. - -- [State guide](/libs/cart/guides/state.md) -- [Drivers guide](/libs/cart/guides/drivers.md) -- [Extension guide](/libs/cart/guides/extension.md) - -## Usage - -### Interacting with platforms -Interacting with platforms through the [cart facade](/libs/cart/guides/state.md#using-the-facade) is the recommended method. - -It is possible to interact with platforms by directly calling the drivers. While this requires more work to integrate into components, it offers greater flexibility. See the [drivers guide](/libs/cart/guides/drivers.md) for more information. - -### Using routing guards -`@daffodil/cart` provides a number of routing guards to prevent access to certain pages until specific data becomes available. - -The following example illustrates using the `DaffShippingAddressGuard` to prevent accessing the shipping method page of checkout until a shipping address has been set. - -```ts -import { - DaffShippingAddressGuard, - DaffCartShippingAddressGuardRedirectUrl -} from '@daffodil/cart'; - -@NgModule({ - imports: [ - ..., - RouterModule.forRoot([ - { - path: 'checkout/shipping', - component: CheckoutShippingComponent, - canActivate: [DaffShippingAddressGuard] - }, - { - path: '', - component: HomepageComponent, - }, - ]) - ], - providers: [ - { - provide: DaffCartShippingAddressGuardRedirectUrl, - useValue: '/' - } - ] -}) -class AppModule {} -``` - -> The `'checkout/shipping'` route's activation was guarded with the `DaffShippingAddressGuard`, ensuring that page cannot be accessed unless the cart has a valid shipping address set. The `DaffCartShippingAddressGuardRedirectUrl` token is used to configure the path to which the user is redirected when and if the activation fails. - -### Providing platform-agnostic payment IDs -`DaffCartFacade` provides a field (`paymentId$`) for agnostic payment IDs. The IDs must be user-supplied to prevent circular package dependencies. Provide an object for the `DaffCartPaymentMethodIdMap` token. The keys of this object should be cart payment methods and the values should be strings. - -```ts -import { - DaffCartPaymentMethodIdMap, - DaffCartFacade, - DaffCartPaymentMethod -} from '@daffodil/cart'; - -@NgModule({ - ..., - providers: [ - { - provide: DaffCartPaymentMethodIdMap, - useValue: { - authorizenet_accept_js: 'authorizenet', - payflowpro: 'paypal' - } - } - ] -}) -class AppModule {} - -@Component({}) -class CartComponent implements OnInit { - paymentID$: Observable; - - constructor(private cartFacade: DaffCartFacade) {} - - ngOnInit() { - this.paymentID$ = this.cartFacade.paymentId$; - } - - setPayment(info) { - this.cartFacade.dispatch(new DaffCartPaymentUpdate({ - method: 'authorizenet_accept_js', - payment_info: info - })); - } -} -``` - -> When `setPayment` is called, the cart payment method will be updated. After this update is finished, the `this.paymentID$` stream will emit `'authorizenet'`. +| Layer | Description | +| -------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | +| [State](/libs/cart/guides/state.md) | Can be used with the models but also allow custom extensions to those models to be passed as generics | +| [Drivers](/libs/cart/guides/drivers.md) | Sits on top of the driver layer | +| [Extensions](/libs/cart/guides/extension.md) | Individual drivers can be overridden through driver injection tokens and custom extensions to models can be passed into the state layer's generics | diff --git a/libs/cart/guides/drivers.md b/libs/cart/guides/drivers.md index 3ababeae9f..18c93e0546 100644 --- a/libs/cart/guides/drivers.md +++ b/libs/cart/guides/drivers.md @@ -1,10 +1,8 @@ # Drivers `@daffodil/cart` can interface with supported platforms through drivers. Choose the driver that corresponds to the platform of choice and follow the linked guide to set it up. -## Supported drivers - -### In-memory web API -The in-memory driver is for rapid development without the need to set up a magento/shopify/etc backend. It will mock out the management of a cart and operate like a functional backend. It is intended for development and testing purposes and not meant to be used in production. +## In-memory web API +The in-memory driver is for rapid development without the need to set up a platform-specific backend. It will mock out the management of a cart and operate like a functional backend. It is intended for development and testing purposes and not meant to be used in production. To set up in the root component: 1. Import the `DaffCartInMemoryDriverModule` from `@daffodil/cart/testing` @@ -28,7 +26,7 @@ Now this `DaffCart` implementation will have access to the in-memory driver to u > Note: It is important to only have one `daffodil/cart` driver set up at a time in the root component. To set up a driver configuration to make switching between different backend drivers simple, follow the [advanced setup guide](). -### Magento +## Magento The Magento driver communicates with the Magento backend through the GraphQL API. To set up in the root component: @@ -53,7 +51,7 @@ This `DaffCart` implementation will now be able to interact with Magento. > Note: It is important to only have one `@daffodil/cart` driver set up in the root component at a time. To set up a driver configuration to make switching between different backend drivers simple, follow the [advanced setup guide](). -#### Fragment introspection +### Fragment introspection You should set up fragment introspection with the Magento backend. Refer to the [fragment introspection guide](../../../../tools/builders/guides/fragment-introspection.md) for more information. ## Usage diff --git a/libs/cart/guides/extension.md b/libs/cart/guides/extensions.md similarity index 99% rename from libs/cart/guides/extension.md rename to libs/cart/guides/extensions.md index f506c2eeb5..6f48d1b507 100644 --- a/libs/cart/guides/extension.md +++ b/libs/cart/guides/extensions.md @@ -1,4 +1,4 @@ -# Extension +# Extensions `@daffodil/cart` provides a number of extension mechanisms so that it can be customized to fit specific needs. ## Custom drivers diff --git a/libs/cart/guides/state.md b/libs/cart/guides/state.md index 3c899b9522..3d1a51470d 100644 --- a/libs/cart/guides/state.md +++ b/libs/cart/guides/state.md @@ -1,11 +1,14 @@ # State -`@daffodil/cart` provides a fully featured state library to streamline the management of an application's state as well as driver interaction. The facade is an abstraction that provides all the functionality needed for standard use. It is the recommended way to interact with the Daffodil state layer. +`@daffodil/cart` provides a fully featured state library to streamline the management of an application's state as well as driver interaction. + +## Overview +The facade is an abstraction that provides all the functionality needed for standard use. It's the recommended way to interact with the Daffodil state layer. ## Set up the root component -1. Import the `DaffCartStateModule` -2. Import `StoreModule.forRoot({})`, which will be relevant later on when using the redux and state management features `@daffodil/cart`. +1. Import the `DaffCartStateModule` in the root component. +2. Import `StoreModule.forRoot({})`. This will be relevant later on when using the redux and state management features of `@daffodil/cart`. -```typescript +```ts @ngModule({ imports:[ StoreModule.forRoot({}), @@ -33,9 +36,11 @@ Once the `DaffCartFacade` has been set up in the component, it can now be used t Additionally, the Daffodil cart facade provides three different loading states for each section of the cart: -- `mutating$` tracks when an update to a cart property is occurring. -- `resolving$` tracks when new data is being fetched but no updates are taking place. -- `loading$` emits `true` when either `mutating$` or `resolving$` is `true`. +| State | Description | +| ------------ | --------------------------------------------------------------------- | +| `mutating$` | Tracks when an update to a cart property is occurring | +| `resolving$` | Tracks when new data is being fetched but no updates are taking place | +| `loading$` | Emits `true` when either `mutating$` or `resolving$` is `true` | There is also overall `featureLoading$`, `featureMutating$`, and `featureResolving$` streams to track loading for any section of the cart. These can be used to enhance the application's UI. @@ -136,7 +141,7 @@ This tutorial will walk you through the cart resolution process, which is respon ### Supported scenarios At the moment, the following scenarios are handled by the `DaffResolvedCartGuard`. -> For customer cart support, use the [@daffodil/cart-customer](/libs/cart-customer/README.md) package. +> For customer cart support, use [@daffodil/cart-customer](/libs/cart-customer/README.md). - Generating a new cart when a user visits the application for the very first time. - Retrieving a previously existing cart for a user upon page reload. diff --git a/libs/cart/guides/testing.md b/libs/cart/guides/testing.md index 14f3261487..71cc8e642c 100644 --- a/libs/cart/guides/testing.md +++ b/libs/cart/guides/testing.md @@ -1,8 +1,8 @@ # Testing -`@daffodil/cart` provides a testing package accessible at `@daffodil/cart/testing`. This package provides model factories, facade mocks, and driver mocks to facilitate unit testing. +`@daffodil/cart` provides a testing package accessible at `@daffodil/cart/testing`. It provides model factories, facade mocks, and driver mocks to facilitate unit testing. ## Example -The following example demonstrates how to unit test a component using Daffodil model factories and the mock facade with the Jasmine testing framework and the `jasmine-marbles` library. +The following example demonstrates how to unit test a component using Daffodil model factories, the mock facade with the Jasmine testing framework, and the `jasmine-marbles` library. `cart.component.ts` ```ts diff --git a/libs/cart/guides/usage.md b/libs/cart/guides/usage.md new file mode 100644 index 0000000000..a82f405bd1 --- /dev/null +++ b/libs/cart/guides/usage.md @@ -0,0 +1,89 @@ +# Usage + +## Interacting with platforms +Interacting with platforms through the [cart facade](/libs/cart/guides/state.md#using-the-facade) is the recommended method. + +It is possible to interact with platforms by directly calling the drivers. While this requires more work to integrate into components, it offers greater flexibility. See the [drivers guide](/libs/cart/guides/drivers.md) for more information. + +## Using routing guards +`@daffodil/cart` provides a number of routing guards to prevent access to certain pages until specific data becomes available. + +The following example illustrates using the `DaffShippingAddressGuard` to prevent accessing the shipping method page of checkout until a shipping address has been set. + +```ts +import { + DaffShippingAddressGuard, + DaffCartShippingAddressGuardRedirectUrl +} from '@daffodil/cart'; + +@NgModule({ + imports: [ + ..., + RouterModule.forRoot([ + { + path: 'checkout/shipping', + component: CheckoutShippingComponent, + canActivate: [DaffShippingAddressGuard] + }, + { + path: '', + component: HomepageComponent, + }, + ]) + ], + providers: [ + { + provide: DaffCartShippingAddressGuardRedirectUrl, + useValue: '/' + } + ] +}) +class AppModule {} +``` + +> The `'checkout/shipping'` route's activation was guarded with the `DaffShippingAddressGuard`, ensuring that page cannot be accessed unless the cart has a valid shipping address set. The `DaffCartShippingAddressGuardRedirectUrl` token is used to configure the path to which the user is redirected when and if the activation fails. + +## Providing platform-agnostic payment IDs +`DaffCartFacade` provides a field (`paymentId$`) for agnostic payment IDs. The IDs must be user-supplied to prevent circular package dependencies. Provide an object for the `DaffCartPaymentMethodIdMap` token. The keys of this object should be cart payment methods and the values should be strings. + +```ts +import { + DaffCartPaymentMethodIdMap, + DaffCartFacade, + DaffCartPaymentMethod +} from '@daffodil/cart'; + +@NgModule({ + ..., + providers: [ + { + provide: DaffCartPaymentMethodIdMap, + useValue: { + authorizenet_accept_js: 'authorizenet', + payflowpro: 'paypal' + } + } + ] +}) +class AppModule {} + +@Component({}) +class CartComponent implements OnInit { + paymentID$: Observable; + + constructor(private cartFacade: DaffCartFacade) {} + + ngOnInit() { + this.paymentID$ = this.cartFacade.paymentId$; + } + + setPayment(info) { + this.cartFacade.dispatch(new DaffCartPaymentUpdate({ + method: 'authorizenet_accept_js', + payment_info: info + })); + } +} +``` + +> When `setPayment` is called, the cart payment method will be updated. After this update is finished, the `this.paymentID$` stream will emit `'authorizenet'`.