Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions components/ds/CropOverlayComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
"use client";
import { FollowingTooltipComponent } from "./FollowingTooltipComponent";

interface CropOverlayProps {
isCropping: boolean;
cropRect: { x: number; y: number; width: number; height: number } | null;
mousePosition: { x: number; y: number };
}

const CropOverlayComponent: React.FC<CropOverlayProps> = ({
isCropping,
cropRect,
mousePosition,
}) => {
if (!isCropping || !cropRect) return null;

const left = Math.min(cropRect.x, cropRect.x + cropRect.width);
const top = Math.min(cropRect.y, cropRect.y + cropRect.height);
const width = Math.abs(cropRect.width);
const height = Math.abs(cropRect.height);

return (
<>
<div
className="absolute border-2 border-dashed border-black bg-white bg-opacity-30 pointer-events-none"
style={{ left, top, width, height }}
></div>
<FollowingTooltipComponent
message="Double-click inside the overlay to accept"
position={mousePosition}
/>
</>
);
};

export { CropOverlayComponent };
16 changes: 16 additions & 0 deletions components/ds/DividerComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"use client";
interface DividerProps {
margin?: "small" | "medium" | "large";
}

const DividerComponent: React.FC<DividerProps> = ({ margin = "small" }) => {
const marginClasses = {
small: "my-2",
medium: "my-6",
large: "my-8",
};

return <div className={`bg-border h-[1px] ${marginClasses[margin]}`}></div>;
};

export { DividerComponent };
21 changes: 21 additions & 0 deletions components/ds/FollowingTooltipComponent.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
"use client";
interface TooltipProps {
message: string;
position: { x: number; y: number };
}

const FollowingTooltipComponent: React.FC<TooltipProps> = ({
message,
position,
}) => {
return (
<div
className="fixed px-2 py-1 bg-gray-800 text-white text-xs rounded shadow-lg"
style={{ left: position.x + 10, top: position.y - 30 }}
>
{message}
</div>
);
};

export { FollowingTooltipComponent };
85 changes: 81 additions & 4 deletions components/utils/resize-image.utils.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import {
calculateCropDimensions,
handleResizeImage,
isPointInCropRect,
processImageFile,
resizeImage,
updateHeight,
Expand Down Expand Up @@ -97,7 +99,7 @@ describe("Image Processing Functions", () => {
const setOutput = jest.fn();

processImageFile({
file: mockFile,
source: mockFile,
format: "jpeg",
preserveAspectRatio: true,
quality: 0.8,
Expand All @@ -121,7 +123,7 @@ describe("Image Processing Functions", () => {
});
const setWidth = jest.fn();

updateWidth({ file: mockFile, height: 200, setWidth });
updateWidth({ source: mockFile, height: 200, setWidth });

setTimeout(() => {
expect(setWidth).toHaveBeenCalledWith(400);
Expand All @@ -135,7 +137,7 @@ describe("Image Processing Functions", () => {
});
const setHeight = jest.fn();

updateHeight({ file: mockFile, width: 300, setHeight });
updateHeight({ source: mockFile, width: 300, setHeight });

setTimeout(() => {
expect(setHeight).toHaveBeenCalledWith(150);
Expand All @@ -150,7 +152,7 @@ describe("Image Processing Functions", () => {
const setOutput = jest.fn();

handleResizeImage({
file: mockFile,
source: mockFile,
format: "jpeg",
height: 400,
width: 600,
Expand All @@ -166,4 +168,79 @@ describe("Image Processing Functions", () => {
done();
}, 0);
});

it("should calculate the crop dimensions correctly", () => {
const imgMock = {
width: 1000,
height: 500,
} as HTMLImageElement;

const currentImageRefMock = {
clientWidth: 500,
clientHeight: 250,
} as HTMLImageElement;

const cropRect = { x: 50, y: 50, width: 100, height: 50 };

const result = calculateCropDimensions(
imgMock,
currentImageRefMock,
cropRect
);

expect(result).toEqual({
x: 100,
y: 100,
width: 200,
height: 100,
});
});

it("should handle negative width and height values in cropRect", () => {
const imgMock = {
width: 1000,
height: 500,
} as HTMLImageElement;

const currentImageRefMock = {
clientWidth: 500,
clientHeight: 250,
} as HTMLImageElement;

const cropRect = { x: 150, y: 150, width: -100, height: -50 };

const result = calculateCropDimensions(
imgMock,
currentImageRefMock,
cropRect
);

expect(result).toEqual({
x: 100,
y: 200,
width: 200,
height: 100,
});
});

const cropRect = { x: 50, y: 50, width: 100, height: 50 };

it("should return true for a point inside the crop rectangle", () => {
const result = isPointInCropRect(75, 75, cropRect);
expect(result).toBe(true);
});

it("should return false for a point outside the crop rectangle", () => {
const result = isPointInCropRect(200, 200, cropRect);
expect(result).toBe(false);
});

it("should handle negative width and height in crop rectangle", () => {
const cropRectNegative = { x: 150, y: 150, width: -100, height: -50 };
const result = isPointInCropRect(75, 75, cropRectNegative);
expect(result).toBe(false);

const resultInside = isPointInCropRect(125, 125, cropRectNegative);
expect(resultInside).toBe(true);
});
});
Loading