import { usePaymentStore } from '#lib/stores/payment' import { DepositMethodEnum, PromotionPlanEnum, TransactionStatusEnum, } from '#lib/enums' import { useCancelPromotion, usePromotion } from '#lib/composables/promotion' import type { AddInvoiceCryptoRequest, CryptoHistory, InvoiceCrypto, } from '#lib/types/deposit' import { formatDate, toUTCDate } from '#lib/utils/date' import { TRANSACTION_CRYPTO_STATUS } from '#lib/constants/history' import { DATE_TIME_FORMAT } from '#lib/constants/app' import { useDepositService, useNadal } from '#lib/composables' import dayjs from 'dayjs' /** * Import types from Nadal. */ import type { TransactionHistoriesRequestPayload, TransactionHistoriesResponseData, } from '@kira-dancer/nadal' import { formatNumberWithCommas } from '#lib/utils' import { computed } from 'vue' /** * Provides functions and state for managing cryptocurrency-related transactions. * * This composable includes functionality for handling cryptocurrency options, * creating invoices, processing transaction histories, and integrating with promotions. * * @returns {Object} An object with functions for cryptocurrency operations and reactive state. * @namespace */ export function useCrypto() { const depositStore = usePaymentStore() const { fetchCrypto } = useDepositService() const { payment, transaction } = useNadal() const { isUsingPromotion, promotionPackages, fetchPromotionPackages } = usePromotion() const { openModalCancelPromotion } = useCancelPromotion() /** * Reactive list of available promotions filtered by the COMMISSION plan. * * @type {ComputedRef} The filtered list of promotions. */ const availablePromotions = computed(() => { return promotionPackages.value?.filter( (item) => item.id === PromotionPlanEnum.COMMISSION, ) }) /** * Reactive list of cryptocurrency options with additional information for display. * * @type {ComputedRef} The list of cryptocurrency options. */ const cryptoOptions = computed(() => { return depositStore.cryptos.map((crypto) => ({ ...crypto, label: crypto.network, price: `${formatNumberWithCommas(crypto.price)} VND`, value: crypto.network, min: 0, address: crypto.address, icon: '', })) }) /** * Fetches and updates the list of available cryptocurrencies. * * @returns {Promise} A promise that resolves once the cryptocurrencies are fetched and stored. */ const fetchCryptoList = async () => { const crypto = await fetchCrypto() if (crypto) { depositStore.setCryptos([crypto]) } else { depositStore.setCryptos([]) } } /** * Creates a new cryptocurrency invoice with the given request data. * * @param {AddInvoiceCryptoRequest} request - The request data for creating the invoice. * @returns {Promise} A promise that resolves with the response from the invoice creation. */ const addInvoiceCryoto = async ( request: AddInvoiceCryptoRequest, ): Promise => { return await payment.addInvoiceCrypto< AddInvoiceCryptoRequest, InvoiceCrypto[] >(request) } /** * Handles cryptocurrency changes and creates a new invoice if no promotion is being used. * * Opens a modal to cancel the promotion if one is being used. * */ const onCryptoChanged = async () => { if (isUsingPromotion.value) { openModalCancelPromotion() } } /** * Customizes cryptocurrency transaction data for display. * * TransactionHistoriesResponseData type is imported from the Nadal module. * * @param {TransactionHistoriesResponseData} data - The transaction history data to customize. * @returns {CryptoHistory | undefined} The customized transaction data or undefined if data is invalid. */ const customizeCryptoData = (data: TransactionHistoriesResponseData) => { if (data) { const crypto = depositStore.cryptos.find((e) => e.value === data.currency) let status = 'Đang xử lý' switch (data.status) { case TransactionStatusEnum.SMART_PAY_PROCESSING: case TransactionStatusEnum.PROCESSING: status = 'Đang xử lý' break case TransactionStatusEnum.APPROVED: case TransactionStatusEnum.FINISHED: status = 'Hoàn thành' break case TransactionStatusEnum.CANCEL: status = 'Thất bại' break default: status = 'Đang xử lý' break } return { numberCode: data.code, date: formatDate( toUTCDate(data.created_time), DATE_TIME_FORMAT.FULL_DATE_FORMAT, ), wallet_address: data.wallet_address, status, statusPay: data.status, statusClass: data.status?.toLowerCase(), link: `https://tronscan.org/#/address/${data.wallet_address}`, currencyName: crypto ? crypto.name : '', rateCode: crypto ? crypto.fee + '%' : '', timeleftApi: data.status === TransactionStatusEnum.SMART_PAY_PROCESSING ? data.timeleft ? Number(data.timeleft) * 1000 : 0 : 0, } } } /** * Retrieves transaction data for the past 24 hours and customizes it for display. * * TransactionHistoriesRequestPayload type is imported from the Nadal module. * * @returns {Promise} A promise that resolves with the customized transaction data. */ const fetchTransactionData = async () => { const params: TransactionHistoriesRequestPayload = { from_date: formatDate( dayjs().subtract(24, 'hour'), DATE_TIME_FORMAT.SHORT_DATE_FORMAT, ), to_date: formatDate(dayjs(), DATE_TIME_FORMAT.SHORT_DATE_FORMAT), status: TRANSACTION_CRYPTO_STATUS, limit: 20, page: 1, } const res = await transaction.histories< TransactionHistoriesRequestPayload, unknown >(params) let returnValue: CryptoHistory = {} const data = res.data as TransactionHistoriesResponseData[] if (data?.length) { const cryptoHistoryProcessing = data.find( (e) => e.method === DepositMethodEnum.CryptoPay && e.status === TransactionStatusEnum.SMART_PAY_PROCESSING, ) const cryptoHistoryApproved = data.find( (e) => e.method === DepositMethodEnum.CryptoPay && (e.status === TransactionStatusEnum.APPROVED || e.status === TransactionStatusEnum.FINISHED), ) const cryptoHistoryCancel = data.find( (e) => e.method === DepositMethodEnum.CryptoPay && e.status === TransactionStatusEnum.CANCEL, ) const cryptoHistory = cryptoHistoryProcessing || cryptoHistoryApproved || cryptoHistoryCancel const status = cryptoHistory ? cryptoHistory.status : '' const isDone = status === TransactionStatusEnum.CANCEL || status === TransactionStatusEnum.APPROVED || status === TransactionStatusEnum.FINISHED if (isDone) { returnValue.isDone = isDone } if (cryptoHistory && !isDone) { returnValue = { ...returnValue, ...customizeCryptoData(cryptoHistory), selectedCrypto: cryptoHistory.currency, // eslint-disable-next-line @typescript-eslint/no-explicit-any packageId: (cryptoHistory as any).package_id, } } } return returnValue } /** * Fetches cryptocurrency options and promotion packages. * * @returns {Promise} A promise that resolves once both the cryptocurrency options and promotion packages are fetched. */ const fetchData = async () => { await Promise.all([fetchCryptoList(), fetchPromotionPackages()]) } return { fetchData, cryptoOptions, promotionPackages: availablePromotions, fetchTransactionData, onCryptoChanged, fetchCryptoList, addInvoiceCryoto, } }