mirror of
https://dev.azure.com/globalhealthx/EMR/_git/helix-engage
synced 2026-04-11 18:28:15 +00:00
feat: add exit animations on lead cards and cross-page filter continuity
- Wrap lead cards in AnimatePresence/motion.div so they fade+slide out when removed from the NEW filter - Update "View All" link to pass active source filter as ?source= URL param - Initialize AllLeadsPage sourceFilter from URL search params on mount Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { useMemo, useState } from 'react';
|
||||
import { useSearchParams } from 'react-router';
|
||||
import { ArrowLeft, Download01, FilterLines, SearchLg, SwitchVertical01 } from '@untitledui/icons';
|
||||
import { Button } from '@/components/base/buttons/button';
|
||||
import { Input } from '@/components/base/input/input';
|
||||
@@ -29,11 +30,13 @@ const PAGE_SIZE = 25;
|
||||
|
||||
export const AllLeadsPage = () => {
|
||||
const { user } = useAuth();
|
||||
const [searchParams] = useSearchParams();
|
||||
const initialSource = searchParams.get('source') as LeadSource | null;
|
||||
const [tab, setTab] = useState<TabKey>('new');
|
||||
const [selectedIds, setSelectedIds] = useState<string[]>([]);
|
||||
const [sortField, setSortField] = useState('createdAt');
|
||||
const [sortDirection, setSortDirection] = useState<'asc' | 'desc'>('desc');
|
||||
const [sourceFilter, setSourceFilter] = useState<LeadSource | null>(null);
|
||||
const [sourceFilter, setSourceFilter] = useState<LeadSource | null>(initialSource);
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
const [currentPage, setCurrentPage] = useState(1);
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { useState } from 'react';
|
||||
import { AnimatePresence, motion } from 'motion/react';
|
||||
|
||||
import { Button } from '@/components/base/buttons/button';
|
||||
import { TopBar } from '@/components/layout/top-bar';
|
||||
@@ -81,23 +82,35 @@ export const LeadWorkspacePage = () => {
|
||||
<div>
|
||||
<div className="mb-3.5 flex items-center justify-between">
|
||||
<h2 className="font-display text-md font-bold text-primary">New Leads</h2>
|
||||
<Button href="/leads" color="link-color" size="sm">
|
||||
View All {total} Leads
|
||||
<Button
|
||||
href={sourceFilter ? `/leads?source=${sourceFilter}` : '/leads'}
|
||||
color="link-color"
|
||||
size="sm"
|
||||
>
|
||||
View All {total} Leads →
|
||||
</Button>
|
||||
</div>
|
||||
<div className="space-y-2">
|
||||
{displayLeads.map((lead) => (
|
||||
<LeadCard
|
||||
key={lead.id}
|
||||
lead={lead}
|
||||
onAssign={handleAssign}
|
||||
onMessage={handleMessage}
|
||||
onMarkSpam={handleMarkSpam}
|
||||
onMerge={handleMerge}
|
||||
onLogCall={handleLogCall}
|
||||
onUpdateStatus={handleUpdateStatus}
|
||||
/>
|
||||
))}
|
||||
<AnimatePresence>
|
||||
{displayLeads.map((lead) => (
|
||||
<motion.div
|
||||
key={lead.id}
|
||||
initial={{ opacity: 1, x: 0 }}
|
||||
exit={{ opacity: 0, x: -20, height: 0, marginBottom: 0 }}
|
||||
transition={{ duration: 0.3 }}
|
||||
>
|
||||
<LeadCard
|
||||
lead={lead}
|
||||
onAssign={handleAssign}
|
||||
onMessage={handleMessage}
|
||||
onMarkSpam={handleMarkSpam}
|
||||
onMerge={handleMerge}
|
||||
onLogCall={handleLogCall}
|
||||
onUpdateStatus={handleUpdateStatus}
|
||||
/>
|
||||
</motion.div>
|
||||
))}
|
||||
</AnimatePresence>
|
||||
{displayLeads.length === 0 && (
|
||||
<p className="py-8 text-center text-sm text-tertiary">
|
||||
No leads match the current filters.
|
||||
|
||||
Reference in New Issue
Block a user