-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
7 changed files
with
252 additions
and
82 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
98 changes: 98 additions & 0 deletions
98
...src/components/molecules/menu-option-rotate-image-90/menu-option-rotate-image-90.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,98 @@ | ||
import { | ||
render, | ||
fireEvent, | ||
waitFor, | ||
act, | ||
screen | ||
} from "@testing-library/react"; | ||
import MenuOptionRotateImage90 from "./menu-option-rotate-image-90.tsx"; | ||
import { IDetailView } from "../../../interfaces/IDetailView.ts"; // for expect assertions | ||
|
||
describe("MenuOptionRotateImage90", () => { | ||
const mockState = { | ||
subPath: "/path/to/image.jpg", | ||
fileIndexItem: { | ||
fileHash: "abc123", | ||
filePath: "/path/to/image.jpg", | ||
orientation: "Horizontal" | ||
// Add any other necessary properties for your test case | ||
}, | ||
breadcrumb: {}, | ||
pageType: "detailView", | ||
colorClassUsage: [], | ||
relativeObjects: {}, | ||
colorClassActiveList: [], | ||
colorClassSelect: [], | ||
isReadOnly: false, | ||
dateCache: {} | ||
// Add any other necessary properties for your test case | ||
} as unknown as IDetailView; | ||
|
||
it("renders without crashing", () => { | ||
const container = render( | ||
<MenuOptionRotateImage90 | ||
state={mockState} | ||
setIsLoading={jest.fn()} | ||
dispatch={jest.fn()} | ||
isMarkedAsDeleted={false} | ||
isReadOnly={false} | ||
/> | ||
); | ||
expect(container.container).toBeTruthy(); | ||
|
||
container.unmount(); | ||
}); | ||
|
||
it("calls rotateImage90 function on click", async () => { | ||
const setIsLoadingMock = jest.fn(); | ||
const container = render( | ||
<MenuOptionRotateImage90 | ||
state={mockState} | ||
setIsLoading={setIsLoadingMock} | ||
dispatch={jest.fn()} | ||
isMarkedAsDeleted={false} | ||
isReadOnly={false} | ||
/> | ||
); | ||
|
||
fireEvent.click(container.getByTestId("rotate")); // Assuming you have "data-testid" attribute in your MenuOption component | ||
|
||
// You might need to wait for async operations to complete before asserting | ||
await waitFor(() => { | ||
expect(setIsLoadingMock).toHaveBeenCalledWith(true); | ||
// Add more assertions based on the expected behavior of your component | ||
}); | ||
}); | ||
|
||
it("handles timeouts correctly", async () => { | ||
const setIsLoadingMock = jest.fn(); | ||
|
||
const component = render( | ||
<MenuOptionRotateImage90 | ||
state={mockState} | ||
setIsLoading={setIsLoadingMock} | ||
dispatch={jest.fn()} | ||
isMarkedAsDeleted={false} | ||
isReadOnly={false} | ||
/> | ||
); | ||
|
||
fireEvent.click(screen.getByTestId("rotate")); | ||
|
||
// Manually advance the timer to the first setTimeout | ||
act(() => { | ||
jest.advanceTimersByTime(3000); | ||
}); | ||
|
||
expect(setIsLoadingMock).toHaveBeenCalled(); | ||
|
||
// Manually advance the timer to the second setTimeout | ||
act(() => { | ||
jest.advanceTimersByTime(7000); | ||
}); | ||
|
||
expect(setIsLoadingMock).toHaveBeenCalledWith(true); | ||
|
||
component.unmount(); | ||
}); | ||
}); |
28 changes: 28 additions & 0 deletions
28
.../components/molecules/menu-option-rotate-image-90/menu-option-rotate-image-90.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
import { Meta } from "@storybook/react"; | ||
import { action } from "@storybook/addon-actions"; | ||
import MenuOptionRotateImage90 from "./menu-option-rotate-image-90.tsx"; | ||
import { IDetailView } from "../../../interfaces/IDetailView.ts"; | ||
|
||
export default { | ||
component: MenuOptionRotateImage90, | ||
title: "Menu/MenuOptionRotateImage90", | ||
decorators: [ | ||
(Story) => ( | ||
<div style={{ padding: "20px", maxWidth: "300px" }}> | ||
<Story /> | ||
</div> | ||
) | ||
] | ||
} as Meta; | ||
|
||
const Template = () => ( | ||
<MenuOptionRotateImage90 | ||
state={{} as IDetailView} | ||
setIsLoading={action("setIsLoading")} | ||
dispatch={() => {}} | ||
isMarkedAsDeleted={false} | ||
isReadOnly={false} | ||
/> | ||
); | ||
|
||
export const Default = Template.bind({}); |
109 changes: 109 additions & 0 deletions
109
...tapp/src/components/molecules/menu-option-rotate-image-90/menu-option-rotate-image-90.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
import React, { Dispatch, memo } from "react"; | ||
import localization from "../../../localization/localization.json"; | ||
import FetchPost from "../../../shared/fetch-post"; | ||
import { UrlQuery } from "../../../shared/url-query"; | ||
import MenuOption from "../../atoms/menu-option/menu-option.tsx"; | ||
import FetchGet from "../../../shared/fetch-get.ts"; | ||
import { CastToInterface } from "../../../shared/cast-to-interface.ts"; | ||
import { Orientation } from "../../../interfaces/IFileIndexItem.ts"; | ||
import { IDetailView } from "../../../interfaces/IDetailView.ts"; | ||
import { DetailViewAction } from "../../../contexts/detailview-context.tsx"; | ||
|
||
interface IMenuOptionMenuOptionRotateImage90Props { | ||
state: IDetailView; | ||
setIsLoading: React.Dispatch<React.SetStateAction<boolean>>; | ||
dispatch: Dispatch<DetailViewAction>; | ||
isMarkedAsDeleted: boolean; | ||
isReadOnly: boolean; | ||
} | ||
|
||
/** | ||
* Used from DetailView | ||
*/ | ||
const MenuOptionRotateImage90: React.FunctionComponent<IMenuOptionMenuOptionRotateImage90Props> = | ||
memo(({ state, setIsLoading, dispatch, isMarkedAsDeleted, isReadOnly }) => { | ||
/** | ||
* Create body params to do url queries | ||
*/ | ||
function newBodyParams(): URLSearchParams { | ||
const bodyParams = new URLSearchParams(); | ||
bodyParams.set("f", state.subPath); | ||
return bodyParams; | ||
} | ||
|
||
/** | ||
* Checks if the hash is changes and update Context: orientation + fileHash | ||
*/ | ||
async function requestNewFileHash(): Promise<boolean | null> { | ||
const resultGet = await FetchGet( | ||
new UrlQuery().UrlIndexServerApi({ f: state.subPath }) | ||
); | ||
if (!resultGet) return null; | ||
if (resultGet.statusCode !== 200) { | ||
console.error(resultGet); | ||
setIsLoading(false); | ||
return null; | ||
} | ||
const media = new CastToInterface().MediaDetailView(resultGet.data).data; | ||
const orientation = media?.fileIndexItem?.orientation | ||
? media.fileIndexItem.orientation | ||
: Orientation.Horizontal; | ||
|
||
// the hash changes if you rotate an image | ||
if (media.fileIndexItem.fileHash === state.fileIndexItem.fileHash) | ||
return false; | ||
|
||
dispatch({ | ||
type: "update", | ||
orientation, | ||
fileHash: media.fileIndexItem.fileHash, | ||
filePath: media.fileIndexItem.filePath | ||
}); | ||
setIsLoading(false); | ||
return true; | ||
} | ||
|
||
/** | ||
* Update the rotation status | ||
*/ | ||
async function rotateImage90() { | ||
if (isMarkedAsDeleted || isReadOnly) return; | ||
setIsLoading(true); | ||
|
||
const bodyParams = newBodyParams(); | ||
bodyParams.set("rotateClock", "1"); | ||
const resultPost = await FetchPost( | ||
new UrlQuery().UrlUpdateApi(), | ||
bodyParams.toString() | ||
); | ||
if (resultPost.statusCode !== 200) { | ||
console.error(resultPost); | ||
return; | ||
} | ||
|
||
// there is an async backend event triggered, sometimes there is an que | ||
setTimeout(() => { | ||
requestNewFileHash().then((result) => { | ||
if (result === false) { | ||
setTimeout(() => { | ||
requestNewFileHash().then(() => { | ||
// when it didn't change after two tries | ||
setIsLoading(false); | ||
}); | ||
}, 7000); | ||
} | ||
}); | ||
}, 3000); | ||
} | ||
|
||
return ( | ||
<MenuOption | ||
isReadOnly={isReadOnly} | ||
onClickKeydown={rotateImage90} | ||
localization={localization.MessageRotateToRight} | ||
testName="rotate" | ||
/> | ||
); | ||
}); | ||
|
||
export default MenuOptionRotateImage90; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters