Skip to content
82 changes: 82 additions & 0 deletions src/actions/__tests__/form-template-actions.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { createStore, combineReducers, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import flushPromises from "flush-promises";
import {
putRequest,
getRequest
} from "openstack-uicore-foundation/lib/utils/actions";
import {
archiveFormTemplate,
RECEIVE_FORM_TEMPLATES
} from "../form-template-actions";
import formTemplateListReducer from "../../reducers/sponsors_inventory/form-template-list-reducer";
import * as methods from "../../utils/methods";

jest.mock("openstack-uicore-foundation/lib/utils/actions", () => ({
__esModule: true,
...jest.requireActual("openstack-uicore-foundation/lib/utils/actions"),
putRequest: jest.fn(),
getRequest: jest.fn()
}));

describe("archiveFormTemplate", () => {
beforeEach(() => {
window.INVENTORY_API_BASE_URL = "http://test-api";
jest.spyOn(methods, "getAccessTokenSafely").mockReturnValue("TOKEN");

putRequest.mockImplementation(
(nullArg, receiveActionCreator) => () => (dispatch) => {
dispatch(
receiveActionCreator({ response: { id: 21, is_archived: true } })
);
return Promise.resolve({ response: { id: 21, is_archived: true } });
}
);

getRequest.mockImplementation(
() => () => () => Promise.resolve({ response: {} })
);
});

afterEach(() => {
jest.restoreAllMocks();
});

it("refetches the corrected page after archiving the last item on the last page", async () => {
// Real store so the reducer runs and getState() reflects the corrected page
const store = createStore(
combineReducers({
currentFormTemplateListState: formTemplateListReducer
}),
applyMiddleware(thunk)
);

// Land on page 3 with 21 items (1 item on page 3, 10 per page)
store.dispatch({
type: RECEIVE_FORM_TEMPLATES,
payload: {
response: {
data: [{ id: 21, is_archived: false, items: [] }],
total: 21,
last_page: 3,
current_page: 3
}
}
});

await store.dispatch(archiveFormTemplate({ id: 21 }));
await flushPromises();

// Reducer corrects page 3 → 2 after FORM_TEMPLATE_ARCHIVED
expect(store.getState().currentFormTemplateListState.currentPage).toBe(2);

// getFormTemplates must refetch page 2, not the stale page 3
expect(getRequest).toHaveBeenCalledWith(
expect.any(Function),
expect.any(Function),
"http://test-api/api/v1/form-templates",
expect.any(Function),
expect.objectContaining({ page: 2 })
);
});
});
50 changes: 38 additions & 12 deletions src/actions/form-template-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -325,18 +325,44 @@ export const deleteFormTemplateMaterial = (templateId, materialId) => {

/* ************************************** ARCHIVE ************************************** */

export const archiveFormTemplate = (formTemplate) => {
const settings = {
url: `${window.INVENTORY_API_BASE_URL}/api/v1/form-templates/${formTemplate.id}/archive`,
updatedActionName: FORM_TEMPLATE_ARCHIVED
export const archiveFormTemplate =
(formTemplate) => async (dispatch, getState) => {
const settings = {
url: `${window.INVENTORY_API_BASE_URL}/api/v1/form-templates/${formTemplate.id}/archive`,
updatedActionName: FORM_TEMPLATE_ARCHIVED
};
await archiveItem(formTemplate, settings)(dispatch);
const { term, currentPage, perPage, order, orderDir, showArchived } =
getState().currentFormTemplateListState;
dispatch(
getFormTemplates(
term,
currentPage,
perPage,
order,
orderDir,
showArchived
)
);
};
return archiveItem(formTemplate, settings);
};

export const unarchiveFormTemplate = (formTemplate) => {
const settings = {
url: `${window.INVENTORY_API_BASE_URL}/api/v1/form-templates/${formTemplate.id}/archive`,
deletedActionName: FORM_TEMPLATE_UNARCHIVED
export const unarchiveFormTemplate =
(formTemplate) => async (dispatch, getState) => {
const settings = {
url: `${window.INVENTORY_API_BASE_URL}/api/v1/form-templates/${formTemplate.id}/archive`,
deletedActionName: FORM_TEMPLATE_UNARCHIVED
};
await unarchiveItem(formTemplate, settings)(dispatch);
const { term, currentPage, perPage, order, orderDir, showArchived } =
getState().currentFormTemplateListState;
dispatch(
getFormTemplates(
term,
currentPage,
perPage,
order,
orderDir,
showArchived
)
);
};
return unarchiveItem(formTemplate, settings);
};
52 changes: 40 additions & 12 deletions src/actions/form-template-item-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -393,18 +393,46 @@ export const deleteItemImage = (

/* ************************************** ARCHIVE ************************************** */

export const archiveFormTemplateItem = (formTemplateId, formTemplateItem) => {
const settings = {
url: `${window.INVENTORY_API_BASE_URL}/api/v1/form-templates/${formTemplateId}/items/${formTemplateItem.id}/archive`,
updatedActionName: FORM_TEMPLATE_ITEM_ARCHIVED
export const archiveFormTemplateItem =
(formTemplateId, formTemplateItem) => async (dispatch, getState) => {
const settings = {
url: `${window.INVENTORY_API_BASE_URL}/api/v1/form-templates/${formTemplateId}/items/${formTemplateItem.id}/archive`,
updatedActionName: FORM_TEMPLATE_ITEM_ARCHIVED
};
await archiveItem(formTemplateItem, settings)(dispatch);
const { term, currentPage, perPage, order, orderDir, showArchived } =
getState().currentFormTemplateItemListState;
dispatch(
getFormTemplateItems(
formTemplateId,
term,
currentPage,
perPage,
order,
orderDir,
showArchived
)
);
};
return archiveItem(formTemplateItem, settings);
};

export const unarchiveFormTemplateItem = (formTemplateId, formTemplateItem) => {
const settings = {
url: `${window.INVENTORY_API_BASE_URL}/api/v1/form-templates/${formTemplateId}/items/${formTemplateItem.id}/archive`,
deletedActionName: FORM_TEMPLATE_ITEM_UNARCHIVED
export const unarchiveFormTemplateItem =
(formTemplateId, formTemplateItem) => async (dispatch, getState) => {
const settings = {
url: `${window.INVENTORY_API_BASE_URL}/api/v1/form-templates/${formTemplateId}/items/${formTemplateItem.id}/archive`,
deletedActionName: FORM_TEMPLATE_ITEM_UNARCHIVED
};
await unarchiveItem(formTemplateItem, settings)(dispatch);
const { term, currentPage, perPage, order, orderDir, showArchived } =
getState().currentFormTemplateItemListState;
dispatch(
getFormTemplateItems(
formTemplateId,
term,
currentPage,
perPage,
order,
orderDir,
showArchived
)
);
};
return unarchiveItem(formTemplateItem, settings);
};
50 changes: 38 additions & 12 deletions src/actions/inventory-item-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -370,18 +370,44 @@ export const deleteInventoryItemImage = (inventoryItemId, imageId) => {

/* ************************************** ARCHIVE ************************************** */

export const archiveInventoryItem = (inventoryItem) => {
const settings = {
url: `${window.INVENTORY_API_BASE_URL}/api/v1/inventory-items/${inventoryItem.id}/archive`,
updatedActionName: INVENTORY_ITEM_ARCHIVED
export const archiveInventoryItem =
(inventoryItem) => async (dispatch, getState) => {
const settings = {
url: `${window.INVENTORY_API_BASE_URL}/api/v1/inventory-items/${inventoryItem.id}/archive`,
updatedActionName: INVENTORY_ITEM_ARCHIVED
};
await archiveItem(inventoryItem, settings)(dispatch);
const { term, currentPage, perPage, order, orderDir, showArchived } =
getState().currentInventoryItemListState;
dispatch(
getInventoryItems(
term,
currentPage,
perPage,
order,
orderDir,
showArchived
)
);
};
return archiveItem(inventoryItem, settings);
};

export const unarchiveInventoryItem = (inventoryItem) => {
const settings = {
url: `${window.INVENTORY_API_BASE_URL}/api/v1/inventory-items/${inventoryItem.id}/archive`,
deletedActionName: INVENTORY_ITEM_UNARCHIVED
export const unarchiveInventoryItem =
(inventoryItem) => async (dispatch, getState) => {
const settings = {
url: `${window.INVENTORY_API_BASE_URL}/api/v1/inventory-items/${inventoryItem.id}/archive`,
deletedActionName: INVENTORY_ITEM_UNARCHIVED
};
await unarchiveItem(inventoryItem, settings)(dispatch);
const { term, currentPage, perPage, order, orderDir, showArchived } =
getState().currentInventoryItemListState;
dispatch(
getInventoryItems(
term,
currentPage,
perPage,
order,
orderDir,
showArchived
)
);
};
return unarchiveItem(inventoryItem, settings);
};
75 changes: 50 additions & 25 deletions src/actions/page-template-actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -211,35 +211,60 @@ export const savePageTemplate = (entity) => async (dispatch) => {

/* ************************************** ARCHIVE ************************************** */

export const archivePageTemplate = (pageTemplateId) => async (dispatch) => {
const accessToken = await getAccessTokenSafely();
const params = { access_token: accessToken };

return putRequest(
null,
createAction(PAGE_TEMPLATE_ARCHIVED),
`${window.SPONSOR_PAGES_API_URL}/api/v1/page-templates/${pageTemplateId}/archive`,
null,
snackbarErrorHandler
)(params)(dispatch);
};
export const archivePageTemplate =
(pageTemplateId) => async (dispatch, getState) => {
const accessToken = await getAccessTokenSafely();
const params = { access_token: accessToken };

await putRequest(
null,
createAction(PAGE_TEMPLATE_ARCHIVED),
`${window.SPONSOR_PAGES_API_URL}/api/v1/page-templates/${pageTemplateId}/archive`,
null,
snackbarErrorHandler
)(params)(dispatch);
const { term, currentPage, perPage, order, orderDir, showArchived } =
getState().pageTemplateListState;
dispatch(
getPageTemplates(
term,
currentPage,
perPage,
order,
orderDir,
showArchived
)
);
};

export const unarchivePageTemplate = (pageTemplateId) => async (dispatch) => {
const accessToken = await getAccessTokenSafely();
const params = { access_token: accessToken };
export const unarchivePageTemplate =
(pageTemplateId) => async (dispatch, getState) => {
const accessToken = await getAccessTokenSafely();
const params = { access_token: accessToken };

dispatch(startLoading());
dispatch(startLoading());

return deleteRequest(
null,
createAction(PAGE_TEMPLATE_UNARCHIVED)({ pageTemplateId }),
`${window.SPONSOR_PAGES_API_URL}/api/v1/page-templates/${pageTemplateId}/archive`,
null,
snackbarErrorHandler
)(params)(dispatch).then(() => {
await deleteRequest(
null,
createAction(PAGE_TEMPLATE_UNARCHIVED)({ pageTemplateId }),
`${window.SPONSOR_PAGES_API_URL}/api/v1/page-templates/${pageTemplateId}/archive`,
null,
snackbarErrorHandler
)(params)(dispatch);
dispatch(stopLoading());
});
};
const { term, currentPage, perPage, order, orderDir, showArchived } =
getState().pageTemplateListState;
dispatch(
getPageTemplates(
term,
currentPage,
perPage,
order,
orderDir,
showArchived
)
);
};

export const clonePageTemplate = (templateId) => async (dispatch) => {
const accessToken = await getAccessTokenSafely();
Expand Down
Loading
Loading