2 min read
Add promotions to cart items
This guide aims to present promotions driven by customData
on cart items.
Most backend contracts have an optional customData
property which allows custom backends to send additional data to the frontend. The PoqSDK is built to work with these backend contracts and easily allows you to map customData
to strongly typed objects using mappers.
For this guide we will use Containers to customise all instances of the Cart. However, it is possible to inject these customisations using a CartBuilder
for a specific instance of the Cart.
Before you begin
Make sure you know the format / contract that the customData
property will take as sent from your backend.
Decode your promotions
- Create a new file named
CartItemCustomData
in an appropriate location such asSources/Cart/Models
. - Implement the
CartItemCustomData
structure conforming toDecodable
andHashable
to match the agreed backend contract for thecustomData
.
struct CartItemCustomData: Hashable, Decodable { var promotion: String}
- Open your
AppModule
and navigate to thesetUpCart
function. - Inject and customise the
PoqCartItemDataMapper
by providing acustomDataMapper
closure.
Container.shared.mappers.cartItemDataMapper = { PoqCartItemDataMapper() { let custom: CartItemCustomData? = $0?.decode() return custom.flatMap(AnyHashable.init) }}
- Validate that your
CartItemDomainModel
objects contain your strongly typedcustomData
.
Check the console for decoding errors to validate your struct
matches the backend agreed customData
contract.
Create the cart item view
- Create a new file named
ClientCartItemView
in an appropriate location such asSources/Cart/Views
. - Implement the
ClientCartItemView
conforming toCartItemView
(or by subclassing thePoqClientItemView
). Make sure to include aUILabel
for promotion text. - Implement the
setup(with viewData: CartItemViewData)
as much as you can but leave the promotion label unset. We will come back to this later.
If you are subclassing a Poq
view, there are defined functions for addSubviews
, addConstraints
and style
. Use these to call super (or not) and modify the default views / constraints.
- Open your
AppModule
and navigate to thesetUpCart
function. - Inject your
ClientCartItemView
to replace the default.
Container.shared.views.cartItemView = { ClientCartItemView() }
Create the cart item view data
- Create a new file named
ClientCartItemViewData
in an appropriate location such asSources/Cart/ViewData
. - Implement the
ClientCartItemViewData
structure conforming to and satisfying theCartItemViewData
protocol. - Add your
promotion
string to the view data. - Conform to
Equatable
. You will need to manually implement it due toprice
andtotal
where you will need to use the following compare function.
&& ...&& lhs.quantity == rhs.quantity&& lhs.price.isEqual(to: rhs.price)&& lhs.total.isEqual(to: rhs.total)&& ...
- Head back to the
setup(with viewData: CartItemViewData)
function of yourClientCartItemView
and cast theviewData
to your newClientCartItemViewData
. Use this to set your promotion label.
func setup(with viewData: CartItemViewData?) { // Set up view without casting...
let clientData = viewData as? ClientCartItemViewData promotionLabel.text = clientData?.promotion}
Create the view data mapper to finish
- Create a new file named
ClientCartItemViewDataMapper
in an appropriate location such asSources/Cart/Mappers
- Implement the
ClientCartItemViewDataMapper
conforming toCartItemViewDataMapper
. You will need to create a property for apriceMapper
.
lazy var priceMapper = Container.shared.mappers.priceViewDataMapper()
- Create and return an instance of your
ClientCartItemViewData
in themap(from domain:)
function. - Map your
customData
by casting the value.
func map(from domain: CartItemDomainModel) -> CartItemViewData { let customData = domain.customData?.base as? CartItemCustomData return ClientCartItemViewData( ... quantity: domain.quantity, price: priceMapper.map(from: domain.price), total: priceMapper.map(from: domain.total), imageUrl: domain.thumbnailUrl, ... promotion: customData?.promotion )}
- Open your
AppModule
and navigate to thesetUpCart
function. - Inject your
ClientCartItemViewDataMapper
to replace the default.
Container.shared.mappers.cartItemViewDataMapper = { ClientCartItemViewDataMapper() }
You have completed this guide! Run your app and check out your new promotions!