import dayjs from 'dayjs' import { useState } from 'react' import { Virtuoso } from 'react-virtuoso' import { useTranslation } from 'react-i18next' import { toast } from 'sonner' import { albumAdapter } from '@/adapters/album' import { AlbumPreview } from '@/components/main/album/album-preview' import { type AlbumPhoto, resolveIsVideo } from '@/components/main/album/utils' import { SearchInput } from '@/components/common/search-input' import { cn } from '@/lib/utils' import { Skeleton } from '@/components/ui/skeleton' import { AlbumSourceSwitcher } from '@/components/common/album-source-switcher' import { CloudEmptyState } from '@/components/common/cloud-empty-state' import { CloudFeatureHighlights } from '@/components/common/cloud-feature-highlights' import { CloudRefreshButton } from '@/components/common/cloud-refresh-button' import { AlbumSource } from '#/types/cloudAlbum' import { useAlbumStore } from '@/store' import { usePicGoCloudUserInfo } from '@/queries/picgo-cloud' import { resolveTimestampValue } from '@/utils/common' import { DEFAULT_DATE_TIME_FORMAT } from '@/utils/consts' import type { DashboardHistoryRecord } from './hooks/use-dashboard-history' import { HistoryItem } from './history-item' interface DashboardHistoryItem { id: number | string previewId: number name: string time: string imgUrl: string isVideo: boolean timestamp: number raw: DashboardHistoryRecord keywords: string[] } interface DashboardHistoryGroup { key: string label: string items: DashboardHistoryItem[] } type DashboardHistoryEntry = | { type: 'header' key: string label: string isFirstGroup: boolean } | { type: 'item' key: string item: DashboardHistoryItem } function resolveAlbumTimestamp (item: DashboardHistoryRecord) { return resolveTimestampValue(item.createdAt) || resolveTimestampValue(item.updatedAt) } function isSameDay (left: Date, right: Date) { return left.getFullYear() === right.getFullYear() && left.getMonth() === right.getMonth() && left.getDate() === right.getDate() } function formatHistoryTimestamp (timestamp: number) { if (timestamp <= 0) { return '' } return dayjs(timestamp).format(DEFAULT_DATE_TIME_FORMAT) } function buildHistoryItems (items: DashboardHistoryRecord[]): DashboardHistoryItem[] { return [...items] .sort((left, right) => resolveAlbumTimestamp(right) - resolveAlbumTimestamp(left)) .map((item, index) => { const name = item.fileName || item.imgUrl || item.originImgUrl || item.id || `${index + 1}` const timestamp = resolveAlbumTimestamp(item) const keywords = [name, item.imgUrl, item.originImgUrl, item.fileName] .filter((value): value is string => typeof value === 'string' && value.length > 0) return { id: item.id || item.imgUrl || `${index}`, previewId: index, name, time: formatHistoryTimestamp(timestamp), imgUrl: item.imgUrl || item.originImgUrl || '', isVideo: resolveIsVideo(item), timestamp, raw: item, keywords } }) } function buildGroupKey (timestamp: number) { const date = new Date(timestamp) return `${date.getFullYear()}-${date.getMonth()}-${date.getDate()}` } function formatGroupLabel (timestamp: number, t: (key: string) => string, locale?: string) { const date = new Date(timestamp) const now = new Date() const yesterday = new Date(now) yesterday.setDate(now.getDate() - 1) if (isSameDay(date, now)) { return t('HISTORY_PANEL_TODAY') } if (isSameDay(date, yesterday)) { return t('HISTORY_PANEL_YESTERDAY') } return new Intl.DateTimeFormat(locale, { year: 'numeric', month: 'short', day: 'numeric' }).format(date) } function buildHistoryGroups ( items: DashboardHistoryItem[], t: (key: string) => string, locale?: string ): DashboardHistoryGroup[] { const groups: DashboardHistoryGroup[] = [] items.forEach((item) => { const key = buildGroupKey(item.timestamp) const lastGroup = groups[groups.length - 1] if (lastGroup?.key === key) { lastGroup.items.push(item) return } groups.push({ key, label: formatGroupLabel(item.timestamp, t, locale), items: [item] }) }) return groups } function buildVirtuosoResetKey (groups: DashboardHistoryGroup[], searchText: string) { const groupSignature = groups .map((group) => `${group.key}:${group.items.map((item) => item.id).join(',')}`) .join('|') return `${searchText}:${groupSignature}` } function buildHistoryEntries (groups: DashboardHistoryGroup[]): DashboardHistoryEntry[] { return groups.flatMap((group, groupIndex) => { const header: DashboardHistoryEntry = { type: 'header', key: `header:${group.key}`, label: group.label, isFirstGroup: groupIndex === 0 } const items = group.items.map((item): DashboardHistoryEntry => ({ type: 'item', key: `item:${item.id}`, item })) return [header, ...items] }) } function HistoryItemSkeleton () { return (