Compare commits
No commits in common. "d27546073fa6cac69f2be07c5fc1216fbc9af1e0" and "80717f0458a3774f92a1379d7126bb65c085fd89" have entirely different histories.
d27546073f
...
80717f0458
@ -72,7 +72,7 @@ export const FilelistView = ({ files, viewFile }) => {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
viewFile({
|
viewFile({
|
||||||
IsOpen: true,
|
IsOpen: true,
|
||||||
Image: files,
|
Image: file.preSignedUrl,
|
||||||
});
|
});
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@ -1,169 +1,80 @@
|
|||||||
import { useState, useRef, useEffect } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
const PreviewDocument = ({ files = [] }) => {
|
|
||||||
const images = Array.isArray(files) ? files : [files];
|
|
||||||
|
|
||||||
const [index, setIndex] = useState(0);
|
const PreviewDocument = ({ imageUrl }) => {
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [rotation, setRotation] = useState(0);
|
const [rotation, setRotation] = useState(0);
|
||||||
const [scale, setScale] = useState(1);
|
const [scale, setScale] = useState(1);
|
||||||
const [position, setPosition] = useState({ x: 0, y: 0 });
|
|
||||||
const [dragging, setDragging] = useState(false);
|
|
||||||
|
|
||||||
const startPos = useRef({ x: 0, y: 0 });
|
|
||||||
|
|
||||||
const MIN_ZOOM = 0.4;
|
|
||||||
const MAX_ZOOM = 3;
|
|
||||||
|
|
||||||
const currentImage = images[index];
|
|
||||||
|
|
||||||
// Reset on image change
|
|
||||||
useEffect(() => {
|
|
||||||
setRotation(0);
|
|
||||||
setScale(1);
|
|
||||||
setPosition({ x: 0, y: 0 });
|
|
||||||
setLoading(true);
|
|
||||||
}, [index]);
|
|
||||||
|
|
||||||
const zoomIn = () => setScale((prev) => Math.min(prev + 0.2, MAX_ZOOM));
|
|
||||||
const zoomOut = () => setScale((prev) => Math.max(prev - 0.2, MIN_ZOOM));
|
|
||||||
|
|
||||||
|
const zoomIn = () => setScale((prev) => Math.min(prev + 0.2, 3));
|
||||||
|
const zoomOut = () => setScale((prev) => Math.max(prev - 0.2, 0.4));
|
||||||
const resetAll = () => {
|
const resetAll = () => {
|
||||||
setRotation(0);
|
setRotation(0);
|
||||||
setScale(1);
|
setScale(1);
|
||||||
setPosition({ x: 0, y: 0 });
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const nextImage = () => {
|
|
||||||
if (index < images.length - 1) setIndex((i) => i + 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const prevImage = () => {
|
|
||||||
if (index > 0) setIndex((i) => i - 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleWheel = (e) => {
|
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
if (e.ctrlKey) {
|
|
||||||
const delta = e.deltaY > 0 ? -0.1 : 0.1;
|
|
||||||
setScale((prev) => {
|
|
||||||
let next = prev + delta;
|
|
||||||
if (next < MIN_ZOOM) next = MIN_ZOOM;
|
|
||||||
if (next > MAX_ZOOM) next = MAX_ZOOM;
|
|
||||||
return next;
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
if (e.deltaY > 0) nextImage();
|
|
||||||
else prevImage();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMouseDown = (e) => {
|
|
||||||
setDragging(true);
|
|
||||||
startPos.current = {
|
|
||||||
x: e.clientX - position.x,
|
|
||||||
y: e.clientY - position.y,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMouseMove = (e) => {
|
|
||||||
if (!dragging) return;
|
|
||||||
|
|
||||||
setPosition({
|
|
||||||
x: e.clientX - startPos.current.x,
|
|
||||||
y: e.clientY - startPos.current.y,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
const handleMouseUp = () => setDragging(false);
|
|
||||||
|
|
||||||
const handleDoubleClick = () => resetAll();
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{/* Top Controls */}
|
<div className="d-flex justify-content-start gap-3 mb-2">
|
||||||
<div className="d-flex justify-content-start align-items-center mb-2">
|
<i
|
||||||
{/* Left */}
|
className="bx bx-rotate-right cursor-pointer fs-4"
|
||||||
<div className="d-flex gap-3">
|
title="Rotate"
|
||||||
<i
|
onClick={() => setRotation((prev) => prev + 90)}
|
||||||
className="bx bx-rotate-right cursor-pointer fs-4"
|
></i>
|
||||||
onClick={() => setRotation((prev) => prev + 90)}
|
|
||||||
title="Rotate"
|
<i
|
||||||
/>
|
className="bx bx-zoom-in cursor-pointer fs-4"
|
||||||
<i
|
title="Zoom In"
|
||||||
className="bx bx-zoom-in cursor-pointer fs-4"
|
onClick={zoomIn}
|
||||||
onClick={zoomIn}
|
></i>
|
||||||
title="Zoom In"
|
|
||||||
/>
|
<i
|
||||||
<i
|
className="bx bx-zoom-out cursor-pointer fs-4"
|
||||||
className="bx bx-zoom-out cursor-pointer fs-4"
|
title="Zoom Out"
|
||||||
onClick={zoomOut}
|
onClick={zoomOut}
|
||||||
title="Zoom Out"
|
></i>
|
||||||
/>
|
|
||||||
<i
|
|
||||||
className="bx bx-reset cursor-pointer fs-4"
|
|
||||||
onClick={resetAll}
|
|
||||||
title="Reset"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
onWheel={handleWheel}
|
className="position-relative d-flex flex-column justify-content-center align-items-center overflow-hidden"
|
||||||
onMouseDown={handleMouseDown}
|
style={{ minHeight: "80vh" }}
|
||||||
onMouseMove={handleMouseMove}
|
|
||||||
onMouseUp={handleMouseUp}
|
|
||||||
onMouseLeave={handleMouseUp}
|
|
||||||
onDoubleClick={handleDoubleClick}
|
|
||||||
className="position-relative d-flex justify-content-center align-items-center bg-light-secondary overflow-hidden"
|
|
||||||
style={{
|
|
||||||
minHeight: "70vh",
|
|
||||||
userSelect: "none",
|
|
||||||
borderRadius: "10px",
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{loading && <div className="text-secondary">Loading...</div>}
|
{loading && (
|
||||||
|
<div className="text-secondary text-center mb-2">
|
||||||
|
Loading...
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<img
|
<div className="mb-3 d-flex justify-content-center align-items-center">
|
||||||
src={currentImage?.preSignedUrl}
|
<img
|
||||||
alt="Preview"
|
src={imageUrl}
|
||||||
draggable="false"
|
alt="Full View"
|
||||||
style={{
|
className="img-fluid"
|
||||||
maxHeight: "60vh",
|
style={{
|
||||||
display: loading ? "none" : "block",
|
maxHeight: "80vh",
|
||||||
transform: `
|
objectFit: "contain",
|
||||||
translate(${position.x}px, ${position.y}px)
|
display: loading ? "none" : "block",
|
||||||
scale(${scale})
|
transform: `rotate(${rotation}deg) scale(${scale})`,
|
||||||
rotate(${rotation}deg)
|
transition: "transform 0.3s ease",
|
||||||
`,
|
cursor: "grab",
|
||||||
transition: dragging ? "none" : "transform 0.2s ease",
|
}}
|
||||||
cursor: dragging ? "grabbing" : "grab",
|
onLoad={() => setLoading(false)}
|
||||||
}}
|
/>
|
||||||
onLoad={() => setLoading(false)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="d-flex justify-content-between">
|
|
||||||
<div className="text-center text-muted mt-2 small">
|
|
||||||
Scroll = change image | Double click = reset
|
|
||||||
</div>
|
</div>
|
||||||
<div className="d-flex align-items-center gap-2">
|
|
||||||
<i
|
<div className="position-absolute bottom-0 start-0 m-2">
|
||||||
className="bx bx-chevron-left cursor-pointer fs-4"
|
<button
|
||||||
onClick={prevImage}
|
className="btn btn-outline-secondary"
|
||||||
/>
|
onClick={resetAll}
|
||||||
<span>
|
>
|
||||||
{index + 1} / {images.length}
|
<i className="bx bx-reset"></i> Reset
|
||||||
</span>
|
</button>
|
||||||
<i
|
|
||||||
className="bx bx-chevron-right cursor-pointer fs-4"
|
|
||||||
onClick={nextImage}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export default PreviewDocument;
|
export default PreviewDocument;
|
||||||
|
|||||||
@ -393,7 +393,7 @@ const tdsPercentage = Number(watch("tdsPercentage")) || 0;
|
|||||||
if (isImage) {
|
if (isImage) {
|
||||||
setDocumentView({
|
setDocumentView({
|
||||||
IsOpen: true,
|
IsOpen: true,
|
||||||
Images: data?.documents,
|
Image: doc.preSignedUrl,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
|
|||||||
@ -51,6 +51,7 @@ const InputSuggestions = ({
|
|||||||
{filteredList.map((org) => (
|
{filteredList.map((org) => (
|
||||||
<li
|
<li
|
||||||
key={org}
|
key={org}
|
||||||
|
className="ropdown-item"
|
||||||
style={{
|
style={{
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
padding: "5px 12px",
|
padding: "5px 12px",
|
||||||
|
|||||||
@ -1,11 +0,0 @@
|
|||||||
import React from 'react'
|
|
||||||
|
|
||||||
const PurchaseList = () => {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export default PurchaseList
|
|
||||||
@ -62,7 +62,7 @@ const ExpensePage = () => {
|
|||||||
|
|
||||||
const [ViewDocument, setDocumentView] = useState({
|
const [ViewDocument, setDocumentView] = useState({
|
||||||
IsOpen: false,
|
IsOpen: false,
|
||||||
Images: null,
|
Image: null,
|
||||||
});
|
});
|
||||||
|
|
||||||
const IsCreatedAble = useHasUserPermission(CREATE_EXEPENSE);
|
const IsCreatedAble = useHasUserPermission(CREATE_EXEPENSE);
|
||||||
@ -208,10 +208,10 @@ const ExpensePage = () => {
|
|||||||
<GlobalModel
|
<GlobalModel
|
||||||
isOpen
|
isOpen
|
||||||
size="md"
|
size="md"
|
||||||
key={ViewDocument.Images ?? "doc"}
|
key={ViewDocument.Image ?? "doc"}
|
||||||
closeModal={() => setDocumentView({ IsOpen: false, Images: null })}
|
closeModal={() => setDocumentView({ IsOpen: false, Image: null })}
|
||||||
>
|
>
|
||||||
<PreviewDocument files={ViewDocument.Images} />
|
<PreviewDocument imageUrl={ViewDocument.Image} />
|
||||||
</GlobalModel>
|
</GlobalModel>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user