| @@ -169,3 +169,38 @@ | |||
| .files-file-routing:hover { | |||
| background-color: #f0f0f0; | |||
| } | |||
| .add-categories-files { | |||
| display: flex; | |||
| } | |||
| .add-categories-files > * { | |||
| margin-left: 6px !important; | |||
| } | |||
| .files-page-card-input { | |||
| display: flex; | |||
| } | |||
| .add-category-input input, | |||
| .files-page-card-input input { | |||
| width: 100%; | |||
| border: 1px solid #e4e4e4 !important; | |||
| padding: 16.5px 20px !important; | |||
| border-radius: 4px; | |||
| outline: none; | |||
| } | |||
| .files-page-card-input > button { | |||
| margin-left: 6px; | |||
| } | |||
| .files-category-custom-modal-buttons { | |||
| display: flex; | |||
| justify-content: flex-end; | |||
| margin-top: 12px; | |||
| } | |||
| .files-category-custom-modal-buttons button { | |||
| margin-left: 8px; | |||
| } | |||
| @@ -16,6 +16,7 @@ import { | |||
| updateFileFilterTag, | |||
| } from "../../store/actions/files/fileActions"; | |||
| import { useParams } from "react-router-dom"; | |||
| import { PAGE_SIZE_FILES } from "../../constants/keyCodeConstants"; | |||
| const DocsFilters = ({ open, handleClose, setPage, setFile }) => { | |||
| const dispatch = useDispatch(); | |||
| @@ -43,7 +44,7 @@ const DocsFilters = ({ open, handleClose, setPage, setFile }) => { | |||
| dispatch( | |||
| getFilesReq({ | |||
| payload: { | |||
| pageSize: 6, | |||
| pageSize: PAGE_SIZE_FILES, | |||
| currentPage: 1, | |||
| categoryId: id, | |||
| extensions: extFilters, | |||
| @@ -6,8 +6,9 @@ import TreeItem from "@mui/lab/TreeItem"; | |||
| import { useDispatch, useSelector } from "react-redux"; | |||
| import { setAllCategoriesReq } from "../../store/actions/categories/categoriesAction"; | |||
| import { selectAllCategories } from "../../store/selectors/categoriesSelector"; | |||
| import PropTypes from "prop-types"; | |||
| function TreeViewFiles() { | |||
| function TreeViewFiles({ onSelectCategory }) { | |||
| const dispatch = useDispatch(); | |||
| const categories = useSelector(selectAllCategories); | |||
| useEffect(() => { | |||
| @@ -15,7 +16,12 @@ function TreeViewFiles() { | |||
| }, []); | |||
| const renderTree = (nodes) => ( | |||
| <TreeItem key={nodes.id} nodeId={nodes.id} label={nodes.name}> | |||
| <TreeItem | |||
| key={nodes.id} | |||
| nodeId={nodes.id} | |||
| label={nodes.name} | |||
| onClick={() => onSelectCategory({ id: nodes.id, name: nodes.name })} | |||
| > | |||
| {Array.isArray(nodes.treeViewCategories) | |||
| ? nodes.treeViewCategories.map((node) => renderTree(node)) | |||
| : null} | |||
| @@ -38,4 +44,8 @@ function TreeViewFiles() { | |||
| ); | |||
| } | |||
| TreeViewFiles.propTypes = { | |||
| onSelectCategory: PropTypes.func, | |||
| }; | |||
| export default TreeViewFiles; | |||
| @@ -14,9 +14,10 @@ import { | |||
| } from "../../store/actions/tags/tagsAction"; | |||
| import { selectTags } from "../../store/selectors/tagsSelector"; | |||
| import { uploadFileReq } from "../../store/actions/uploadFile/uploadFileActions"; | |||
| import { FILES_VIEW_PAGE } from "../../constants/pages"; | |||
| import { FILES_PAGE } from "../../constants/pages"; | |||
| import PropTypes from "prop-types"; | |||
| import TreeViewFiles from "../../components/Files/TreeViewFiles"; | |||
| import Button from "../../components/Button/Button"; | |||
| const AddFile = ({ history }) => { | |||
| const [dropzoneActive, setDropzoneActive] = useState(false); | |||
| @@ -26,7 +27,10 @@ const AddFile = ({ history }) => { | |||
| const dispatch = useDispatch(); | |||
| // const categories = useSelector(selectCategories); | |||
| const tags = useSelector(selectTags); | |||
| // const [selectedCategory, setSelectedCategory] = useState(null); | |||
| const [selectedCategory, setSelectedCategory] = useState({ | |||
| id: -1, | |||
| name: "", | |||
| }); | |||
| const { t } = useTranslation(); | |||
| useEffect(() => { | |||
| @@ -39,6 +43,7 @@ const AddFile = ({ history }) => { | |||
| setPdfFile(null); | |||
| setTitle(""); | |||
| setShowMessage(true); | |||
| setSelectedCategory({ id: -1, name: "" }); | |||
| }; | |||
| useEffect(() => { | |||
| @@ -61,9 +66,9 @@ const AddFile = ({ history }) => { | |||
| setPdfFile(selectedFile); | |||
| }; | |||
| // const selectCategoryHandler = (e) => { | |||
| // setSelectedCategory(e.target.value); | |||
| // }; | |||
| const selectCategoryHandler = (category) => { | |||
| setSelectedCategory(category); | |||
| }; | |||
| const onChangeTagsCheckbox = (id) => { | |||
| dispatch(changeTagIsCheckedValue(id)); | |||
| @@ -74,17 +79,12 @@ const AddFile = ({ history }) => { | |||
| .filter((tag) => tag.isChecked === true) | |||
| .map((tag) => Number(tag.id)); | |||
| if ( | |||
| title === "" || | |||
| tagsIds.length === 0 || | |||
| pdfFile === null | |||
| ) | |||
| return; | |||
| if (title === "" || tagsIds.length === 0 || pdfFile === null) return; | |||
| dispatch( | |||
| uploadFileReq({ | |||
| title, | |||
| categoryId: -1, | |||
| categoryId: selectedCategory.id, | |||
| tagsIds, | |||
| fileToUpload: pdfFile, | |||
| onSuccessUploadFile, | |||
| @@ -120,7 +120,29 @@ const AddFile = ({ history }) => { | |||
| </MenuItem> | |||
| ))} | |||
| </Select> */} | |||
| <TreeViewFiles/> | |||
| <TreeViewFiles onSelectCategory={selectCategoryHandler} /> | |||
| </div> | |||
| </div> | |||
| <div className="files-page-card"> | |||
| <div className="files-page-card-title"> | |||
| <h1>Selected Category</h1> | |||
| </div> | |||
| <div className="files-page-card-input"> | |||
| <input | |||
| type="text" | |||
| disabled={true} | |||
| value={selectedCategory.id !== -1 ? selectedCategory.name : "null"} | |||
| /> | |||
| <Button | |||
| type="button" | |||
| variant="contained" | |||
| className="c-btn c-btn--primary" | |||
| onClick={() => setSelectedCategory({ id: -1, name: "" })} | |||
| disabled={selectedCategory.id === -1} | |||
| > | |||
| Set root | |||
| </Button> | |||
| </div> | |||
| </div> | |||
| @@ -224,7 +246,7 @@ const AddFile = ({ history }) => { | |||
| > | |||
| <p | |||
| className="applicant-ads-back-button" | |||
| onClick={() => history.push(FILES_VIEW_PAGE)} | |||
| onClick={() => history.push(FILES_PAGE)} | |||
| > | |||
| Nazad na sve fajlove | |||
| </p> | |||
| @@ -2,7 +2,10 @@ import React, { useEffect, useState } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { useSelector, useDispatch } from "react-redux"; | |||
| import IconButton from "../../components/IconButton/IconButton"; | |||
| import { setCategoriesReq } from "../../store/actions/categories/categoriesAction"; | |||
| import { | |||
| createCategoryReq, | |||
| setCategoriesReq, | |||
| } from "../../store/actions/categories/categoriesAction"; | |||
| import { | |||
| selectCategories, | |||
| selectChildParentRelations, | |||
| @@ -12,12 +15,18 @@ import { FILES_PAGE } from "../../constants/pages"; | |||
| import FileTable from "./FileTable"; | |||
| import { useParams } from "react-router-dom"; | |||
| import { ADD_FILE } from "../../constants/pages"; | |||
| import CustomModal from "../../components/UI/CustomModal"; | |||
| import xIcon from "../../assets/images/x.png"; | |||
| import plusIcon from "../../assets/images/plus.png"; | |||
| import Button from "../../components/Button/Button"; | |||
| const FilesPage = ({ history }) => { | |||
| const categories = useSelector(selectCategories); | |||
| const childParentRelations = useSelector(selectChildParentRelations); | |||
| const dispatch = useDispatch(); | |||
| const [trigger, setTrigger] = useState(0); | |||
| const [openCreateCategoryModal, setOpenCreateCategoryModal] = useState(false); | |||
| const [createCategoryName, setCreateCategoryName] = useState(""); | |||
| let { id } = useParams(); | |||
| useEffect(() => { | |||
| @@ -28,11 +37,33 @@ const FilesPage = ({ history }) => { | |||
| } | |||
| }, [id]); | |||
| const changeOpenCreateCategoryModal = () => { | |||
| setOpenCreateCategoryModal((oldState) => !oldState); | |||
| }; | |||
| const getNameHandler = (name) => { | |||
| if (name.length > 15) return name.substr(0, 15) + "..."; | |||
| return name; | |||
| }; | |||
| const onSuccessCreatingCategoryHandler = () => { | |||
| dispatch( | |||
| setCategoriesReq(id === undefined ? undefined : { parentCategoryId: id }) | |||
| ); | |||
| setOpenCreateCategoryModal(false); | |||
| }; | |||
| const createCategoryHandler = () => { | |||
| dispatch( | |||
| createCategoryReq({ | |||
| name: createCategoryName, | |||
| parentId: id !== undefined ? id : null, | |||
| onSuccess: onSuccessCreatingCategoryHandler, | |||
| }) | |||
| ); | |||
| setCreateCategoryName(""); | |||
| }; | |||
| const ColoredLine = () => ( | |||
| <hr | |||
| style={{ | |||
| @@ -47,6 +78,54 @@ const FilesPage = ({ history }) => { | |||
| <> | |||
| <div className="l-t-rectangle"></div> | |||
| <div className="r-b-rectangle"></div> | |||
| <CustomModal | |||
| classes="files-custom-modal" | |||
| open={openCreateCategoryModal} | |||
| onCloseModal={changeOpenCreateCategoryModal} | |||
| > | |||
| <div className="add-pattern-modal-header"> | |||
| <div className="add-pattern-modal-header-title"> | |||
| <div className="add-pattern-modal-header-title-image"> | |||
| <img src={plusIcon} alt="plus" /> | |||
| </div> | |||
| <div className="add-pattern-modal-header-title-title"> | |||
| <p>Create category</p> | |||
| </div> | |||
| </div> | |||
| <div | |||
| className="add-pattern-modal-header-close" | |||
| onClick={changeOpenCreateCategoryModal} | |||
| > | |||
| <img src={xIcon} alt="close" /> | |||
| </div> | |||
| </div> | |||
| <div className="add-category-input"> | |||
| <input | |||
| type="text" | |||
| placeholder="Category name" | |||
| value={createCategoryName} | |||
| onChange={(e) => setCreateCategoryName(e.target.value)} | |||
| /> | |||
| </div> | |||
| <div className="files-category-custom-modal-buttons"> | |||
| <Button | |||
| type="button" | |||
| variant="contained" | |||
| className="c-btn c-btn--primary-outlined" | |||
| onClick={changeOpenCreateCategoryModal} | |||
| > | |||
| Close | |||
| </Button> | |||
| <Button | |||
| type="button" | |||
| variant="contained" | |||
| className="c-btn c-btn--primary" | |||
| onClick={createCategoryHandler} | |||
| > | |||
| Create category | |||
| </Button> | |||
| </div> | |||
| </CustomModal> | |||
| <div | |||
| className="pl-144" | |||
| style={{ paddingTop: "36px" }} | |||
| @@ -64,7 +143,7 @@ const FilesPage = ({ history }) => { | |||
| }} | |||
| > | |||
| <h1 className="page-heading">Folderi</h1> | |||
| <div style={{ display: "flex" }}> | |||
| <div className="add-categories-files"> | |||
| <IconButton | |||
| className="c-btn ads-page-btn c-btn--primary add-ad-btn filesPage" | |||
| onClick={() => history.push(ADD_FILE)} | |||
| @@ -73,7 +152,7 @@ const FilesPage = ({ history }) => { | |||
| </IconButton> | |||
| <IconButton | |||
| className="c-btn ads-page-btn c-btn--primary add-ad-btn filesPage" | |||
| onClick={() => history.push(ADD_FILE)} | |||
| onClick={changeOpenCreateCategoryModal} | |||
| > | |||
| + Kategorija | |||
| </IconButton> | |||
| @@ -28,6 +28,7 @@ import editIcon from "../../assets/images/edit.png"; | |||
| import xIcon from "../../assets/images/x.png"; | |||
| import ConfirmDialog from "../../components/MUI/ConfirmDialog"; | |||
| import CustomModal from "../../components/UI/CustomModal"; | |||
| import { PAGE_SIZE_FILES } from "../../constants/keyCodeConstants"; | |||
| const FilesViewPage = ({ history }) => { | |||
| const [toggleFiltersDrawer, setToggleFiltersDrawer] = useState(false); | |||
| @@ -68,7 +69,7 @@ const FilesViewPage = ({ history }) => { | |||
| dispatch( | |||
| getFilesReq({ | |||
| payload: { | |||
| pageSize: 6, | |||
| pageSize: PAGE_SIZE_FILES, | |||
| currentPage: page, | |||
| categories: [state && state.category], | |||
| extensions: [], | |||
| @@ -100,7 +101,7 @@ const FilesViewPage = ({ history }) => { | |||
| dispatch( | |||
| getFilesReq({ | |||
| payload: { | |||
| pageSize: 6, | |||
| pageSize: PAGE_SIZE_FILES, | |||
| currentPage: value, | |||
| categories: catFilters, | |||
| extensions: extFilters, | |||
| @@ -151,7 +152,7 @@ const FilesViewPage = ({ history }) => { | |||
| dispatch( | |||
| getFilesReq({ | |||
| payload: { | |||
| pageSize: 6, | |||
| pageSize: PAGE_SIZE_FILES, | |||
| currentPage: page, | |||
| categories: catFilters, | |||
| extensions: extFilters, | |||
| @@ -73,7 +73,8 @@ export default { | |||
| rootCategories: base + "/categories/root-categories", | |||
| isCategoriesChecked: base + "/categories/granted-categories", | |||
| grantCategory: base + "/users/grant-category", | |||
| allCategories:base + "/categories/all-categories" | |||
| allCategories: base + "/categories/all-categories", | |||
| createCategory: base + "/categories", | |||
| }, | |||
| tags: { | |||
| allTags: base + "/tags/names", | |||
| @@ -15,3 +15,6 @@ export const grantCategoryRequest = (payload) => | |||
| export const getAllCategories = () => | |||
| getRequest(apiEndpoints.categories.allCategories); | |||
| export const createCategoryRequest = (payload) => | |||
| postRequest(apiEndpoints.categories.createCategory, payload); | |||
| @@ -12,6 +12,9 @@ import { | |||
| FETCH_ALL_CATEGORIES_ERR, | |||
| FETCH_ALL_CATEGORIES_REQ, | |||
| FETCH_ALL_CATEGORIES_SUCCESS, | |||
| CREATE_CATEGORY_REQ, | |||
| CREATE_CATEGORY_ERR, | |||
| CREATE_CATEGORY_SUCCESS, | |||
| } from "./categoriesActionConstants"; | |||
| export const setCategoriesReq = (payload) => ({ | |||
| @@ -77,3 +80,17 @@ export const setAllCategories = (payload) => ({ | |||
| type: FETCH_ALL_CATEGORIES_SUCCESS, | |||
| payload, | |||
| }); | |||
| export const createCategoryReq = (payload) => ({ | |||
| type: CREATE_CATEGORY_REQ, | |||
| payload, | |||
| }); | |||
| export const createCategoryError = () => ({ | |||
| type: CREATE_CATEGORY_ERR | |||
| }); | |||
| export const setCreateCategory = (payload) => ({ | |||
| type: CREATE_CATEGORY_SUCCESS, | |||
| payload, | |||
| }); | |||
| @@ -8,6 +8,7 @@ const FETCH_ROOT_CATEGORIES_SCOPE = "FETCH_ROOT_CATEGORIES"; | |||
| const FETCH_IS_CATEGORIES_CHECKED_SCOPE = "FETCH_IS_CATEGORIES_CHECKED"; | |||
| const GRANT_CATEGORY_SCOPE = "GRANT_CATEGORY"; | |||
| const FETCH_ALL_CATEGORIES_SCOPE = "FETCH_ALL_CATEGORIES"; | |||
| const CREATE_CATEGORY_SCOPE = "CREATE_CATEGORY"; | |||
| export const FETCH_ROOT_CATEGORIES_REQ = createFetchType( | |||
| FETCH_ROOT_CATEGORIES_SCOPE | |||
| @@ -36,4 +37,8 @@ export const FETCH_ALL_CATEGORIES_REQ = createFetchType(FETCH_ALL_CATEGORIES_SCO | |||
| export const FETCH_ALL_CATEGORIES_ERR = createErrorType(FETCH_ALL_CATEGORIES_SCOPE); | |||
| export const FETCH_ALL_CATEGORIES_SUCCESS = createSuccessType(FETCH_ALL_CATEGORIES_SCOPE); | |||
| export const CREATE_CATEGORY_REQ = createFetchType(CREATE_CATEGORY_SCOPE); | |||
| export const CREATE_CATEGORY_ERR = createErrorType(CREATE_CATEGORY_SCOPE); | |||
| export const CREATE_CATEGORY_SUCCESS = createSuccessType(CREATE_CATEGORY_SCOPE); | |||
| export const CHANGE_IC_CHECKED_CATEGORY = "CHANGE_IC_CHECKED_CATEGORY"; | |||
| @@ -7,14 +7,16 @@ import { | |||
| GRANT_CATEGORY_ERR, | |||
| GRANT_CATEGORY_SUCCESS, | |||
| FETCH_ALL_CATEGORIES_ERR, | |||
| FETCH_ALL_CATEGORIES_SUCCESS | |||
| FETCH_ALL_CATEGORIES_SUCCESS, | |||
| CREATE_CATEGORY_SUCCESS, | |||
| CREATE_CATEGORY_ERR, | |||
| } from "../../actions/categories/categoriesActionConstants"; | |||
| import createReducer from "../../utils/createReducer"; | |||
| const initialState = { | |||
| categories: [], | |||
| childParentRelations: [], | |||
| allCategories:[], | |||
| allCategories: [], | |||
| isCategoriesChecked: [], | |||
| changedCategories: [], | |||
| errorMessage: "", | |||
| @@ -31,6 +33,8 @@ export default createReducer( | |||
| [GRANT_CATEGORY_ERR]: setGrantCategoriesErrorMessage, | |||
| [FETCH_ALL_CATEGORIES_SUCCESS]: setStateAllCategories, | |||
| [FETCH_ALL_CATEGORIES_ERR]: setStateAllCategoriesErrorMessage, | |||
| [CREATE_CATEGORY_SUCCESS]: setCreateCategoryReducer, | |||
| [CREATE_CATEGORY_ERR]: setCreateCategoryErrorMessage, | |||
| }, | |||
| initialState | |||
| ); | |||
| @@ -39,7 +43,7 @@ function setStateCategories(state, action) { | |||
| return { | |||
| ...state, | |||
| categories: action.payload.categories, | |||
| childParentRelations: action.payload.childParentRelations | |||
| childParentRelations: action.payload.childParentRelations, | |||
| }; | |||
| } | |||
| @@ -101,7 +105,7 @@ function setIsCheckedCategory(state, action) { | |||
| function setStateGrantCategories(state) { | |||
| return { | |||
| ...state, | |||
| changedCategories: [] | |||
| changedCategories: [], | |||
| }; | |||
| } | |||
| @@ -115,7 +119,7 @@ function setGrantCategoriesErrorMessage(state, action) { | |||
| function setStateAllCategories(state, action) { | |||
| return { | |||
| ...state, | |||
| allCategories:action.payload | |||
| allCategories: action.payload, | |||
| }; | |||
| } | |||
| @@ -125,3 +129,16 @@ function setStateAllCategoriesErrorMessage(state, action) { | |||
| errorMessage: action.payload, | |||
| }; | |||
| } | |||
| function setCreateCategoryReducer(state) { | |||
| return { | |||
| ...state, | |||
| }; | |||
| } | |||
| function setCreateCategoryErrorMessage(state, action) { | |||
| return { | |||
| ...state, | |||
| errorMessage: action.payload, | |||
| }; | |||
| } | |||
| @@ -7,7 +7,8 @@ import { | |||
| setGrantCategories, | |||
| setGrantCategoriesError, | |||
| setAllCategories, | |||
| setAllCategoriesError | |||
| setAllCategoriesError, | |||
| setCreateCategory, | |||
| } from "../actions/categories/categoriesAction"; | |||
| import { authScopeStringGetHelper } from "../../util/helpers/authScopeHelpers"; | |||
| import { JWT_TOKEN } from "../../constants/localStorage"; | |||
| @@ -17,14 +18,16 @@ import { | |||
| FETCH_ROOT_CATEGORIES_REQ, | |||
| FETCH_IS_CATEGORIES_CHECKED_REQ, | |||
| GRANT_CATEGORY_REQ, | |||
| FETCH_ALL_CATEGORIES_REQ | |||
| FETCH_ALL_CATEGORIES_REQ, | |||
| CREATE_CATEGORY_REQ, | |||
| } from "../actions/categories/categoriesActionConstants"; | |||
| import { | |||
| getRootCategories, | |||
| getIsCategoriesChecked, | |||
| grantCategoryRequest, | |||
| getRootCategories2, | |||
| getAllCategories | |||
| getAllCategories, | |||
| createCategoryRequest, | |||
| } from "../../request/categoriesRequest"; | |||
| export function* getRootCategoriesSaga({ payload }) { | |||
| @@ -37,7 +40,12 @@ export function* getRootCategoriesSaga({ payload }) { | |||
| } else { | |||
| result = yield call(getRootCategories2, payload.parentCategoryId); | |||
| } | |||
| yield put(setCategories({categories: result.data.categories, childParentRelations: result.data.childParentRelations})); | |||
| yield put( | |||
| setCategories({ | |||
| categories: result.data.categories, | |||
| childParentRelations: result.data.childParentRelations, | |||
| }) | |||
| ); | |||
| } catch (error) { | |||
| const errorMessage = yield call(rejectErrorCodeHelper, error); | |||
| yield put(setCategoriesError(errorMessage)); | |||
| @@ -80,11 +88,28 @@ export function* getAllCategoriesSaga() { | |||
| } | |||
| } | |||
| export function* createCategorySaga({ payload }) { | |||
| try { | |||
| const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN); | |||
| yield call(addHeaderToken, JwtToken); | |||
| yield call(createCategoryRequest, { | |||
| name: payload.name, | |||
| parentId: payload.parentId, | |||
| }); | |||
| yield put(setCreateCategory()); | |||
| if (payload.onSuccess) yield call(payload.onSuccess); | |||
| } catch (error) { | |||
| const errorMessage = yield call(rejectErrorCodeHelper, error); | |||
| yield put(setGrantCategoriesError(errorMessage)); | |||
| } | |||
| } | |||
| export default function* categoriesSaga() { | |||
| yield all([ | |||
| takeLatest(FETCH_ROOT_CATEGORIES_REQ, getRootCategoriesSaga), | |||
| takeLatest(FETCH_IS_CATEGORIES_CHECKED_REQ, getIsCategoriesCheckedSaga), | |||
| takeLatest(GRANT_CATEGORY_REQ, grantCategoriesCheckedSaga), | |||
| takeLatest(FETCH_ALL_CATEGORIES_REQ, getAllCategoriesSaga), | |||
| takeLatest(CREATE_CATEGORY_REQ, createCategorySaga), | |||
| ]); | |||
| } | |||
| @@ -50,6 +50,7 @@ export function* getAll({ payload }) { | |||
| try { | |||
| const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN); | |||
| yield call(addHeaderToken, JwtToken); | |||
| const result = yield call(getAllFilesReq, payload.payload); | |||
| yield put(getFileSuccess(result.data)); | |||
| if (payload.payload.onSuccess) { | |||