diff --git a/src/pages/tickets/TicketModalPage.tsx b/src/pages/tickets/TicketModalPage.tsx
index 6583bd63f..b061e07af 100644
--- a/src/pages/tickets/TicketModalPage.tsx
+++ b/src/pages/tickets/TicketModalPage.tsx
@@ -34,6 +34,8 @@ export const TicketModalPage = observer(({ setConnectPerson }: Props) => {
const [visible, setVisible] = useState(false);
const [isDeleted, setisDeleted] = useState(false);
const [accessDenied, setAccessDenied] = useState(false);
+ const [hidePrevArrow, setHidePrevArrow] = useState(false);
+ const [hideNextArrow, setHideNextArrow] = useState(false);
const [toasts, setToasts]: any = useState([]);
@@ -78,7 +80,7 @@ export const TicketModalPage = observer(({ setConnectPerson }: Props) => {
if (bountyId) {
const isNumeric = /^\d+$/.test(bountyId);
-
+
if (isNumeric) {
bounty = await main.getBountyById(Number(bountyId), unlockCode);
bountyIndex = await main.getBountyIndexById(Number(bountyId));
@@ -166,6 +168,11 @@ export const TicketModalPage = observer(({ setConnectPerson }: Props) => {
getBounty();
}, [getBounty, removeNextAndPrev]);
+ useEffect(() => {
+ setHidePrevArrow(false);
+ setHideNextArrow(false);
+ }, [bountyId, activeWorkspace]);
+
const isDirectAccess = useCallback(() => !document.referrer, [location.pathname]);
const goBack = () => {
@@ -188,6 +195,7 @@ export const TicketModalPage = observer(({ setConnectPerson }: Props) => {
try {
const bountyId = await main.getWorkspaceNextBountyByCreated(activeWorkspace, created);
if (bountyId === 0) {
+ setHidePrevArrow(true);
addToast('There are no more bounties to display!', 'primary');
} else {
history.replace(`/bounty/${bountyId}`);
@@ -198,7 +206,12 @@ export const TicketModalPage = observer(({ setConnectPerson }: Props) => {
} else {
try {
const bountyId = await main.getNextBountyByCreated(created);
- history.replace(`/bounty/${bountyId}`);
+ if (bountyId === 0) {
+ setHidePrevArrow(true);
+ addToast('There are no more bounties to display!', 'primary');
+ } else {
+ history.replace(`/bounty/${bountyId}`);
+ }
} catch (e) {
console.error(e);
}
@@ -212,6 +225,7 @@ export const TicketModalPage = observer(({ setConnectPerson }: Props) => {
try {
const bountyId = await main.getWorkspacePreviousBountyByCreated(activeWorkspace, created);
if (bountyId === 0) {
+ setHideNextArrow(true);
addToast('There are no more bounties to display!', 'primary');
} else {
history.replace(`/bounty/${bountyId}`);
@@ -222,7 +236,12 @@ export const TicketModalPage = observer(({ setConnectPerson }: Props) => {
} else {
try {
const bountyId = await main.getPreviousBountyByCreated(created);
- history.replace(`/bounty/${bountyId}`);
+ if (bountyId === 0) {
+ setHideNextArrow(true);
+ addToast('There are no more bounties to display!', 'primary');
+ } else {
+ history.replace(`/bounty/${bountyId}`);
+ }
} catch (e) {
console.error(e);
}
@@ -324,8 +343,8 @@ export const TicketModalPage = observer(({ setConnectPerson }: Props) => {
right: '-50px',
borderRadius: '50%'
}}
- prevArrowNew={removeNextAndPrev ? undefined : prevArrHandler}
- nextArrowNew={removeNextAndPrev ? undefined : nextArrHandler}
+ prevArrowNew={removeNextAndPrev || hidePrevArrow ? undefined : prevArrHandler}
+ nextArrowNew={removeNextAndPrev || hideNextArrow ? undefined : nextArrHandler}
>
() => {});
+// eslint-disable-next-line @typescript-eslint/no-empty-function
+jest.mock('rehype-raw', () => () => {});
+
jest.mock('hooks', () => ({
useIsMobile: jest.fn(),
useFeatureFlag: jest.fn().mockReturnValue({ isEnabled: true })
@@ -20,17 +27,20 @@ jest.mock('hooks', () => ({
const mockPush = jest.fn();
const mockGoBack = jest.fn();
+const mockReplace = jest.fn();
+let mockLocationState: any;
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useHistory: () => ({
push: mockPush,
- goBack: mockGoBack
+ goBack: mockGoBack,
+ replace: mockReplace
}),
useLocation: () => ({
pathname: '/bounty/1239',
search: '',
- state: {}
+ state: mockLocationState
}),
useParams: () => ({
uuid: 'ck95pe04nncjnaefo08g',
@@ -47,6 +57,11 @@ jest.mock('helpers', () => ({
describe('TicketModalPage Component', () => {
beforeEach(() => {
+ mockLocationState = undefined;
+ mainStore.setActiveWorkspace('');
+ fetchMock.doMock();
+ fetchMock.mockResponse(JSON.stringify([]));
+
const mockIntersectionObserver = jest.fn();
mockIntersectionObserver.mockReturnValue({
observe: () => null,
@@ -58,6 +73,9 @@ describe('TicketModalPage Component', () => {
afterEach(() => {
jest.clearAllMocks();
+ fetchMock.resetMocks();
+ fetchMock.dontMock();
+ mainStore.setActiveWorkspace('');
});
it('reder ticket modal', async () => {
@@ -811,6 +829,86 @@ describe('TicketModalPage Component', () => {
});
});
+ it('hides the public next arrow and keeps the user off the deleted bounty page at list end', async () => {
+ jest
+ .spyOn(mainStore, 'getBountyById')
+ .mockReturnValue(
+ Promise.resolve([
+ { ...newBounty, body: { ...mockBountiesMutated[1].body, assignee: user } }
+ ])
+ );
+ jest.spyOn(mainStore, 'getBountyIndexById').mockReturnValue(Promise.resolve(1239));
+ jest.spyOn(mainStore, 'getNextBountyByCreated').mockResolvedValueOnce(0);
+
+ await act(async () => {
+ render(
+
+
+
+ );
+ });
+
+ await waitFor(() => screen.getByText('chevron_left'));
+ fireEvent.click(screen.getByText('chevron_left'));
+
+ await waitFor(() => expect(screen.queryByText('chevron_left')).not.toBeInTheDocument());
+ expect(mockReplace).not.toHaveBeenCalledWith('/bounty/0');
+ expect(screen.getByText('There are no more bounties to display!')).toBeInTheDocument();
+ });
+
+ it('hides the workspace previous arrow and keeps the user off the deleted bounty page at list end', async () => {
+ mockLocationState = { activeWorkspace: 'workspace-uuid' };
+ jest
+ .spyOn(mainStore, 'getBountyById')
+ .mockReturnValue(
+ Promise.resolve([
+ { ...newBounty, body: { ...mockBountiesMutated[1].body, assignee: user } }
+ ])
+ );
+ jest.spyOn(mainStore, 'getBountyIndexById').mockReturnValue(Promise.resolve(1239));
+ jest.spyOn(mainStore, 'getWorkspacePreviousBountyByCreated').mockResolvedValueOnce(0);
+
+ await act(async () => {
+ render(
+
+
+
+ );
+ });
+
+ await waitFor(() => screen.getByText('chevron_right'));
+ fireEvent.click(screen.getByText('chevron_right'));
+
+ await waitFor(() => expect(screen.queryByText('chevron_right')).not.toBeInTheDocument());
+ expect(mockReplace).not.toHaveBeenCalledWith('/bounty/0');
+ expect(screen.getByText('There are no more bounties to display!')).toBeInTheDocument();
+ });
+
+ it('navigates to the exact public bounty returned by the L/R lookup', async () => {
+ jest
+ .spyOn(mainStore, 'getBountyById')
+ .mockReturnValue(
+ Promise.resolve([
+ { ...newBounty, body: { ...mockBountiesMutated[1].body, assignee: user } }
+ ])
+ );
+ jest.spyOn(mainStore, 'getBountyIndexById').mockReturnValue(Promise.resolve(1239));
+ jest.spyOn(mainStore, 'getPreviousBountyByCreated').mockResolvedValueOnce(5678);
+
+ await act(async () => {
+ render(
+
+
+
+ );
+ });
+
+ await waitFor(() => screen.getByText('chevron_right'));
+ fireEvent.click(screen.getByText('chevron_right'));
+
+ await waitFor(() => expect(mockReplace).toHaveBeenCalledWith('/bounty/5678'));
+ });
+
it('checks for enabled state of the delete button based on no assignment status', async () => {
uiStore.setMeInfo(user);
jest.spyOn(mainStore, 'getBountyById').mockReturnValue(