Skip to content

Commit

Permalink
feat: inventory item crud pages (WIP)
Browse files Browse the repository at this point in the history
  • Loading branch information
romanetar committed Dec 16, 2024
1 parent 0d6d1b4 commit b1e30a0
Show file tree
Hide file tree
Showing 15 changed files with 1,013 additions and 8 deletions.
4 changes: 3 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,16 @@ REPORT_API_BASE_URL=
MARKETING_API_BASE_URL=
EMAIL_API_BASE_URL=
FILE_UPLOAD_API_BASE_URL=
INVENTORY_API_BASE_URL=
SIGNAGE_BASE_URL=
PRINT_APP_URL=https://badge-print-app.dev.fnopen.com
PUB_API_BASE_URL=
OS_BASE_URL=
SCOPES_BASE_REALM=${API_BASE_URL}
EMAIL_SCOPES="clients/read templates/read templates/write emails/read"
FILE_UPLOAD_SCOPES="files/upload"
SCOPES="profile openid offline_access ${EMAIL_SCOPES} ${FILE_UPLOAD_SCOPES} ${SCOPES_BASE_REALM}/summits/delete-event ${SCOPES_BASE_REALM}/summits/write ${SCOPES_BASE_REALM}/summits/write-event ${SCOPES_BASE_REALM}/summits/read/all ${SCOPES_BASE_REALM}/summits/read ${SCOPES_BASE_REALM}/summits/publish-event ${SCOPES_BASE_REALM}/members/read ${SCOPES_BASE_REALM}/members/read/me ${SCOPES_BASE_REALM}/speakers/write ${SCOPES_BASE_REALM}/attendees/write ${SCOPES_BASE_REALM}/members/write ${SCOPES_BASE_REALM}/organizations/write ${SCOPES_BASE_REALM}/organizations/read ${SCOPES_BASE_REALM}/summits/write-presentation-materials ${SCOPES_BASE_REALM}/summits/registration-orders/update ${SCOPES_BASE_REALM}/summits/registration-orders/delete ${SCOPES_BASE_REALM}/summits/registration-orders/create/offline ${SCOPES_BASE_REALM}/summits/badge-scans/read entity-updates/publish ${SCOPES_BASE_REALM}/audit-logs/read"
INVENTORY_API_SCOPES="inventory-items/get inventory-items/add inventory-items/update inventory-items/delete"
SCOPES="profile openid offline_access ${EMAIL_SCOPES} ${FILE_UPLOAD_SCOPES} ${INVENTORY_API_SCOPES} ${SCOPES_BASE_REALM}/summits/delete-event ${SCOPES_BASE_REALM}/summits/write ${SCOPES_BASE_REALM}/summits/write-event ${SCOPES_BASE_REALM}/summits/read/all ${SCOPES_BASE_REALM}/summits/read ${SCOPES_BASE_REALM}/summits/publish-event ${SCOPES_BASE_REALM}/members/read ${SCOPES_BASE_REALM}/members/read/me ${SCOPES_BASE_REALM}/speakers/write ${SCOPES_BASE_REALM}/attendees/write ${SCOPES_BASE_REALM}/members/write ${SCOPES_BASE_REALM}/organizations/write ${SCOPES_BASE_REALM}/organizations/read ${SCOPES_BASE_REALM}/summits/write-presentation-materials ${SCOPES_BASE_REALM}/summits/registration-orders/update ${SCOPES_BASE_REALM}/summits/registration-orders/delete ${SCOPES_BASE_REALM}/summits/registration-orders/create/offline ${SCOPES_BASE_REALM}/summits/badge-scans/read entity-updates/publish ${SCOPES_BASE_REALM}/audit-logs/read"
GOOGLE_API_KEY=
ALLOWED_USER_GROUPS="super-admins administrators summit-front-end-administrators summit-room-administrators track-chairs-admins sponsors"
APP_CLIENT_NAME = "openstack"
Expand Down
192 changes: 192 additions & 0 deletions src/actions/inventory-item-actions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
/**
* Copyright 2024 OpenStack Foundation
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* */

