263 lines
12 KiB
TypeScript
263 lines
12 KiB
TypeScript
|
|
import React, { useEffect, useState } from 'react'
|
|
import { RootState } from '../../../../store/store';
|
|
import { useSelector } from 'react-redux';
|
|
import { DroppedItemsObj } from '../DocumentContainer';
|
|
import { MdKeyboardArrowUp, MdMoreVert } from 'react-icons/md';
|
|
import { PiTagSimpleFill } from 'react-icons/pi';
|
|
|
|
const DocumentPages: React.FC<{
|
|
isPages: boolean;
|
|
droppedItems: DroppedItemsObj;
|
|
setIsPages: React.Dispatch<React.SetStateAction<boolean>>;
|
|
}> = ({ isPages, droppedItems, setIsPages }) => {
|
|
|
|
type RecipientPageTagInfo = {
|
|
color: string;
|
|
recipientIndex: number;
|
|
recipientTagCount?: number;
|
|
};
|
|
|
|
type DocumentTagsMapping = {
|
|
[documentId: string]: {
|
|
[pageIndex: string]: RecipientPageTagInfo[];
|
|
};
|
|
};
|
|
|
|
const selectedDocuments = useSelector((state: RootState) => state.documents.documents)
|
|
const [documentPagesTagsMapping, setDocumentPagesTagsMapping] = useState<DocumentTagsMapping>({});
|
|
|
|
const recipients = useSelector((state: RootState) => state.selectedRecipients.recipients);
|
|
|
|
const [openDocs, setOpenDocs] = useState<Record<string, boolean>>(
|
|
() => Object.fromEntries(selectedDocuments.map((d, i) => [d.id, i === 0]))
|
|
)
|
|
const [activePage, setActivePage] = useState<string | null>(
|
|
selectedDocuments[0] ? `${selectedDocuments[0].id}_0` : null
|
|
)
|
|
|
|
const toggleDoc = (docId: string) => {
|
|
setOpenDocs(prev => ({ ...prev, [docId]: !prev[docId] }))
|
|
}
|
|
|
|
const goToPage = (docId: string, pageIndex: number) => {
|
|
const key = `${docId}_${pageIndex}`
|
|
setActivePage(key)
|
|
window.location.hash = docId + "" + pageIndex
|
|
}
|
|
|
|
// useEffect(() => {
|
|
// setTimeout(() => {
|
|
|
|
// let documentPagesTagsMappingLocal: {
|
|
// [documentId: string]: {
|
|
// [pageIndex: number]: [number, string];
|
|
// };
|
|
// }[] = [];
|
|
// recipients && recipients.length && recipients.forEach((selectedRecipient, selectedRecipientIndx) => {
|
|
// const selectedRecipientColor = selectedRecipient.color
|
|
|
|
// let activeRecipientTagsCount = 0;
|
|
|
|
// droppedItems && Object.keys(droppedItems).length > 0 && Object.keys(droppedItems).forEach(key => {
|
|
// activeRecipientTagsCount = (droppedItems[key] && droppedItems[key].length) > 0 ? droppedItems[key].reduce((acc, item) => !item.isDeleted && item.recipientIndx == selectedRecipientIndx ? acc + 1 : acc, 0) : 0;
|
|
|
|
// if (activeRecipientTagsCount == 0) return;
|
|
|
|
// const [documentId, pageIndex] = key.split("_");
|
|
|
|
// if (!documentPagesTagsMappingLocal[documentId]) {
|
|
// documentPagesTagsMappingLocal[documentId] = {};
|
|
// }
|
|
|
|
// documentPagesTagsMappingLocal.push({ [documentId]: { [pageIndex]: [activeRecipientTagsCount, selectedRecipientColor] } })
|
|
// })
|
|
// })
|
|
|
|
// setDocumentPagesTagsMapping(documentPagesTagsMappingLocal)
|
|
// }, 300)
|
|
// // }, [droppedItems, selectedRecipientIndx])
|
|
// }, [droppedItems])
|
|
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
setTimeout(() => {
|
|
|
|
let documentTagsMappingLocal: DocumentTagsMapping = {};
|
|
|
|
recipients &&
|
|
recipients.length &&
|
|
recipients.forEach((selectedRecipient, selectedRecipientIndx) => {
|
|
|
|
const selectedRecipientColor = selectedRecipient.color;
|
|
|
|
droppedItems &&
|
|
Object.keys(droppedItems).length > 0 &&
|
|
Object.keys(droppedItems).forEach(key => {
|
|
|
|
const activeRecipientTagsCount =
|
|
(droppedItems[key] && droppedItems[key].length) > 0
|
|
? droppedItems[key].reduce((acc, item) => {
|
|
return !item.isDeleted &&
|
|
item.recipientIndx == selectedRecipientIndx
|
|
? acc + 1
|
|
: acc;
|
|
}, 0)
|
|
: 0;
|
|
|
|
if (activeRecipientTagsCount === 0) return;
|
|
|
|
const [documentId, pageIndex] = key.split("_");
|
|
|
|
// Create document object
|
|
if (!documentTagsMappingLocal[documentId]) {
|
|
documentTagsMappingLocal[documentId] = {};
|
|
}
|
|
|
|
// Create page array
|
|
if (!documentTagsMappingLocal[documentId][pageIndex]) {
|
|
documentTagsMappingLocal[documentId][pageIndex] = [];
|
|
}
|
|
|
|
// Push recipient info
|
|
documentTagsMappingLocal[documentId][pageIndex].push({
|
|
color: selectedRecipientColor,
|
|
recipientIndex: selectedRecipientIndx,
|
|
recipientTagCount: activeRecipientTagsCount,
|
|
});
|
|
});
|
|
});
|
|
|
|
setDocumentPagesTagsMapping(documentTagsMappingLocal);
|
|
|
|
}, 300);
|
|
|
|
}, [droppedItems]);
|
|
|
|
useEffect(() => {
|
|
setTimeout(() => {
|
|
if (!isPages) return
|
|
const docPagesCon = document.getElementById("document-pages");
|
|
|
|
if (docPagesCon) {
|
|
docPagesCon.focus();
|
|
}
|
|
}, 0)
|
|
}, [isPages]);
|
|
|
|
return (
|
|
<div id='document-pages'
|
|
tabIndex={-1}
|
|
onBlur={() => window.innerWidth <= 638 && setIsPages(false)}
|
|
className={`h-[100vh] absolute ${isPages || window.innerWidth > 638 ? "" : "hidden"} top-0 left-0 sm:static max-w-max bg-slate-100 z-50 sm:col-span-2 flex flex-col w-full overflow-y-auto`}>
|
|
{selectedDocuments.map((document, indx) => (
|
|
<div key={indx} className="border-b border-slate-200 pb-3 mb-1">
|
|
|
|
{/* Section label (if any) */}
|
|
{document.section && (
|
|
<p className="text-[10px] font-semibold uppercase tracking-wide text-slate-400 px-3 pt-2 pb-1">
|
|
{document.section}
|
|
</p>
|
|
)}
|
|
|
|
{/* Document Header */}
|
|
<div
|
|
onClick={() => toggleDoc(document.id)}
|
|
className="flex items-start justify-between px-3 py-2.5 cursor-pointer hover:bg-slate-50 transition-colors"
|
|
>
|
|
<div>
|
|
<p className="text-[13px] font-medium text-slate-800 leading-tight">{document.name}</p>
|
|
<p className="text-[11px] text-slate-400 mt-0.5">
|
|
{document.pages?.length} {document.pages?.length === 1 ? 'page' : 'pages'}
|
|
</p>
|
|
</div>
|
|
<MdKeyboardArrowUp
|
|
size={20}
|
|
className={`text-slate-400 mt-0.5 flex-shrink-0 transition-transform duration-200 ${openDocs[document.id] ? '' : 'rotate-180'}`}
|
|
/>
|
|
</div>
|
|
|
|
{/* Page Thumbnails */}
|
|
{openDocs[document.id] && (
|
|
<div className="flex flex-col px-2">
|
|
{document.pages?.map((_: any, pageIndex: number) => {
|
|
const key = `${document.id}_${pageIndex}`
|
|
const isActive = activePage === key
|
|
|
|
return (
|
|
<div
|
|
key={pageIndex}
|
|
onClick={() => goToPage(document.id, pageIndex)}
|
|
className="flex flex-col items-center py-2 px-1 rounded-md cursor-pointer hover:bg-slate-50 transition-colors"
|
|
>
|
|
{/* Big Thumbnail */}
|
|
<div className={`relative sm:p-2 lg:p-4 bg-slate-100 rounded border flex items-center justify-center overflow-hidden
|
|
${isActive ? 'border-blue-500 border-2' : 'border-slate-200'}`}
|
|
>
|
|
{document.thumbnail ? (
|
|
<img
|
|
src={"data:image/png;base64," + document.thumbnail}
|
|
alt={`Page ${pageIndex + 1}`}
|
|
className="w-[140px] h-[180px] h-full object-cover"
|
|
/>
|
|
) : (
|
|
<div className="text-slate-300 text-4xl">Document</div>
|
|
)}
|
|
|
|
{/* Page number + dots menu */}
|
|
<div className="absolute bottom-0 bg-slate-800 flex items-center justify-between w-full pl-4 pr-2 py-3 bg-white">
|
|
<span className="text-[13px] text-slate-500">{pageIndex + 1}</span>
|
|
{
|
|
// <>
|
|
// <button
|
|
// onClick={(e) => { e.stopPropagation(); /* open context menu */ }}
|
|
// className="text-slate-400 hover:text-slate-600 hover:bg-slate-100 rounded p-0.5"
|
|
// >
|
|
// <MdMoreVert size={18} />
|
|
// </button>
|
|
// </>
|
|
}
|
|
</div>
|
|
|
|
<div className='absolute top-4 left-2 h-[80%] overflow-y-auto overflow-x-hidden'>
|
|
{documentPagesTagsMapping[document.id]?.[pageIndex]?.length > 0 && (
|
|
<>
|
|
{documentPagesTagsMapping[document.id][pageIndex].map((tagInfo, indx) => (
|
|
<div key={indx} className='relative'>
|
|
|
|
{/* Count */}
|
|
{/* Optional */}
|
|
{/* <span className='absolute text-white text-[9px] font-medium top-[50%] left-[50%] transform -translate-x-1/2 -translate-y-1/2 pointer-events-none select-none z-10'>
|
|
{tagInfo.recipientTagCount}
|
|
</span> */}
|
|
|
|
{/* Tag */}
|
|
<PiTagSimpleFill
|
|
style={{
|
|
fontSize: '1.2rem',
|
|
color: tagInfo.color,
|
|
}}
|
|
/>
|
|
</div>
|
|
))}
|
|
</>
|
|
)}
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
</div>
|
|
)
|
|
})}
|
|
</div>
|
|
)}
|
|
</div>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export default DocumentPages |