From 122ade9e89c8f4cc745d7d7dc48aff48702825bc Mon Sep 17 00:00:00 2001 From: sarthakjdev Date: Wed, 5 Jun 2024 21:53:55 +0530 Subject: [PATCH] fix: bifurcate product and product list message into more smaller components and add documentation for the same Signed-off-by: sarthakjdev --- .../building-message-components.mdx | 30 +- .../using-typescript.mdx | 0 .../js.wapikit.com/guide/wapijs-sdk-scope.mdx | 6 +- apps/js.wapikit.com/mint.json | 3 +- packages/example-chat-bot/src/index.ts | 5 +- packages/wapi.js/src/structures/index.ts | 17 ++ .../src/structures/interaction/index.ts | 269 +----------------- .../src/structures/interaction/interface.ts | 32 +-- .../src/structures/multi-product/index.ts | 190 +++++++++++++ .../src/structures/multi-product/interface.ts | 27 ++ .../wapi.js/src/structures/order/index.ts | 19 +- .../wapi.js/src/structures/order/interface.ts | 10 +- .../wapi.js/src/structures/product/index.ts | 137 +++++++++ .../src/structures/product/interface.ts | 14 + packages/wapi.js/src/webhook/index.ts | 4 +- 15 files changed, 440 insertions(+), 323 deletions(-) delete mode 100644 apps/js.wapikit.com/guide/installation-and-preparations/using-typescript.mdx create mode 100644 packages/wapi.js/src/structures/multi-product/index.ts create mode 100644 packages/wapi.js/src/structures/multi-product/interface.ts create mode 100644 packages/wapi.js/src/structures/product/index.ts create mode 100644 packages/wapi.js/src/structures/product/interface.ts diff --git a/apps/js.wapikit.com/guide/building-your-application/building-message-components.mdx b/apps/js.wapikit.com/guide/building-your-application/building-message-components.mdx index 1e23249..1099829 100644 --- a/apps/js.wapikit.com/guide/building-your-application/building-message-components.mdx +++ b/apps/js.wapikit.com/guide/building-your-application/building-message-components.mdx @@ -221,7 +221,14 @@ const buttonMessage = new ButtonInteractionMessage({ Product message is a message component that you can use to send a product to a user. You can create a product message using the following code: ```typescript - +import { ProductMessage } from '@wapijs/wapi.js' +const productMessage = new ProductMessage({ + bodyText: 'Hii, I am a product.', + buttonText: 'Buy', + catalogId: '123', + productRetailerId: '123', + footerText: 'Beta version', +}) ``` ### Product List Message @@ -229,6 +236,27 @@ Product message is a message component that you can use to send a product to a u Product List message is a message component that you can use to send a list of products to a user. You can create a product list message using the following code: ```typescript +import { ProductListMessage, ProductListSection, Product, HeaderTypeEnum } from '@wapijs/wapi.js' +const productListMessage = new ProductListMessage({ + bodyText: 'Welcome to Wapi.js', + buttonText: 'Buy', + footerText: 'Beta version', + catalogId: '123', + productRetailerId: '123', + header: { + text: 'Products', + type: HeaderTypeEnum.Text + }, + sections: [ + new ProductListSection([new Product('123')], 'Section 1'), + ] + }) + + const section = new ProductListSection([], 'Section 2') + + section.addProduct(new Product('123')) + + productListMessage.addSection(section) ``` ### Temaplate Message diff --git a/apps/js.wapikit.com/guide/installation-and-preparations/using-typescript.mdx b/apps/js.wapikit.com/guide/installation-and-preparations/using-typescript.mdx deleted file mode 100644 index e69de29..0000000 diff --git a/apps/js.wapikit.com/guide/wapijs-sdk-scope.mdx b/apps/js.wapikit.com/guide/wapijs-sdk-scope.mdx index e333cda..fba2f63 100644 --- a/apps/js.wapikit.com/guide/wapijs-sdk-scope.mdx +++ b/apps/js.wapikit.com/guide/wapijs-sdk-scope.mdx @@ -11,7 +11,7 @@ title: Scope of Wapi.js SDK ## Upcoming Features - Support for WhatsApp Business Account Management API -- Support for Interactive Address Message -- Support for Business Management API +- Support for [Interactive Address Message](https://developers.facebook.com/docs/whatsapp/cloud-api/messages/address-messages) - Support for WhatsApp Paymnent API -- Support for WhatsApp Order Mangement \ No newline at end of file +- Support for WhatsApp Order Mangement +- Support for [Interactive Location Message](https://developers.facebook.com/docs/whatsapp/cloud-api/guides/send-messages/location-request-messages) \ No newline at end of file diff --git a/apps/js.wapikit.com/mint.json b/apps/js.wapikit.com/mint.json index 0cf71c4..35aff23 100644 --- a/apps/js.wapikit.com/mint.json +++ b/apps/js.wapikit.com/mint.json @@ -71,8 +71,7 @@ "group": "Installation and Preparations", "pages": [ "guide/installation-and-preparations/setup-node", - "guide/installation-and-preparations/creating-application", - "guide/installation-and-preparations/using-typescript" + "guide/installation-and-preparations/creating-application" ] }, { diff --git a/packages/example-chat-bot/src/index.ts b/packages/example-chat-bot/src/index.ts index 6a89f63..e655751 100644 --- a/packages/example-chat-bot/src/index.ts +++ b/packages/example-chat-bot/src/index.ts @@ -1,5 +1,6 @@ import { whatsappClient } from './utils/client' -import { ButtonInteractionMessage, ListInteractionMessage, TextMessage } from '@wapijs/wapi.js' +import { ButtonInteractionMessage, ListInteractionMessage, Product, ProductListMessage, ProductListSection, ProductMessage, TextMessage } from '@wapijs/wapi.js' +import { HeaderTypeEnum } from '@wapijs/wapi.js/dist/cjs/src/structures/interaction/schema' function init() { whatsappClient.on('Ready', () => { @@ -97,8 +98,6 @@ function init() { } }) - - whatsappClient.on('ListInteraction', async message => { console.log('List Interaction', message) diff --git a/packages/wapi.js/src/structures/index.ts b/packages/wapi.js/src/structures/index.ts index 03a006e..991e264 100644 --- a/packages/wapi.js/src/structures/index.ts +++ b/packages/wapi.js/src/structures/index.ts @@ -4,12 +4,29 @@ export * from "./text/interface"; export * from "./interaction/index"; export * from "./interaction/interface"; +export * from "./product/index"; +export * from "./product/interface"; + +export * from "./multi-product/index"; +export * from "./multi-product/interface"; + export * from "./location/index"; export * from "./location/interface"; + export * from "./contact/index"; +export * from "./contact/interface"; export * from "./media/index"; export * from "./media/interface"; export * from "./reaction/index"; export * from "./reaction/interface"; + +export * from "./reaction/index"; +export * from "./reaction/interface"; + +export * from "./reaction/index"; +export * from "./reaction/interface"; + +export * from "./template/index"; +export * from "./template/interface"; \ No newline at end of file diff --git a/packages/wapi.js/src/structures/interaction/index.ts b/packages/wapi.js/src/structures/interaction/index.ts index 9e227c4..acb0716 100644 --- a/packages/wapi.js/src/structures/interaction/index.ts +++ b/packages/wapi.js/src/structures/interaction/index.ts @@ -4,8 +4,6 @@ import { InteractiveMessageTypeEnum, type InteractiveMessageInterface, type ListInteractionMessageInterface, - type ProductInteractionMessageInterface, - type ProductListInteractionMessageInterface, } from "./interface"; import { MessageTypeEnum } from "../message/types"; import { BaseMessage } from "../message"; @@ -14,9 +12,6 @@ import { type ButtonInteractiveMessagePayload, type ListInteractiveMessagePayload, ListInteractiveMessageSection, - type ProductInteractiveMessagePayload, - type ProductListInteractiveMessageSection, - type ProductListInteractiveMessagePayload, } from "../../api-request-payload-schema"; import { HeaderTypeEnum, @@ -29,7 +24,7 @@ import { * @implements {InteractiveMessageInterface} * @abstract */ -abstract class InteractiveMessage +export abstract class InteractiveMessage extends BaseMessage implements InteractiveMessageInterface { @@ -323,266 +318,4 @@ export class ListInteractionMessage } } -/** - * Represents a product interaction message. - * @extends {InteractiveMessage} - * @implements {ProductInteractionMessageInterface} - * @class - */ -export class ProductInteractionMessage - extends InteractiveMessage - implements ProductInteractionMessageInterface -{ - data: { - catalogId: string; - productRetailerId: string; - }; - - /** - * Creates an instance of ProductInteractionMessage. - * @constructor - * @memberof ProductInteractionMessage - * @param {Object} params - The parameters for creating the product interaction message. - * @param {string} params.buttonText - The button text of the message. - * @param {string} [params.footerText] - The footer text of the message. - * @param {string} params.bodyText - The body text of the message. - * @param {string} params.catalogId - The catalog ID of the product. - * @param {string} params.productRetailerId - The product retailer ID of the product. - */ - constructor(params: { - buttonText: string; - footerText?: string; - bodyText: string; - catalogId: string; - productRetailerId: string; - }) { - super({ - type: InteractiveMessageTypeEnum.Button, - footerText: params.footerText, - bodyText: params.bodyText, - }); - this.data = { - catalogId: params.catalogId, - productRetailerId: params.productRetailerId, - }; - } - - /** - * Adds a header to the message. - */ - addHeader() {} - - /** - * Adds a footer to the message. - * @param {string} footerText - The footer text to be added. - */ - addFooter(footerText: string) { - this.interactiveMessageData.footerText = footerText; - } - - /** - * Converts the message to JSON format. - * @memberof ProductInteractionMessage - * @param {Object} params - The parameters for converting the message to JSON. - * @param {string} params.to - The recipient of the message. - * @param {string} [params.replyToMessageId] - The ID of the message to reply to. - * @returns {Object} The JSON representation of the message. - */ - toJson(params: { to: string; replyToMessageId?: string }): z.infer< - typeof InteractiveMessageApiPayloadSchemaType - > & { - interactive: z.infer; - } { - return { - ...(params.replyToMessageId - ? { context: { message_id: params.replyToMessageId } } - : {}), - to: params.to, - messaging_product: "whatsapp", - recipient_type: "individual", - type: MessageTypeEnum.Interactive, - interactive: { - type: InteractiveMessageTypeEnum.Product, - action: { - catalogId: this.data.catalogId, - productRetailerId: this.data.productRetailerId, - }, - body: { - text: this.interactiveMessageData.bodyText, - }, - ...(this.interactiveMessageData.header - ? { - header: { - ...(this.interactiveMessageData.header.type === - HeaderTypeEnum.Text - ? { - type: HeaderTypeEnum.Text, - text: this.interactiveMessageData.header.text, - } - : this.interactiveMessageData.header.type === - HeaderTypeEnum.Document - ? { - type: HeaderTypeEnum.Document, - document: this.interactiveMessageData.header.document, - } - : this.interactiveMessageData.header.type === - HeaderTypeEnum.Image - ? { - type: HeaderTypeEnum.Image, - image: this.interactiveMessageData.header.image, - } - : { - type: HeaderTypeEnum.Video, - video: this.interactiveMessageData.header.video, - }), - }, - } - : {}), - ...(this.interactiveMessageData.footerText - ? { - footer: { - text: this.interactiveMessageData.footerText, - }, - } - : {}), - }, - }; - } -} - -/** - * Represents a product list interaction message. - * @class - * @extends {InteractiveMessage} - * @implements {ProductListInteractionMessageInterface} - */ -export class ProductListInteractionMessage - extends InteractiveMessage - implements ProductListInteractionMessageInterface -{ - data: { - catalogId: string; - productRetailerId: string; - sections: z.infer[]; - }; - - /** - * Creates an instance of ProductListInteractionMessage. - * @constructor - * @memberof ProductListInteractionMessage - * @param {Object} params - The parameters for creating the product list interaction message. - * @param {string} params.buttonText - The button text of the message. - * @param {string} [params.footerText] - The footer text of the message. - * @param {string} params.bodyText - The body text of the message. - * @param {string} params.catalogId - The catalog ID of the product. - * @param {string} params.productRetailerId - The product retailer ID of the product. - * @param {Array} params.sections - The sections of the message. - * @param {Object} params.header - The header of the message. - */ - constructor(params: { - buttonText: string; - footerText?: string; - bodyText: string; - catalogId: string; - productRetailerId: string; - sections: z.infer[]; - header: z.infer; - }) { - super({ - type: InteractiveMessageTypeEnum.Button, - footerText: params.footerText, - bodyText: params.bodyText, - }); - this.data = { - catalogId: params.catalogId, - productRetailerId: params.productRetailerId, - sections: params.sections, - }; - } - - /** - * Adds a section to the message - * @memberof ProductListInteractionMessage - * @param {Object} section - The section to be added. - */ - addSection(section: z.infer) { - this.data.sections.push(section); - } - - /** - * Adds a footer to the message. - * @param {string} footerText - The footer text to be added. - */ - addFooter(footerText: string) { - this.interactiveMessageData.footerText = footerText; - } - - /** - * Converts the message to JSON format. - * @memberof ProductListInteractionMessage - * @param {Object} params - The parameters for converting the message to JSON. - * @param {string} params.to - The recipient of the message. - * @param {string} [params.replyToMessageId] - The ID of the message to reply to. - * @returns {Object} The JSON representation of the message. - */ - toJson(params: { to: string; replyToMessageId?: string }): z.infer< - typeof InteractiveMessageApiPayloadSchemaType - > & { - interactive: z.infer; - } { - if (!this.interactiveMessageData.header) - throw new Error("Header is required for ProductListInteractiveMessage"); - - return { - ...(params.replyToMessageId - ? { context: { message_id: params.replyToMessageId } } - : {}), - to: params.to, - messaging_product: "whatsapp", - recipient_type: "individual", - type: MessageTypeEnum.Interactive, - interactive: { - type: InteractiveMessageTypeEnum.ProductList, - action: { - catalogId: this.data.catalogId, - productRetailerId: this.data.productRetailerId, - sections: this.data.sections, - }, - header: { - ...(this.interactiveMessageData.header.type === HeaderTypeEnum.Text - ? { - type: HeaderTypeEnum.Text, - text: this.interactiveMessageData.header.text, - } - : this.interactiveMessageData.header.type === - HeaderTypeEnum.Document - ? { - type: HeaderTypeEnum.Document, - document: this.interactiveMessageData.header.document, - } - : this.interactiveMessageData.header.type === HeaderTypeEnum.Image - ? { - type: HeaderTypeEnum.Image, - image: this.interactiveMessageData.header.image, - } - : { - type: HeaderTypeEnum.Video, - video: this.interactiveMessageData.header.video, - }), - }, - body: { - text: this.interactiveMessageData.bodyText, - }, - ...(this.interactiveMessageData.footerText - ? { - footer: { - text: this.interactiveMessageData.footerText, - }, - } - : {}), - }, - }; - } -} - // ! TODO: flow interactions diff --git a/packages/wapi.js/src/structures/interaction/interface.ts b/packages/wapi.js/src/structures/interaction/interface.ts index d177c9c..ae48fff 100644 --- a/packages/wapi.js/src/structures/interaction/interface.ts +++ b/packages/wapi.js/src/structures/interaction/interface.ts @@ -1,9 +1,6 @@ import { type z } from "zod"; import { type BaseMessageInterface } from "../message/interface"; -import { - type ProductListInteractiveMessageSection, - type ListInteractiveMessageSection, -} from "../../api-request-payload-schema"; +import { type ListInteractiveMessageSection } from "../../api-request-payload-schema"; /** * Represents the interface for an interactive message. @@ -43,33 +40,6 @@ export interface ListInteractionMessageInterface }; } -/** - * Represents the interface for a product interaction message. - * @interface - * @extends {InteractiveMessageInterface} - */ -export interface ProductInteractionMessageInterface - extends InteractiveMessageInterface { - data: { - catalogId: string; - productRetailerId: string; - }; -} - -/** - * Represents the interface for a product list interaction message. - * @interface - * @extends {InteractiveMessageInterface} - */ -export interface ProductListInteractionMessageInterface - extends InteractiveMessageInterface { - data: { - catalogId: string; - productRetailerId: string; - sections: z.infer[]; - }; -} - /** * Represents the enum for interactive message types. * @enum {string} diff --git a/packages/wapi.js/src/structures/multi-product/index.ts b/packages/wapi.js/src/structures/multi-product/index.ts new file mode 100644 index 0000000..14c8584 --- /dev/null +++ b/packages/wapi.js/src/structures/multi-product/index.ts @@ -0,0 +1,190 @@ +import type { z } from "zod"; +import type { + InteractiveMessageApiPayloadSchemaType, + ProductListInteractiveMessagePayload, +} from "../../api-request-payload-schema"; +import { InteractiveMessage } from "../interaction"; +import type { + ProductInterface, + ProductListMessageInterface, + ProductListSectionInterface, +} from "./interface"; +import { + HeaderTypeEnum, + type InteractiveMessageHeaderSchemaType, +} from "../interaction/schema"; +import { InteractiveMessageTypeEnum } from "../interaction/interface"; +import { MessageTypeEnum } from "../message/types"; + +/** + * Represents a product. + * @class + * @implements {ProductInterface} + */ +export class Product implements ProductInterface { + retailerId: string; + constructor(retailerId: string) { + this.retailerId = retailerId; + } +} + +/** + * Represents a product list section. + * @class + * @implements {ProductListSectionInterface} + */ +export class ProductListSection implements ProductListSectionInterface { + products: Product[]; + title: string; + + constructor(products: Product[], title: string) { + this.products = products; + this.title = title; + } + + addProduct(product: Product): void { + this.products.push(product); + } +} + +/** + * Represents a product list interaction message. + * @class + * @extends {InteractiveMessage} + * @implements {ProductListMessageInterface} + */ +export class ProductListMessage + extends InteractiveMessage + implements ProductListMessageInterface { + data: { + catalogId: string; + productRetailerId: string; + sections: ProductListSection[]; + }; + + /** + * Creates an instance of ProductListInteractionMessage. + * @constructor + * @memberof ProductListInteractionMessage + * @param {Object} params - The parameters for creating the product list interaction message. + * @param {string} params.buttonText - The button text of the message. + * @param {string} [params.footerText] - The footer text of the message. + * @param {string} params.bodyText - The body text of the message. + * @param {string} params.catalogId - The catalog ID of the product. + * @param {string} params.productRetailerId - The product retailer ID of the product. + * @param {ProductListSection[]} params.sections - The sections of the product list. + * @param {Object} params.header - The header of the message. + */ + constructor(params: { + buttonText: string; + footerText?: string; + bodyText: string; + catalogId: string; + productRetailerId: string; + sections: ProductListSection[]; + header: z.infer; + }) { + super({ + type: InteractiveMessageTypeEnum.Button, + footerText: params.footerText, + bodyText: params.bodyText, + }); + this.data = { + catalogId: params.catalogId, + productRetailerId: params.productRetailerId, + sections: params.sections, + }; + } + + /** + * Adds a section to the message. + * @param {ProductListSection} section - The section to be added. + */ + addSection(section: ProductListSection) { + this.data.sections.push(section); + } + + /** + * Adds a footer to the message. + * @param {string} footerText - The footer text to be added. + */ + addFooter(footerText: string) { + this.interactiveMessageData.footerText = footerText; + } + + /** + * Converts the message to JSON format. + * @memberof ProductListInteractionMessage + * @param {Object} params - The parameters for converting the message to JSON. + * @param {string} params.to - The recipient of the message. + * @param {string} [params.replyToMessageId] - The ID of the message to reply to. + * @returns {Object} The JSON representation of the message. + */ + toJson(params: { to: string; replyToMessageId?: string }): z.infer< + typeof InteractiveMessageApiPayloadSchemaType + > & { + interactive: z.infer; + } { + if (!this.interactiveMessageData.header) + throw new Error("Header is required for ProductListInteractiveMessage"); + + return { + ...(params.replyToMessageId + ? { context: { message_id: params.replyToMessageId } } + : {}), + to: params.to, + messaging_product: "whatsapp", + recipient_type: "individual", + type: MessageTypeEnum.Interactive, + interactive: { + type: InteractiveMessageTypeEnum.ProductList, + action: { + catalogId: this.data.catalogId, + productRetailerId: this.data.productRetailerId, + sections: this.data.sections.map((section) => { + return { + product_items: section.products.map((product) => { + return { + product_retailer_id: product.retailerId, + }; + }), + title: section.title, + }; + }), + }, + header: { + ...(this.interactiveMessageData.header.type === HeaderTypeEnum.Text + ? { + type: HeaderTypeEnum.Text, + text: this.interactiveMessageData.header.text, + } + : this.interactiveMessageData.header.type === + HeaderTypeEnum.Document + ? { + type: HeaderTypeEnum.Document, + document: this.interactiveMessageData.header.document, + } + : this.interactiveMessageData.header.type === HeaderTypeEnum.Image + ? { + type: HeaderTypeEnum.Image, + image: this.interactiveMessageData.header.image, + } + : { + type: HeaderTypeEnum.Video, + video: this.interactiveMessageData.header.video, + }), + }, + body: { + text: this.interactiveMessageData.bodyText, + }, + ...(this.interactiveMessageData.footerText + ? { + footer: { + text: this.interactiveMessageData.footerText, + }, + } + : {}), + }, + }; + } +} diff --git a/packages/wapi.js/src/structures/multi-product/interface.ts b/packages/wapi.js/src/structures/multi-product/interface.ts new file mode 100644 index 0000000..497e50b --- /dev/null +++ b/packages/wapi.js/src/structures/multi-product/interface.ts @@ -0,0 +1,27 @@ +import { type InteractiveMessageInterface } from "../interaction/interface"; +import type { Product, ProductListSection } from "."; + +export interface ProductListSectionInterface { + products: Product[]; + title: string; + addProduct(product: Product): void; +} + +export interface ProductInterface { + retailerId: string; +} + +/** + * Represents the interface for a product list interaction message. + * @interface + * @extends {InteractiveMessageInterface} + */ +export interface ProductListMessageInterface + extends InteractiveMessageInterface { + data: { + catalogId: string; + productRetailerId: string; + sections: ProductListSection[]; + }; + addSection(section: ProductListSection): void; +} diff --git a/packages/wapi.js/src/structures/order/index.ts b/packages/wapi.js/src/structures/order/index.ts index 2ff980d..92f388b 100644 --- a/packages/wapi.js/src/structures/order/index.ts +++ b/packages/wapi.js/src/structures/order/index.ts @@ -1,4 +1,7 @@ -import { type ProductItemInterface, type OrderInterface } from "./interface"; +import { + type OrderedProductItemInterface as OrderedProductItemInterface, + type OrderInterface, +} from "./interface"; /** * Represents an order. @@ -7,19 +10,19 @@ import { type ProductItemInterface, type OrderInterface } from "./interface"; */ export class Order implements OrderInterface { catalogId: string; - productItems: ProductItem[]; + productItems: OrderedProductItem[]; text: string; /** * Creates a new Order instance. * @param {Object} params - The parameters for creating an Order. * @param {string} params.catalogId - The catalog ID of the order. - * @param {ProductItem[]} params.productItems - The product items in the order. + * @param {OrderedProductItem[]} params.productItems - The product items in the order. * @param {string} params.text - The text associated with the order. */ constructor(params: { catalogId: string; - productItems: ProductItem[]; + productItems: OrderedProductItem[]; text: string; }) { this.productItems = params.productItems; @@ -29,9 +32,9 @@ export class Order implements OrderInterface { /** * Adds a product item to the order. - * @param {ProductItem} product - The product item to add. + * @param {OrderedProductItem} product - The product item to add. */ - addProductItem(product: ProductItem) { + addProductItem(product: OrderedProductItem) { this.productItems.push(product); } } @@ -39,9 +42,9 @@ export class Order implements OrderInterface { /** * Represents a product item. * @class - * @implements {ProductItemInterface} + * @implements {OrderedProductItemInterface} */ -export class ProductItem implements ProductItemInterface { +export class OrderedProductItem implements OrderedProductItemInterface { currency: string; itemPrice: string; productRetailerId: string; diff --git a/packages/wapi.js/src/structures/order/interface.ts b/packages/wapi.js/src/structures/order/interface.ts index 51a1d74..6ff468f 100644 --- a/packages/wapi.js/src/structures/order/interface.ts +++ b/packages/wapi.js/src/structures/order/interface.ts @@ -2,7 +2,7 @@ * Represents the interface for a product item. * @interface */ -export interface ProductItemInterface { +export interface OrderedProductItemInterface { /** * The retailer ID of the product. */ @@ -38,13 +38,13 @@ export interface OrderInterface { text: string; /** * The array of product items in the order. - * @type {ProductItemInterface[]} + * @type {OrderedProductItemInterface[]} */ - productItems: ProductItemInterface[]; + productItems: OrderedProductItemInterface[]; /** * Adds a product item to the order. - * @param {ProductItemInterface} product - The product item to add. + * @param {OrderedProductItemInterface} product - The product item to add. * @returns {void} */ - addProductItem: (product: ProductItemInterface) => void; + addProductItem: (product: OrderedProductItemInterface) => void; } diff --git a/packages/wapi.js/src/structures/product/index.ts b/packages/wapi.js/src/structures/product/index.ts new file mode 100644 index 0000000..1d9dfff --- /dev/null +++ b/packages/wapi.js/src/structures/product/index.ts @@ -0,0 +1,137 @@ +import { type z } from "zod"; +import type { + InteractiveMessageApiPayloadSchemaType, + ProductInteractiveMessagePayload, +} from "../../api-request-payload-schema"; +import { InteractiveMessage } from "../interaction"; +import { InteractiveMessageTypeEnum } from "../interaction/interface"; +import type { ProductMessageMessageInterface } from "./interface"; +import { MessageTypeEnum } from "../message/types"; +import { HeaderTypeEnum } from "../interaction/schema"; + +/** + * Represents a product interaction message. + * @extends {InteractiveMessage} + * @implements {ProductMessageMessageInterface} + * @class + */ +export class ProductMessage + extends InteractiveMessage + implements ProductMessageMessageInterface +{ + data: { + catalogId: string; + productRetailerId: string; + }; + + /** + * Creates an instance of ProductInteractionMessage. + * @constructor + * @memberof ProductInteractionMessage + * @param {Object} params - The parameters for creating the product interaction message. + * @param {string} params.buttonText - The button text of the message. + * @param {string} [params.footerText] - The footer text of the message. + * @param {string} params.bodyText - The body text of the message. + * @param {string} params.catalogId - The catalog ID of the product. + * @param {string} params.productRetailerId - The product retailer ID of the product. + */ + constructor(params: { + buttonText: string; + footerText?: string; + bodyText: string; + catalogId: string; + productRetailerId: string; + }) { + super({ + type: InteractiveMessageTypeEnum.Button, + footerText: params.footerText, + bodyText: params.bodyText, + }); + this.data = { + catalogId: params.catalogId, + productRetailerId: params.productRetailerId, + }; + } + + /** + * Adds a header to the message. + */ + addHeader() {} + + /** + * Adds a footer to the message. + * @param {string} footerText - The footer text to be added. + */ + addFooter(footerText: string) { + this.interactiveMessageData.footerText = footerText; + } + + /** + * Converts the message to JSON format. + * @memberof ProductInteractionMessage + * @param {Object} params - The parameters for converting the message to JSON. + * @param {string} params.to - The recipient of the message. + * @param {string} [params.replyToMessageId] - The ID of the message to reply to. + * @returns {Object} The JSON representation of the message. + */ + toJson(params: { to: string; replyToMessageId?: string }): z.infer< + typeof InteractiveMessageApiPayloadSchemaType + > & { + interactive: z.infer; + } { + return { + ...(params.replyToMessageId + ? { context: { message_id: params.replyToMessageId } } + : {}), + to: params.to, + messaging_product: "whatsapp", + recipient_type: "individual", + type: MessageTypeEnum.Interactive, + interactive: { + type: InteractiveMessageTypeEnum.Product, + action: { + catalogId: this.data.catalogId, + productRetailerId: this.data.productRetailerId, + }, + body: { + text: this.interactiveMessageData.bodyText, + }, + ...(this.interactiveMessageData.header + ? { + header: { + ...(this.interactiveMessageData.header.type === + HeaderTypeEnum.Text + ? { + type: HeaderTypeEnum.Text, + text: this.interactiveMessageData.header.text, + } + : this.interactiveMessageData.header.type === + HeaderTypeEnum.Document + ? { + type: HeaderTypeEnum.Document, + document: this.interactiveMessageData.header.document, + } + : this.interactiveMessageData.header.type === + HeaderTypeEnum.Image + ? { + type: HeaderTypeEnum.Image, + image: this.interactiveMessageData.header.image, + } + : { + type: HeaderTypeEnum.Video, + video: this.interactiveMessageData.header.video, + }), + }, + } + : {}), + ...(this.interactiveMessageData.footerText + ? { + footer: { + text: this.interactiveMessageData.footerText, + }, + } + : {}), + }, + }; + } +} diff --git a/packages/wapi.js/src/structures/product/interface.ts b/packages/wapi.js/src/structures/product/interface.ts new file mode 100644 index 0000000..5469404 --- /dev/null +++ b/packages/wapi.js/src/structures/product/interface.ts @@ -0,0 +1,14 @@ +import { type InteractiveMessageInterface } from "../interaction/interface"; + +/** + * Represents the interface for a product interaction message. + * @interface + * @extends {InteractiveMessageInterface} + */ +export interface ProductMessageMessageInterface + extends InteractiveMessageInterface { + data: { + catalogId: string; + productRetailerId: string; + }; +} diff --git a/packages/wapi.js/src/webhook/index.ts b/packages/wapi.js/src/webhook/index.ts index 2adc5fa..5fd1df3 100644 --- a/packages/wapi.js/src/webhook/index.ts +++ b/packages/wapi.js/src/webhook/index.ts @@ -47,7 +47,7 @@ import { OrderMessageEvent } from "./events/order"; import { UnknownEvent } from "./events/unknown"; import { CustomerIdentityChangeEvent } from "./events/customer-identity-changed"; import { CustomerNumberChangeEvent } from "./events/customer-number-changed"; -import { Order, ProductItem } from "../structures/order"; +import { Order, OrderedProductItem } from "../structures/order"; import { StickerMessageEvent } from "./events/sticker"; import { LocationMessageEvent } from "./events/location"; import { ProductInquiryEvent } from "./events/product-inquiry"; @@ -492,7 +492,7 @@ export class Webhook implements WebhookInterface { catalogId: message.order.catalog_id, productItems: message.order.product_items.map( (item) => - new ProductItem({ + new OrderedProductItem({ currency: item.currency, itemPrice: item.item_price, productRetailerId: item.product_retailer_id,