import T from "i18n-react/dist/i18n-react";
import {
getRequest,
putRequest,
postRequest,
deleteRequest,
createAction,
stopLoading,
startLoading,
showMessage,
showSuccessMessage,
authErrorHandler,
escapeFilterValue
} from "openstack-uicore-foundation/lib/utils/actions";
import history from "../history";
import { getAccessTokenSafely } from "../utils/methods";
import {
DEFAULT_CURRENT_PAGE,
DEFAULT_ORDER_DIR,
DEFAULT_PER_PAGE
} from "../utils/constants";

export const ADD_INVENTORY_ITEM = "ADD_INVENTORY_ITEM";
export const CHANGE_INVENTORY_ITEM_SEARCH_TERM =
"CHANGE_INVENTORY_ITEM_SEARCH_TERM";
export const INVENTORY_ITEM_ADDED = "INVENTORY_ITEM_ADDED";
export const INVENTORY_ITEM_DELETED = "INVENTORY_ITEM_DELETED";
export const INVENTORY_ITEM_UPDATED = "INVENTORY_ITEM_UPDATED";
export const RECEIVE_INVENTORY_ITEM = "RECEIVE_INVENTORY_ITEM";
export const RECEIVE_INVENTORY_ITEMS = "RECEIVE_INVENTORY_ITEMS";
export const REQUEST_INVENTORY_ITEMS = "REQUEST_INVENTORY_ITEMS";
export const RESET_INVENTORY_ITEM_FORM = "RESET_INVENTORY_ITEM_FORM";
export const UPDATE_INVENTORY_ITEM = "UPDATE_INVENTORY_ITEM";

export const getInventoryItems =
(
term = null,
page = DEFAULT_CURRENT_PAGE,
perPage = DEFAULT_PER_PAGE,
order = "id",
orderDir = DEFAULT_ORDER_DIR
) =>
async (dispatch) => {
const accessToken = await getAccessTokenSafely();
const filter = [];

dispatch(startLoading());

if (term) {
const escapedTerm = escapeFilterValue(term);
filter.push(`name=@${escapedTerm}`);
}

const params = {
page,
fields: "id,code,name",
per_page: perPage,
access_token: accessToken
};

if (filter.length > 0) {
params["filter[]"] = filter;
}

// order
if (order != null && orderDir != null) {
const orderDirSign = orderDir === 1 ? "+" : "-";
params.order = `${orderDirSign}${order}`;
}

return getRequest(
createAction(REQUEST_INVENTORY_ITEMS),
createAction(RECEIVE_INVENTORY_ITEMS),
`${window.INVENTORY_API_BASE_URL}/api/v1/inventory-items/`,
authErrorHandler,
{ order, orderDir, page, term }
)(params)(dispatch).then(() => {
dispatch(stopLoading());
});
};

export const getInventoryItem = (inventoryItemId) => async (dispatch) => {
const accessToken = await getAccessTokenSafely();

dispatch(startLoading());

const params = {
access_token: accessToken,
expand: "images,meta_fields,meta_fields.values"
};

return getRequest(
null,
createAction(RECEIVE_INVENTORY_ITEM),
`${window.INVENTORY_API_BASE_URL}/api/v1/inventory-items/${inventoryItemId}/`,
authErrorHandler
)(params)(dispatch).then(() => {
dispatch(stopLoading());
});
};

export const deleteInventoryItem = (inventoryItemId) => async (dispatch) => {
const accessToken = await getAccessTokenSafely();

dispatch(startLoading());

const params = {
access_token: accessToken
};

return deleteRequest(
null,
createAction(INVENTORY_ITEM_DELETED)({ inventoryItemId }),
`${window.INVENTORY_API_BASE_URL}/api/v1/inventory-items/${inventoryItemId}/`,
null,
authErrorHandler
)(params)(dispatch).then(() => {
dispatch(stopLoading());
});
};

