diff --git a/.circleci/config.yml b/.circleci/config.yml index 761ddf89e..dab38d7e8 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -29,7 +29,7 @@ jobs: build-bridge: working_directory: ~/mini-js-bridge docker: - - image: circleci/node:14.17.0 + - image: circleci/node:14.18.0 steps: - checkout - restore_cache: @@ -64,7 +64,7 @@ jobs: export-bridge: working_directory: ~/mini-js-bridge docker: - - image: circleci/node:14.17.0 + - image: circleci/node:14.18.0 steps: - checkout - attach_workspace: @@ -77,7 +77,7 @@ jobs: build-sdk: working_directory: ~/mini-js-sdk docker: - - image: circleci/node:14.17.0 + - image: circleci/node:14.18.0 steps: - checkout - restore_cache: @@ -131,7 +131,7 @@ jobs: publish-sdk: working_directory: ~/mini-js-sdk docker: - - image: circleci/node:14.17.0 + - image: circleci/node:14.18.0 steps: - checkout - attach_workspace: @@ -173,7 +173,7 @@ jobs: build-sample: # builds & tests the sample app against latest sdk build. working_directory: ~/js-miniapp-sample docker: - - image: circleci/node:14.17.0 + - image: circleci/node:14.18.0 # TODO get the sdk build from saved workspace environment: PUBLIC_URL: . @@ -210,7 +210,7 @@ jobs: deploy-sample: working_directory: ~/js-miniapp-sample docker: - - image: circleci/node:14.17.0 + - image: circleci/node:14.18.0 steps: - checkout - attach_workspace: @@ -236,7 +236,7 @@ jobs: upload-coverage: working_directory: ~/js-miniapp docker: - - image: circleci/node:14.17.0 + - image: circleci/node:14.18.0 steps: - checkout - attach_workspace: diff --git a/js-miniapp-bridge/src/common-bridge.ts b/js-miniapp-bridge/src/common-bridge.ts index 036a85829..f9878e72c 100644 --- a/js-miniapp-bridge/src/common-bridge.ts +++ b/js-miniapp-bridge/src/common-bridge.ts @@ -27,7 +27,7 @@ import { ShareInfoType } from './types/share-info'; import { AccessTokenData, NativeTokenData } from './types/token-data'; import { MiniAppError, parseMiniAppError } from './types/error-types'; import { MiniAppResponseInfo } from './types/response-types/miniapp'; -import { Product, PurchasedProduct } from './types/in-app-purchase'; +import { ProductInfo, PurchasedProductInfo } from './types/in-app-purchase'; /** @internal */ const mabMessageQueue: Callback[] = []; @@ -691,12 +691,12 @@ export class MiniAppBridge { * @see {getAllProducts} */ getAllProducts() { - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { return this.executor.exec( 'getAllProducts', null, productsList => { - resolve(JSON.parse(productsList) as Product[]); + resolve(JSON.parse(productsList) as ProductInfo[]); }, error => reject(parseMiniAppError(error)) ); @@ -709,12 +709,12 @@ export class MiniAppBridge { * @returns Purchased product details and the transaction details of the purchase. */ purchaseProductWith(id: string) { - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { return this.executor.exec( 'purchaseProductWith', - { product_id: id }, + { productId: id }, purchasedProduct => { - resolve(JSON.parse(purchasedProduct) as PurchasedProduct); + resolve(JSON.parse(purchasedProduct) as PurchasedProductInfo); }, error => reject(parseMiniAppError(error)) ); @@ -730,7 +730,7 @@ export class MiniAppBridge { return new Promise((resolve, reject) => { return this.executor.exec( 'consumeProductWith', - { product_id: id, transaction_id: transactionId }, + { productId: id, productTransactionId: transactionId }, consumedInfo => { resolve(JSON.parse(consumedInfo) as MiniAppResponseInfo); }, diff --git a/js-miniapp-bridge/src/index.ts b/js-miniapp-bridge/src/index.ts index f027df142..dea72132d 100644 --- a/js-miniapp-bridge/src/index.ts +++ b/js-miniapp-bridge/src/index.ts @@ -38,6 +38,11 @@ import { SecureStorageBusyError, SecureStorageUnavailableError, SecureStorageIOError, + PurchaseFailedError, + ConsumeFailedError, + ProductNotFoundError, + ProductPurchasedAlreadyError, + UserCancelledPurchaseError, } from './types/error-types'; import { MiniAppSecureStorageKeyValues, @@ -45,8 +50,8 @@ import { MiniAppSecureStorageEvents, } from './types/secure-storage'; import { - Product, - PurchasedProduct, + ProductInfo, + PurchasedProductInfo, ProductPrice, } from './types/in-app-purchase'; @@ -85,7 +90,12 @@ export { SecureStorageIOError, MiniAppSecureStorageEvents, CloseAlertInfo, - Product, - PurchasedProduct, + ProductInfo, + PurchasedProductInfo, ProductPrice, + PurchaseFailedError, + ConsumeFailedError, + ProductNotFoundError, + ProductPurchasedAlreadyError, + UserCancelledPurchaseError, }; diff --git a/js-miniapp-bridge/src/types/error-types/in-app-purchase-errors.ts b/js-miniapp-bridge/src/types/error-types/in-app-purchase-errors.ts new file mode 100644 index 000000000..7712207c3 --- /dev/null +++ b/js-miniapp-bridge/src/types/error-types/in-app-purchase-errors.ts @@ -0,0 +1,72 @@ +import { MiniAppError, MiniAppJson } from './mini-app-error'; + +enum MiniAppInAppPurchaseErrorType { + PurchaseFailedError = 'PurchaseFailedError', + ConsumeFailedError = 'ConsumeFailedError', + ProductNotFoundError = 'ProductNotFoundError', + ProductPurchasedAlreadyError = 'ProductPurchasedAlreadyError', + UserCancelledPurchaseError = 'UserCancelledPurchaseError', +} + +export class PurchaseFailedError extends MiniAppError { + constructor(public errorInput: MiniAppJson) { + super(errorInput); + Object.setPrototypeOf(this, PurchaseFailedError.prototype); + this.message = 'Product Purchase failed, please try again later'; + } +} + +export class ConsumeFailedError extends MiniAppError { + constructor(public errorInput: MiniAppJson) { + super(errorInput); + Object.setPrototypeOf(this, ConsumeFailedError.prototype); + this.message = + 'Unable to consume the product, please make sure the product is purchased already'; + } +} + +export class ProductNotFoundError extends MiniAppError { + constructor(public errorInput: MiniAppJson) { + super(errorInput); + Object.setPrototypeOf(this, ProductNotFoundError.prototype); + this.message = + 'Unable to find the ProductId. Please make sure that the productId is registered in Google Play'; + } +} + +export class ProductPurchasedAlreadyError extends MiniAppError { + constructor(public errorInput: MiniAppJson) { + super(errorInput); + Object.setPrototypeOf(this, ProductPurchasedAlreadyError.prototype); + this.message = 'This Product is purchased already'; + } +} + +export class UserCancelledPurchaseError extends MiniAppError { + constructor(public errorInput: MiniAppJson) { + super(errorInput); + Object.setPrototypeOf(this, UserCancelledPurchaseError.prototype); + this.message = 'User cancelled the purchase'; + } +} + +export function parseInAppPurchaseError(json: MiniAppJson) { + const errorType: MiniAppInAppPurchaseErrorType = + MiniAppInAppPurchaseErrorType[ + json.type as keyof typeof MiniAppInAppPurchaseErrorType + ]; + switch (errorType) { + case MiniAppInAppPurchaseErrorType.PurchaseFailedError: + return new PurchaseFailedError(json); + case MiniAppInAppPurchaseErrorType.ConsumeFailedError: + return new ConsumeFailedError(json); + case MiniAppInAppPurchaseErrorType.ProductNotFoundError: + return new ProductNotFoundError(json); + case MiniAppInAppPurchaseErrorType.ProductPurchasedAlreadyError: + return new ProductPurchasedAlreadyError(json); + case MiniAppInAppPurchaseErrorType.UserCancelledPurchaseError: + return new UserCancelledPurchaseError(json); + default: + return undefined; + } +} diff --git a/js-miniapp-bridge/src/types/error-types/index.ts b/js-miniapp-bridge/src/types/error-types/index.ts index f97083b1b..8bb5e6778 100644 --- a/js-miniapp-bridge/src/types/error-types/index.ts +++ b/js-miniapp-bridge/src/types/error-types/index.ts @@ -18,6 +18,14 @@ import { SecureStorageIOError, parseStorageError, } from './secure-storage-errors'; +import { + PurchaseFailedError, + ConsumeFailedError, + ProductNotFoundError, + ProductPurchasedAlreadyError, + UserCancelledPurchaseError, + parseInAppPurchaseError, +} from './in-app-purchase-errors'; import { MiniAppError, MiniAppJson } from './mini-app-error'; function parseMiniAppError(jsonString: string): MiniAppError { @@ -28,6 +36,7 @@ function parseMiniAppError(jsonString: string): MiniAppError { parseAuthError(json) || parseDownloadError(json) || parseStorageError(json) || + parseInAppPurchaseError(json) || new MiniAppError(json) ); } catch (e) { @@ -53,4 +62,9 @@ export { SecureStorageBusyError, SecureStorageUnavailableError, SecureStorageIOError, + PurchaseFailedError, + ConsumeFailedError, + ProductNotFoundError, + ProductPurchasedAlreadyError, + UserCancelledPurchaseError, }; diff --git a/js-miniapp-bridge/src/types/in-app-purchase.ts b/js-miniapp-bridge/src/types/in-app-purchase.ts index 4001e1a43..2f51b0c07 100644 --- a/js-miniapp-bridge/src/types/in-app-purchase.ts +++ b/js-miniapp-bridge/src/types/in-app-purchase.ts @@ -1,17 +1,15 @@ -export interface Product { +export interface ProductInfo { title: string; description: string; id: string; - price: ProductPrice; + productPriceInfo: ProductPrice; } - export interface ProductPrice { currencyCode: string; price: string; } - -export interface PurchasedProduct { - product: Product; +export interface PurchasedProductInfo { + productInfo: ProductInfo; transactionId: string; transactionDate: string; } diff --git a/js-miniapp-sample/src/index.js b/js-miniapp-sample/src/index.js index 3e7f50b37..a86c4a302 100644 --- a/js-miniapp-sample/src/index.js +++ b/js-miniapp-sample/src/index.js @@ -1,18 +1,17 @@ import React from 'react'; - -import ReactDOM from 'react-dom'; +import { createRoot } from 'react-dom/client'; import './index.css'; import App from './App'; //$FlowFixMe import * as serviceWorker from './serviceWorker'; -ReactDOM.render( +const container = document.getElementById('root'); +const root = createRoot(container); +root.render( - , - //$FlowFixMe - document.getElementById('root') + ); // If you want your app to work offline and load faster, you can change diff --git a/js-miniapp-sample/src/pages/in-app-purchase.js b/js-miniapp-sample/src/pages/in-app-purchase.js index d7e4521d2..5d7646902 100644 --- a/js-miniapp-sample/src/pages/in-app-purchase.js +++ b/js-miniapp-sample/src/pages/in-app-purchase.js @@ -2,27 +2,22 @@ import React, { useReducer } from 'react'; import { Button, - CardHeader, CircularProgress, FormGroup, Typography, CardContent, CardActions, - TextField, - Paper, + ListItem, + ListItemText, } from '@material-ui/core'; import { red, green } from '@material-ui/core/colors'; import { makeStyles } from '@material-ui/core/styles'; +import { Alert, AlertTitle } from '@mui/material'; +import Snackbar from '@mui/material/Snackbar'; import clsx from 'clsx'; -import { MiniAppError, PurchasedProductResponse } from 'js-miniapp-sdk'; -import { connect } from 'react-redux'; +import MiniApp, { MiniAppError } from 'js-miniapp-sdk'; import GreyCard from '../components/GreyCard'; -import { - getAllProductsAction, - purchaseProductAction, - consumeProductAction, -} from '../services/purchase/action'; const useStyles = makeStyles((theme) => ({ scrollable: { @@ -102,6 +97,21 @@ const useStyles = makeStyles((theme) => ({ red: { color: red[500], }, + displayInlineBlock: { + display: 'inline-block', + }, + purchaseButtonContainer: { + textAlign: 'center', + display: 'flex', + flexDirection: 'row', + justifyContent: 'space-evenly', + }, + purchaseButton: { + margin: '15px', + }, + listItemStyle: { + overflowWrap: 'anywhere', + }, })); export const initialState = { @@ -118,13 +128,18 @@ type State = { type Action = { type: string, miniAppError: MiniAppError, + productInfo: ProductInfo[], + purchasedProductInfo: PurchasedProductInfo, + consumeProductResponse: MiniAppResponseInfo, }; export const dataFetchReducer = (state: State, action: Action) => { + console.log('dataFetchReducer: ', state); + console.log('dataFetchReducer ACTION: ', action); + console.log('dataFetchReducer Items: ', action.productInfo); switch (action.type) { case 'PURCHASE_FETCH_INIT': return { - ...state, isLoading: true, isError: false, error: null, @@ -135,146 +150,315 @@ export const dataFetchReducer = (state: State, action: Action) => { isLoading: false, isError: false, error: null, + productInfo: action.productInfo, }; case 'PURCHASE_FETCH_FAILURE': + return { + ...state, + isLoading: false, + isError: false, + error: null, + productInfo: null, + }; + case 'PURCHASE_PRODUCT_INIT': + return { + isLoading: true, + isError: false, + error: null, + }; + case 'PURCHASE_PRODUCT_SUCCESS': + return { + ...state, + isLoading: false, + isError: false, + error: null, + purchasedProductInfo: action.purchasedProduct, + }; + case 'PURCHASE_PRODUCT_FAILURE': return { ...initialState, isLoading: false, isError: true, + purchasedProductInfo: null, error: (typeof action.miniAppError == 'string' ? action.miniAppError : action.miniAppError.message) || '', }; + case 'CONSUME_PRODUCT_SUCCESS': + return { + ...state, + isLoading: false, + isError: false, + error: null, + consumeProductResponse: action.consumeProductResponse, + }; + case 'CONSUME_PRODUCT_FAILURE': + return { + ...initialState, + isLoading: false, + isError: true, + consumeProductResponse: null, + error: + (typeof action.miniAppError == 'string' + ? action.miniAppError + : action.miniAppError.message) || 'Product is not purchased yet', + }; + default: throw Error('Unknown action type'); } }; -type PurchaseProductProps = { - purchasedProduct: PurchasedProductResponse, - purchaseProductWith: (itemId: string) => Promise, - consumeProductWith: (itemId: string) => Promise, - purchaseError: MiniAppError, -}; - -function PurchaseComponent(props: PurchaseProductProps) { +function PurchaseProductComponent() { const [state, dispatch] = useReducer(dataFetchReducer, initialState); - const classes = useStyles(); - - let inputValue = ''; + const [productFetchState, productFetchDispatch] = useReducer( + dataFetchReducer, + initialState + ); + const [snackBarOpen, setSnackBarOpen] = React.useState(false); - const handleInput = (e: SyntheticInputEvent) => { - e.preventDefault(); - inputValue = e.currentTarget.value; - }; + const classes = useStyles(); const buttonClassname = clsx({ [classes.buttonFailure]: state.isError, [classes.buttonSuccess]: !state.isError, }); - function handlePurchaseClick(e) { + const handleSnackBarClose = ( + event?: React.SyntheticEvent | Event, + reason?: string + ) => { + setSnackBarOpen(false); + }; + + function handleFetchClick(e) { if (!state.isLoading) { - dispatch({ type: 'PURCHASE_FETCH_INIT', miniAppError: null }); - BuyProduct(); + productFetchDispatch({ type: 'PURCHASE_FETCH_INIT', miniAppError: null }); + getAllProducts(); } } - function BuyProduct() { - props - .purchaseProductWith(inputValue) - .then(() => - dispatch({ type: 'PURCHASE_FETCH_SUCCESS', miniAppError: null }) - ) + function getAllProducts() { + MiniApp.purchaseService + .getAllProducts() + .then((products) => { + productFetchDispatch({ + type: 'PURCHASE_FETCH_SUCCESS', + miniAppError: null, + productInfo: products, + }); + }) .catch((miniAppError) => { - console.log('Product Error: ', miniAppError); - dispatch({ type: 'PURCHASE_FETCH_FAILURE', miniAppError }); + console.log('getAllProducts Error: ', miniAppError); + productFetchDispatch({ type: 'PURCHASE_FETCH_FAILURE', miniAppError }); }); } - function handleConsumeClick(e) { + function handlePurchaseClick(e) { if (!state.isLoading) { - dispatch({ type: 'PURCHASE_FETCH_INIT', miniAppError: null }); - ConsumeProduct(); + dispatch({ + type: 'PURCHASE_PRODUCT_INIT', + miniAppError: null, + }); + BuyProduct(e.currentTarget.value); } } - function ConsumeProduct() { - props - .consumePurchaseWith(inputValue) - .then(() => - dispatch({ type: 'PURCHASE_FETCH_SUCCESS', miniAppError: null }) - ) + function BuyProduct(productId: string) { + MiniApp.purchaseService + .purchaseProductWith(productId) + .then((purchasedProduct) => { + console.log('SUCCESS - BuyProduct', purchasedProduct); + dispatch({ + type: 'PURCHASE_PRODUCT_SUCCESS', + miniAppError: null, + purchasedProduct: purchasedProduct, + }); + cachePurchasedProduct( + purchasedProduct.productInfo.id, + purchasedProduct + ); + }) .catch((miniAppError) => { - console.log('Product Error: ', miniAppError); - dispatch({ type: 'PURCHASE_FETCH_FAILURE', miniAppError }); + console.log('Buy Product Error: ', miniAppError); + dispatch({ + type: 'PURCHASE_PRODUCT_FAILURE', + miniAppError, + }); }); } - function PurchaseProduct() { - return ( - - - - - ); + function cachePurchasedProduct(key, value) { + window.localStorage.setItem(key, JSON.stringify(value)); + } + + function handleConsumeClick(e) { + if (!state.isLoading) { + dispatch({ type: 'PURCHASE_PRODUCT_INIT', miniAppError: null }); + ConsumeProduct( + e.currentTarget.value, + getTransactionId(e.currentTarget.value) + ); + } + } + + function getTransactionId(productId: string) { + const purchasedProduct = window.localStorage.getItem(productId); + var productInfo = JSON.parse(purchasedProduct); + return productInfo.transactionId; + } + + function ConsumeProduct(productId: string, transactionId: string) { + if (transactionId !== null || transactionId !== undefined) { + MiniApp.purchaseService + .consumePurchaseWith(productId, transactionId) + .then((response) => { + console.log('SUCCESS - ConsumeProduct', response); + setSnackBarOpen(true); + dispatch({ + type: 'CONSUME_PRODUCT_SUCCESS', + miniAppError: null, + consumeProductResponse: response, + }); + cachePurchasedProduct(productId, ''); + }) + .catch((miniAppError) => { + console.log('Consume Product Error: ', miniAppError); + dispatch({ + type: 'CONSUME_PRODUCT_FAILURE', + miniAppError, + }); + }); + } else { + dispatch({ + type: 'CONSUME_PRODUCT_FAILURE', + }); + } } function TransactionDetails() { - const dateInfo = new Date(props.purchasedProduct.product.transactionDate); + const dateInfo = new Date(state.purchasedProductInfo.transactionDate); return ( - - Transaction - {props.purchasedProduct.status} - + Transaction ID: {state.purchasedProductInfo.transactionId} +
Transaction Date: {dateInfo.toLocaleDateString()}
Transaction Time: {dateInfo.toLocaleTimeString()}
- Transaction ID: {props.purchasedProduct.product.transactionId}
); } - function ShowPurchasedProductDetails() { + function ShowConsumedAlert() { + return ( + + + + {state.consumeProductResponse.title} + {state.consumeProductResponse.description} + + + + ); + } + + function ShowProductDetails() { + console.log('ShowProductDetails: ', productFetchState); return ( - - {!state.isLoading && !state.isError && props.purchasedProduct && ( - - {TransactionDetails()} -
- Product Info - ( + - ID: {props.purchasedProduct.product.productInfo.id}
- Title: {props.purchasedProduct.product.productInfo.title}
- Description:{' '} - {props.purchasedProduct.product.productInfo.description}
-
-
-
- )} + + + {productInfo.description && + productInfo.description !== '' && ( + + {'Description: ' + productInfo.description} + + )} + + + {productInfo.id && productInfo.id !== '' && ( + {'Product ID: ' + productInfo.id} + )} + + + {productInfo.id && productInfo.id !== '' && ( + + {'Price : ' + + productInfo.productPriceInfo.price + + ' ' + + productInfo.productPriceInfo.currencyCode} + + )} + +
+ } + /> +
+
+ +
+
+ + {state.isLoading && ( + + )} +
+
+ {state.purchasedProductInfo && + state.purchasedProductInfo.productInfo.id === + productInfo.id &&
{TransactionDetails()}
} + + ))} ); } @@ -285,7 +469,7 @@ function PurchaseComponent(props: PurchaseProductProps) {
- - {state.isLoading && ( - - )} -
-
- {state.isLoading && ( @@ -323,47 +490,25 @@ function PurchaseComponent(props: PurchaseProductProps) { {state.error} )} + {!state.isLoading && state.consumeProductResponse && ( +
{ShowConsumedAlert()}
+ )} ); } return (
+ + {PurchaseProductCardActionsForm()} + - -
- {PurchaseProduct()} - {ShowPurchasedProductDetails()} -
-
- - {PurchaseProductCardActionsForm()} - + {!productFetchState.isLoading && productFetchState.productInfo && ( + {ShowProductDetails()} + )}
); } -const mapStateToProps = (state) => { - console.log('MapStateToProps: ', state); - return { - purchasedProduct: state.purchaseProduct, - purchaseError: state.error, - }; -}; - -const mapDispatchToProps = (dispatch) => { - return { - getAllProducts: () => dispatch(getAllProductsAction()), - purchaseProductWith: (itemId: string) => - dispatch(purchaseProductAction(itemId)), - consumeProductWith: (itemId: string, transactionId: string) => - dispatch(consumeProductAction(itemId)), - }; -}; - -export { PurchaseComponent }; -export default connect(mapStateToProps, mapDispatchToProps)(PurchaseComponent); +export { PurchaseProductComponent }; diff --git a/js-miniapp-sample/src/routes.js b/js-miniapp-sample/src/routes.js index 0d5b42b9c..d481d5085 100644 --- a/js-miniapp-sample/src/routes.js +++ b/js-miniapp-sample/src/routes.js @@ -30,7 +30,7 @@ import EventListener from './pages/event-listener'; import FileDownload from './pages/file-download'; import FileUploader from './pages/file-upload'; import GifPage from './pages/gifs'; -import { PurchaseComponent } from './pages/in-app-purchase'; +import { PurchaseProductComponent } from './pages/in-app-purchase'; import Landing from './pages/landing'; import LocalStorage from './pages/local-storage'; import Media from './pages/media'; @@ -130,6 +130,7 @@ const navLinks = [ secureStorageNavLink, closeAlertNavLink, universalBridgeNavLink, + inAppPurchaseNavLink, ]; const homeItem = [ @@ -260,7 +261,7 @@ const appItems = [ icon: , label: inAppPurchaseNavLink.label, navLink: inAppPurchaseNavLink.navLink, - element: , + element: , }, ]; diff --git a/js-miniapp-sample/src/services/landing/reducers.js b/js-miniapp-sample/src/services/landing/reducers.js index 589cd23a3..13d4f24be 100644 --- a/js-miniapp-sample/src/services/landing/reducers.js +++ b/js-miniapp-sample/src/services/landing/reducers.js @@ -38,7 +38,7 @@ const SecureStorageStatusReducer = ( return { isReady: false, error: action.error, - ...state + ...state, }; default: return { diff --git a/js-miniapp-sample/src/services/permissions/actions.js b/js-miniapp-sample/src/services/permissions/actions.js index d89c6a44c..673385683 100644 --- a/js-miniapp-sample/src/services/permissions/actions.js +++ b/js-miniapp-sample/src/services/permissions/actions.js @@ -12,7 +12,7 @@ import { type PermissionsAction = { type: String, permissions: CustomPermissionResult[], - error: MiniAppError + error: MiniAppError, }; const requestCustomPermissions = ( diff --git a/js-miniapp-sample/src/services/permissions/reducers.js b/js-miniapp-sample/src/services/permissions/reducers.js index 9f319b469..d8fd8b2e4 100644 --- a/js-miniapp-sample/src/services/permissions/reducers.js +++ b/js-miniapp-sample/src/services/permissions/reducers.js @@ -1,18 +1,21 @@ import { CustomPermissionName, CustomPermissionStatus } from 'js-miniapp-sdk'; import type { PermissionsAction } from './actions'; -import { REQUEST_PERMISSIONS_SUCCESS, REQUEST_PERMISSIONS_FAILURE } from './types'; +import { + REQUEST_PERMISSIONS_SUCCESS, + REQUEST_PERMISSIONS_FAILURE, +} from './types'; type PermissionsState = { type: REQUEST_PERMISSIONS_FAILURE, permissions: CustomPermissionResult[], - error: MiniAppError + error: MiniAppError, }; const defaultState: PermissionsState = { type: undefined, permissions: [], - error: null + error: null, }; const PermissionsReducer = ( diff --git a/js-miniapp-sample/src/services/purchase/action.js b/js-miniapp-sample/src/services/purchase/action.js deleted file mode 100644 index 59bfe4cf4..000000000 --- a/js-miniapp-sample/src/services/purchase/action.js +++ /dev/null @@ -1,83 +0,0 @@ -import MiniApp, { PurchasedProductResponse } from 'js-miniapp-sdk'; - -import { - REQUEST_PRODUCT_PURCHASE_SUCCESS, - REQUEST_PRODUCT_PURCHASE_FAILURE, -} from './types'; - -type PurchaseProductSuccessAction = { - type: string, - purchasedProduct: PurchasedProductResponse, - productsList: Product[], -}; - -const getAllProductsAction = (): Function => { - return (dispatch) => { - return MiniApp.purchaseService - .getAllProducts() - .then((products) => { - console.log('getAllProducts Success Action: ', products); - dispatch({ - type: REQUEST_PRODUCT_PURCHASE_SUCCESS, - productsList: products, - }); - return Promise.resolve(products); - }) - .catch((e) => { - console.log('getAllProducts Error: ', e); - dispatch({ - type: REQUEST_PRODUCT_PURCHASE_FAILURE, - }); - throw e; - }); - }; -}; - -const purchaseProductAction = (itemId: string): Function => { - return (dispatch) => { - return MiniApp.purchaseService - .purchaseItemWith(itemId) - .then((purchasedProduct) => { - console.log('PurchaseProductSuccessAction: ', purchasedProduct); - dispatch({ - type: REQUEST_PRODUCT_PURCHASE_SUCCESS, - purchasedProduct: purchasedProduct, - }); - return Promise.resolve(purchasedProduct); - }) - .catch((e) => { - console.log('PurchaseProduct Error: ', e); - dispatch({ - type: REQUEST_PRODUCT_PURCHASE_FAILURE, - }); - throw e; - }); - }; -}; - -const consumeProductAction = ( - itemId: string, - transactionId: string -): Function => { - return (dispatch) => { - return MiniApp.purchaseService - .consumePurchaseWith(itemId, transactionId) - .then((miniAppResponseInfo) => { - console.log('consumeProductAction: ', miniAppResponseInfo); - dispatch({ - type: REQUEST_PRODUCT_PURCHASE_SUCCESS, - }); - return Promise.resolve(miniAppResponseInfo); - }) - .catch((e) => { - console.log('consumeProductAction Error: ', e); - dispatch({ - type: REQUEST_PRODUCT_PURCHASE_FAILURE, - }); - throw e; - }); - }; -}; - -export { getAllProductsAction, purchaseProductAction, consumeProductAction }; -export type { PurchaseProductSuccessAction }; diff --git a/js-miniapp-sample/src/services/purchase/reducers.js b/js-miniapp-sample/src/services/purchase/reducers.js deleted file mode 100644 index a62f7779f..000000000 --- a/js-miniapp-sample/src/services/purchase/reducers.js +++ /dev/null @@ -1,17 +0,0 @@ -import type { PurchaseProductSuccessAction } from './actions'; -import { REQUEST_PRODUCT_PURCHASE_SUCCESS } from './types'; - -const defaultPurchaseProduct = null; -const PurchaseProductReducer = ( - state: ?string = defaultPurchaseProduct, - action: PurchaseProductSuccessAction -): ?string => { - switch (action.type) { - case REQUEST_PRODUCT_PURCHASE_SUCCESS: - return action.purchasedProduct; - default: - return state; - } -}; - -export { PurchaseProductReducer }; \ No newline at end of file diff --git a/js-miniapp-sample/src/services/purchase/types.js b/js-miniapp-sample/src/services/purchase/types.js deleted file mode 100644 index 9fad7b5cf..000000000 --- a/js-miniapp-sample/src/services/purchase/types.js +++ /dev/null @@ -1,4 +0,0 @@ -const REQUEST_PRODUCT_PURCHASE_SUCCESS = 'REQUEST_PRODUCT_PURCHASE_SUCCESS'; -const REQUEST_PRODUCT_PURCHASE_FAILURE = 'REQUEST_PRODUCT_PURCHASE_FAILURE'; - -export { REQUEST_PRODUCT_PURCHASE_SUCCESS, REQUEST_PRODUCT_PURCHASE_FAILURE }; \ No newline at end of file diff --git a/js-miniapp-sample/src/services/reducers.js b/js-miniapp-sample/src/services/reducers.js index 3e3c53861..78b6516e9 100644 --- a/js-miniapp-sample/src/services/reducers.js +++ b/js-miniapp-sample/src/services/reducers.js @@ -8,7 +8,6 @@ import { } from './landing/reducers'; import MessageReducer from './message/reducers'; import { PermissionsReducer } from './permissions/reducers'; -import { PurchaseProductReducer } from './purchase/reducers'; import storageReducer from './secure-storage/reducers'; import userReducer from './user/reducers'; import { UUIDReducer } from './uuid/reducers'; @@ -23,5 +22,4 @@ export default combineReducers({ file: FileDownloadReducer, secureStorage: storageReducer, secureStorageStatus: SecureStorageStatusReducer, - purchaseProduct: PurchaseProductReducer, }); diff --git a/js-miniapp-sdk/src/index.ts b/js-miniapp-sdk/src/index.ts index 13b2e4338..f48994889 100644 --- a/js-miniapp-sdk/src/index.ts +++ b/js-miniapp-sdk/src/index.ts @@ -33,9 +33,14 @@ import { SecureStorageIOError, MiniAppSecureStorageEvents, CloseAlertInfo, - Product, + ProductInfo, ProductPrice, - PurchasedProduct, + PurchasedProductInfo, + PurchaseFailedError, + ConsumeFailedError, + ProductNotFoundError, + ProductPurchasedAlreadyError, + UserCancelledPurchaseError, } from '../../js-miniapp-bridge/src'; import { MiniApp } from './miniapp'; @@ -81,7 +86,12 @@ export { SecureStorageIOError, MiniAppSecureStorageEvents, CloseAlertInfo, - Product, + ProductInfo, ProductPrice, - PurchasedProduct, + PurchasedProductInfo, + PurchaseFailedError, + ConsumeFailedError, + ProductNotFoundError, + ProductPurchasedAlreadyError, + UserCancelledPurchaseError, }; diff --git a/js-miniapp-sdk/src/modules/in-app-purchase.ts b/js-miniapp-sdk/src/modules/in-app-purchase.ts index 582770e3e..2d6ddd562 100644 --- a/js-miniapp-sdk/src/modules/in-app-purchase.ts +++ b/js-miniapp-sdk/src/modules/in-app-purchase.ts @@ -1,4 +1,7 @@ -import { Product, PurchasedProduct } from '../../../js-miniapp-bridge/src'; +import { + ProductInfo, + PurchasedProductInfo, +} from '../../../js-miniapp-bridge/src'; import { MiniAppResponseInfo } from '../../../js-miniapp-bridge/src/types/response-types/miniapp'; import { getBridge } from '../sdkbridge'; @@ -6,14 +9,14 @@ interface PurchaseProvider { /** * Retrieves and lists all the products from the play/app store which are available for inapp-purchases. */ - getAllProducts(): Promise; + getAllProducts(): Promise; /** * Triggers the request to host app to Purchase a product using the Product ID. * @param id The product id which must be purchased from inapp-purchase. * This will return the status of inapp-purchase and the details of the purchased product. */ - purchaseProductWith(id: string): Promise; + purchaseProductWith(id: string): Promise; /** * Triggers the request to host app to Purchase a product using the Product ID. @@ -23,16 +26,16 @@ interface PurchaseProvider { consumePurchaseWith( id: string, transactionId: string - ): Promise; + ): Promise; } /** @internal */ export class Purchases { - getAllProducts(): Promise { + getAllProducts(): Promise { return getBridge().getAllProducts(); } - purchaseProductWith(id: string): Promise { + purchaseProductWith(id: string): Promise { return getBridge().purchaseProductWith(id); }