refactor(sns): use shared jump date popover

This commit is contained in:
aits2026
2026-03-06 15:30:10 +08:00
parent 21cb09fbde
commit 03f65317a9
3 changed files with 56 additions and 38 deletions

View File

@@ -1,7 +1,7 @@
import React from 'react' import React, { useEffect, useRef, useState } from 'react'
import { Search, Calendar, User, X, Loader2 } from 'lucide-react' import { Search, Calendar, User, X, Loader2 } from 'lucide-react'
import { Avatar } from '../Avatar' import { Avatar } from '../Avatar'
// import JumpToDateDialog from '../JumpToDateDialog' // Assuming this is imported from parent or moved import JumpToDatePopover from '../JumpToDatePopover'
interface Contact { interface Contact {
username: string username: string
@@ -22,7 +22,6 @@ interface SnsFilterPanelProps {
setSearchKeyword: (val: string) => void setSearchKeyword: (val: string) => void
jumpTargetDate?: Date jumpTargetDate?: Date
setJumpTargetDate: (date?: Date) => void setJumpTargetDate: (date?: Date) => void
onOpenJumpDialog: () => void
selectedUsernames: string[] selectedUsernames: string[]
setSelectedUsernames: (val: string[]) => void setSelectedUsernames: (val: string[]) => void
contacts: Contact[] contacts: Contact[]
@@ -37,7 +36,6 @@ export const SnsFilterPanel: React.FC<SnsFilterPanelProps> = ({
setSearchKeyword, setSearchKeyword,
jumpTargetDate, jumpTargetDate,
setJumpTargetDate, setJumpTargetDate,
onOpenJumpDialog,
selectedUsernames, selectedUsernames,
setSelectedUsernames, setSelectedUsernames,
contacts, contacts,
@@ -46,6 +44,19 @@ export const SnsFilterPanel: React.FC<SnsFilterPanelProps> = ({
loading, loading,
contactsCountProgress contactsCountProgress
}) => { }) => {
const [showJumpPopover, setShowJumpPopover] = useState(false)
const jumpCalendarWrapRef = useRef<HTMLDivElement | null>(null)
useEffect(() => {
if (!showJumpPopover) return
const handleClickOutside = (event: MouseEvent) => {
if (!jumpCalendarWrapRef.current) return
if (jumpCalendarWrapRef.current.contains(event.target as Node)) return
setShowJumpPopover(false)
}
document.addEventListener('mousedown', handleClickOutside)
return () => document.removeEventListener('mousedown', handleClickOutside)
}, [showJumpPopover])
const filteredContacts = contacts.filter(c => const filteredContacts = contacts.filter(c =>
(c.displayName || '').toLowerCase().includes(contactSearch.toLowerCase()) || (c.displayName || '').toLowerCase().includes(contactSearch.toLowerCase()) ||
@@ -116,27 +127,35 @@ export const SnsFilterPanel: React.FC<SnsFilterPanelProps> = ({
<Calendar size={14} /> <Calendar size={14} />
<span></span> <span></span>
</div> </div>
<button <div className="jump-calendar-anchor" ref={jumpCalendarWrapRef}>
className={`date-picker-trigger ${jumpTargetDate ? 'active' : ''}`} <button
onClick={onOpenJumpDialog} className={`date-picker-trigger ${jumpTargetDate ? 'active' : ''}`}
> onClick={() => setShowJumpPopover(prev => !prev)}
<span className="date-text"> >
{jumpTargetDate <span className="date-text">
? jumpTargetDate.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric' }) {jumpTargetDate
: '选择日期...'} ? jumpTargetDate.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric' })
</span> : '选择日期...'}
{jumpTargetDate && ( </span>
<div {jumpTargetDate && (
className="clear-date-btn" <div
onClick={(e) => { className="clear-date-btn"
e.stopPropagation() onClick={(e) => {
setJumpTargetDate(undefined) e.stopPropagation()
}} setJumpTargetDate(undefined)
> }}
<X size={12} /> >
</div> <X size={12} />
)} </div>
</button> )}
</button>
<JumpToDatePopover
isOpen={showJumpPopover}
currentDate={jumpTargetDate || new Date()}
onClose={() => setShowJumpPopover(false)}
onSelect={(date) => setJumpTargetDate(date)}
/>
</div>
</div> </div>
{/* Contact Widget */} {/* Contact Widget */}

View File

@@ -1063,6 +1063,18 @@
} }
/* Date Widget */ /* Date Widget */
.jump-calendar-anchor {
position: relative;
display: flex;
align-items: center;
isolation: isolate;
z-index: 20;
.jump-date-popover {
z-index: 2600;
}
}
.date-picker-trigger { .date-picker-trigger {
width: 100%; width: 100%;
display: flex; display: flex;

View File

@@ -1,6 +1,5 @@
import { useEffect, useLayoutEffect, useState, useRef, useCallback, useMemo } from 'react' import { useEffect, useLayoutEffect, useState, useRef, useCallback, useMemo } from 'react'
import { RefreshCw, Search, X, Download, FolderOpen, FileJson, FileText, Image, CheckCircle, AlertCircle, Calendar, Users, Info, ChevronLeft, ChevronRight, Shield, ShieldOff, Loader2 } from 'lucide-react' import { RefreshCw, Search, X, Download, FolderOpen, FileJson, FileText, Image, CheckCircle, AlertCircle, Calendar, Users, Info, ChevronLeft, ChevronRight, Shield, ShieldOff, Loader2 } from 'lucide-react'
import JumpToDateDialog from '../components/JumpToDateDialog'
import './SnsPage.scss' import './SnsPage.scss'
import { SnsPost } from '../types/sns' import { SnsPost } from '../types/sns'
import { SnsPostItem } from '../components/Sns/SnsPostItem' import { SnsPostItem } from '../components/Sns/SnsPostItem'
@@ -118,7 +117,6 @@ export default function SnsPage() {
}) })
// UI states // UI states
const [showJumpDialog, setShowJumpDialog] = useState(false)
const [debugPost, setDebugPost] = useState<SnsPost | null>(null) const [debugPost, setDebugPost] = useState<SnsPost | null>(null)
const [authorTimelineTarget, setAuthorTimelineTarget] = useState<ContactSnsTimelineTarget | null>(null) const [authorTimelineTarget, setAuthorTimelineTarget] = useState<ContactSnsTimelineTarget | null>(null)
@@ -1114,7 +1112,6 @@ export default function SnsPage() {
setSearchKeyword={setSearchKeyword} setSearchKeyword={setSearchKeyword}
jumpTargetDate={jumpTargetDate} jumpTargetDate={jumpTargetDate}
setJumpTargetDate={setJumpTargetDate} setJumpTargetDate={setJumpTargetDate}
onOpenJumpDialog={() => setShowJumpDialog(true)}
selectedUsernames={selectedUsernames} selectedUsernames={selectedUsernames}
setSelectedUsernames={setSelectedUsernames} setSelectedUsernames={setSelectedUsernames}
contacts={contacts} contacts={contacts}
@@ -1125,16 +1122,6 @@ export default function SnsPage() {
/> />
{/* Dialogs and Overlays */} {/* Dialogs and Overlays */}
<JumpToDateDialog
isOpen={showJumpDialog}
onClose={() => setShowJumpDialog(false)}
onSelect={(date) => {
setJumpTargetDate(date)
setShowJumpDialog(false)
}}
currentDate={jumpTargetDate || new Date()}
/>
<ContactSnsTimelineDialog <ContactSnsTimelineDialog
target={authorTimelineTarget} target={authorTimelineTarget}
onClose={closeAuthorTimeline} onClose={closeAuthorTimeline}