export const resetInventoryItemForm = () => (dispatch) => {
dispatch(createAction(RESET_INVENTORY_ITEM_FORM)({}));
};

export const saveInventoryItem = (entity) => async (dispatch) => {
const accessToken = await getAccessTokenSafely();
dispatch(startLoading());

const params = {
access_token: accessToken
};

const normalizedEntity = normalizeEntity(entity);

if (entity.id) {
putRequest(
createAction(UPDATE_INVENTORY_ITEM),
createAction(INVENTORY_ITEM_UPDATED),
`${window.INVENTORY_API_BASE_URL}/api/v1/inventory-items/${entity.id}/`,
normalizedEntity,
authErrorHandler,
entity
)(params)(dispatch).then(() => {
dispatch(
showSuccessMessage(
T.translate("edit_inventory_item.inventory_item_saved")
)
);
});
} else {
const success_message = {
title: T.translate("general.done"),
html: T.translate("edit_inventory_item.inventory_item_created"),
type: "success"
};

postRequest(
createAction(ADD_INVENTORY_ITEM),
createAction(INVENTORY_ITEM_ADDED),
`${window.INVENTORY_API_BASE_URL}/api/v1/inventory-items/`,
normalizedEntity,
authErrorHandler,
entity
)(params)(dispatch).then(() => {
dispatch(
showMessage(success_message, () => {
history.push("/app/sponsors-inventory");
})
);
});
}
};

const normalizeEntity = (entity) => {
const normalizedEntity = { ...entity };

return normalizedEntity;
};
1 change: 1 addition & 0 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ window.REPORT_API_BASE_URL = process.env.REPORT_API_BASE_URL;
window.MARKETING_API_BASE_URL = process.env.MARKETING_API_BASE_URL;
window.EMAIL_API_BASE_URL = process.env.EMAIL_API_BASE_URL;
window.FILE_UPLOAD_API_BASE_URL = process.env.FILE_UPLOAD_API_BASE_URL;
window.INVENTORY_API_BASE_URL = process.env.INVENTORY_API_BASE_URL;
window.SIGNAGE_BASE_URL = process.env.SIGNAGE_BASE_URL;
window.OAUTH2_CLIENT_ID = process.env.OAUTH2_CLIENT_ID;
window.SCOPES = process.env.SCOPES;
Expand Down
67 changes: 67 additions & 0 deletions src/components/form-repeater/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import React, { useState } from "react";

const FormRepeater = ({ renderContent }) => {
const [lines, setLines] = useState([{ id: Date.now(), value: "" }]);

const handleAddLine = (id) => {
const newLine = { id: Date.now(), value: "" };
const index = lines.findIndex((line) => line.id === id);
const updatedLines = [
...lines.slice(0, index + 1),
newLine,
...lines.slice(index + 1)
];
setLines(updatedLines);
};

const handleRemoveLine = (id) => {
setLines(lines.filter((line) => line.id !== id));
};

return (
<div>
{lines.map((line) => (
<div
key={line.id}
style={{ display: "flex", alignItems: "center", marginBottom: "8px" }}
>
<div style={{ marginRight: "8px", flex: 1 }}>
{renderContent(line, (value) => {
const updatedLines = lines.map((l) =>
l.id === line.id ? { ...l, value } : l
);
setLines(updatedLines);
})}
</div>
<button
type="button"
onClick={() => handleAddLine(line.id)}
style={{
border: "none",
background: "none",
cursor: "pointer",
marginRight: "4px"
}}
>
<i className="fa fa-plus" aria-hidden="true" title="Add" />
</button>
{lines.length > 1 && (
<button
type="button"
onClick={() => handleRemoveLine(line.id)}
style={{
border: "none",
background: "none",
cursor: "pointer"
}}
>
<i className="fa fa-trash" aria-hidden="true" title="Remove" />
</button>
)}
</div>
))}
</div>
);
};

export default FormRepeater;
Loading

0 comments on commit b1e30a0

Please sign in to comment.