import { computed, ref, watch, type ComputedRef } from 'vue' import { fetchZaanboxPriceHistory, type LandingHistoryRange, } from '@/api/zaarboxPriceHistory' import { buildSeriesChartPaths } from '@/utils/chartAreaPaths' import { usePrice } from '@/utils/usePrice' const CHART_RANGE_OPTIONS = [ { value: 'DAILY' as const, shortLabel: '۲۴ ساعت', label: 'ارزش دارایی — ۲۴ ساعت گذشته' }, { value: 'WEEKLY' as const, shortLabel: 'هفته', label: 'ارزش دارایی — هفته گذشته' }, { value: 'MONTHLY' as const, shortLabel: 'ماه', label: 'ارزش دارایی — ماه گذشته' }, ] export function useAssetsPortfolioChart( cashRial: ComputedRef, metalRial: ComputedRef, ) { const chartRange = ref('MONTHLY') const chartDrawn = ref(false) const chartLoading = ref(false) const priceHistory = ref>([]) async function loadChartHistory(range: LandingHistoryRange) { chartLoading.value = true try { priceHistory.value = await fetchZaanboxPriceHistory(range) } catch { priceHistory.value = [] } finally { chartLoading.value = false chartDrawn.value = true } } function setChartRange(range: LandingHistoryRange) { chartHover.value = null chartRange.value = range void loadChartHistory(range) } const portfolioSeries = computed(() => { const cash = Math.max(0, cashRial.value) const metal = Math.max(0, metalRial.value) const prices = priceHistory.value if (prices.length < 2) { const total = cash + metal if (total <= 0) return [] return prices.map((point) => ({ timeMs: point.timeMs, value: total })) } const refPrice = prices[prices.length - 1]?.price if (!refPrice || metal <= 0) { const total = cash + metal return prices.map((point) => ({ timeMs: point.timeMs, value: total })) } return prices.map((point) => ({ timeMs: point.timeMs, value: Math.round(cash + metal * (point.price / refPrice)), })) }) const portfolioChart = computed(() => buildSeriesChartPaths(portfolioSeries.value)) const chartHover = ref<{ xPercent: number yPercent: number valueLabel: string timeLabel: string } | null>(null) function formatChartTimeLabel(timeMs: number) { try { return new Intl.DateTimeFormat('fa-IR', { timeZone: 'Asia/Tehran', month: 'short', day: 'numeric', hour: '2-digit', minute: '2-digit', }).format(new Date(timeMs)) } catch { return '' } } function onChartPointerMove(event: PointerEvent) { const chart = portfolioChart.value if (!chart.hasData || chart.samples.length < 2) { chartHover.value = null return } const target = event.currentTarget as HTMLElement | null if (!target) return const rect = target.getBoundingClientRect() if (rect.width <= 0 || rect.height <= 0) return const ratio = Math.min(1, Math.max(0, (event.clientX - rect.left) / rect.width)) const index = Math.round(ratio * (chart.samples.length - 1)) const sample = chart.samples[index] if (!sample) return chartHover.value = { xPercent: (sample.x / chart.width) * 100, yPercent: (sample.y / chart.height) * 100, valueLabel: usePrice(sample.value), timeLabel: formatChartTimeLabel(sample.timeMs), } } function onChartPointerLeave() { chartHover.value = null } watch( () => cashRial.value + metalRial.value, (total) => { if (total > 0 && priceHistory.value.length === 0) { void loadChartHistory(chartRange.value) } }, { flush: 'post' }, ) async function initAssetsPortfolioChart() { await loadChartHistory(chartRange.value) } return { chartRange, chartRangeOptions: CHART_RANGE_OPTIONS, chartDrawn, chartLoading, portfolioChart, chartHover, onChartPointerMove, onChartPointerLeave, setChartRange, initAssetsPortfolioChart, } }