Drill Downs
This package provides reusable components and hooks for implementing drill-down modal functionality across different applications.
Purpose
The primary goal is to centralize and standardize drill-down modal components and logic into a shared package.
Architecture
This package follows a registry pattern where:
- The
DrillDownRegistryProvidermanages modal instances - Individual drill-down hooks register themselves with the registry
- Applications call specific drill-down hooks to open modals
Basic Setup
Wrap your application with the DrillDownRegistryProvider to enable drill-down functionality:
import { DrillDownRegistryProvider } from '@shared/drill-downs';
function App() {
return (
<DrillDownRegistryProvider enabled={true}>
{/* Your app content */}
</DrillDownRegistryProvider>
);
}
Using Existing Drill-Downs
The package includes several pre-built drill-down modals that you can use out of the box:
- Conversations - For displaying conversation details and history
Example: Using Conversations Drill-Down
import { useConversationsDrillDownModal } from '@shared/drill-downs';
function Dashboard() {
const { openModal } = useConversationsDrillDownModal({
fetcher: async ({ page, total }, payload) => {
// Implementation to fetch conversation IDs
return {
data: ids,
pagination: { page, perPage: 50, total },
};
}
});
const handleViewConversations = (filterData) => {
openModal({
title: 'Conversations',
subtitle: 'Last 30 days',
description: 'All conversations for selected timeframe',
total: 42,
queryKey: ['unique', 'conversations', 'key'],
filters: filterData.filters,
});
};
return (
<button onClick={handleViewConversations}>View Conversations</button>
);
}
Implementing new modals
To create your own custom drill-down modal:
- Create a modal component:
// src/modals/YourModal/index.tsx
import { useDrillDownModal } from '../../context/ModalRegistry';
import { DrillDownModal } from '../../components/Modal';
type YourModalProps = {
isOpen: boolean;
close: () => void;
payload?: {
title: string;
subtitle: string;
data: any[];
// any other data needed by your modal
};
};
function YourModal({ isOpen, close, payload }: YourModalProps) {
return (
<DrillDownModal
title={payload?.title || 'Default Title'}
subtitle={payload?.subtitle}
isOpen={isOpen}
close={close}
>
{/* Your modal content */}
{payload?.data.map(item => (
<div key={item.id}>{item.name}</div>
))}
</DrillDownModal>
);
}
// Create a hook for using this modal
export function useYourDrillDownModal() {
return useDrillDownModal({
render: ({ isOpen, close, payload }) => (
<YourModal
isOpen={isOpen}
close={close}
payload={payload}
/>
),
});
}
- Use your custom modal hook:
import { useYourDrillDownModal } from '@shared/drill-downs/src/modals/YourModal';
function YourComponent() {
const { openModal } = useYourDrillDownModal();
const handleOpenModal = () => {
openModal({
title: 'Your Modal Title',
subtitle: 'Additional information',
data: [{ id: 1, name: 'Item 1' }],
});
};
return <button onClick={handleOpenModal}>Open Modal</button>;
}
- Use data fetching utilities (optional):
For modals that need data fetching with pagination, use the useDrillDownData utility:
import { useDrillDownData } from '../../utils/useFetcher';
function YourModal({ isOpen, close, payload }) {
const {
isLoading,
flatData,
fetchNextPage,
hasNextPage
} = useDrillDownData({
fetcher: payload?.fetcher,
fetcherPayload: payload?.fetcherPayload,
queryKey: payload?.queryKey || [],
total: payload?.total || 0,
enabled: isOpen,
});
return (
<DrillDownModal
title={payload?.title}
isOpen={isOpen}
close={close}
onScrollToEnd={fetchNextPage}
>
{isLoading ? (
<LoadingState />
) : (
<YourDataList data={flatData} />
)}
{hasNextPage && <LoadingMore />}
</DrillDownModal>
);
}
- Export your hook from the package (in
src/index.ts):
// src/index.ts
// ...existing exports
export { useYourDrillDownModal } from './modals/YourModal';