| @@ -266,10 +266,14 @@ | |||
| .files-button-responsive { | |||
| gap: 5px; | |||
| width: 105px; | |||
| width: 85px; | |||
| height: 31px; | |||
| } | |||
| .add-categories-files > button:first-child { | |||
| margin-left: 0px !important; | |||
| } | |||
| .file-viewer-close-btn { | |||
| width: 100px; | |||
| align-self: flex-end; | |||
| @@ -29,24 +29,27 @@ import { useTranslation } from "react-i18next"; | |||
| import CloseIcon from "@mui/icons-material/Close"; | |||
| import LogoutIcon from "@mui/icons-material/Logout"; | |||
| import UserProfile from "../Profile/UserProfile"; | |||
| import { useSelector } from "react-redux"; | |||
| import { useDispatch, useSelector } from "react-redux"; | |||
| //import { userSelector } from "../../store/selectors/userSelectors"; | |||
| import { Link, useLocation } from "react-router-dom"; | |||
| import rs from "../../assets/images/rs.png"; | |||
| import en from "../../assets/images/en.png"; | |||
| import { logoutUser } from "../../store/actions/login/loginActions"; | |||
| const NavbarComponent = () => { | |||
| const navItems = [ | |||
| "users", | |||
| "files" | |||
| ]; | |||
| const navItems = ["users", "files"]; | |||
| const { pathname } = useLocation(); | |||
| const [openDrawer, setOpenDrawer] = useState(false); | |||
| const [preview, setPreview] = useState(false); | |||
| const theme = useTheme(); | |||
| const matches = useMediaQuery(theme.breakpoints.down("sm")); | |||
| const dispatch = useDispatch(); | |||
| // const toggleColorMode = useContext(ColorModeContext); | |||
| const logout = () => { | |||
| dispatch(logoutUser()); | |||
| }; | |||
| let userRef = useRef(); | |||
| let btnRef = useRef(); | |||
| @@ -70,8 +73,10 @@ const NavbarComponent = () => { | |||
| }; | |||
| const filterNavItems = () => { | |||
| return navItems.filter(n => ((n === "users" && user.role === "SuperAdmin") || n !== "users")) | |||
| } | |||
| return navItems.filter( | |||
| (n) => (n === "users" && user.role === "SuperAdmin") || n !== "users" | |||
| ); | |||
| }; | |||
| useEffect(() => { | |||
| let handler = (e) => { | |||
| @@ -197,6 +202,7 @@ const NavbarComponent = () => { | |||
| {/* <Typography>s</Typography> */} | |||
| <div className="flex-center"> | |||
| <Button | |||
| onClick={logout} | |||
| sx={{ | |||
| padding: "18px 72px", | |||
| border: "1px solid #226cb0", | |||
| @@ -299,9 +299,12 @@ export default { | |||
| addFileSuccessfullyAddedFile: "Successfully added file", | |||
| addFileGoBackToFiles: "Go back to all files", | |||
| createCategoryModalTitle: "Create category", | |||
| createTagModalTitle: "Create tag", | |||
| createCategoryModalPlaceholder: "Category name", | |||
| createTagModalPlaceholder: "Tag name", | |||
| close: "Close", | |||
| createCategoryModalSubmitButton: "Create category", | |||
| createTagModalSubmitButton: "Create tag", | |||
| folders: "Folders", | |||
| file: "File", | |||
| files: "Files", | |||
| @@ -323,6 +326,7 @@ export default { | |||
| documents: "| Documents", | |||
| extension: "Extension", | |||
| tags: "Tags", | |||
| search: "Search" | |||
| search: "Search", | |||
| tag:"Tag" | |||
| } | |||
| }; | |||
| @@ -337,9 +337,12 @@ export default { | |||
| addFileSuccessfullyAddedFile: "Uspešno dodat fajl", | |||
| addFileGoBackToFiles: "Nazad na sve fajlove", | |||
| createCategoryModalTitle: "Napravite kategoriju", | |||
| createTagModalTitle: "Napravite tag", | |||
| createCategoryModalPlaceholder: "Naziv kategorije", | |||
| createTagModalPlaceholder: "Naziv taga", | |||
| close: "Izađite", | |||
| createCategoryModalSubmitButton: "Napravite kategoriju", | |||
| createTagModalSubmitButton: "Napravite tag", | |||
| folders: "Folderi", | |||
| file: "Fajl", | |||
| files: "Fajlovi", | |||
| @@ -361,6 +364,7 @@ export default { | |||
| documents: "| Dokumenti", | |||
| extension: "Ekstenzija", | |||
| tags: "Tagovi", | |||
| search: "Pretraži" | |||
| search: "Pretraži", | |||
| tag:"Tag" | |||
| }, | |||
| }; | |||
| @@ -6,6 +6,7 @@ import { | |||
| createCategoryReq, | |||
| setCategoriesReq, | |||
| } from "../../store/actions/categories/categoriesAction"; | |||
| import { createTagReq } from "../../store/actions/tags/tagsAction"; | |||
| import { | |||
| selectCategories, | |||
| selectChildParentRelations, | |||
| @@ -29,7 +30,9 @@ const FilesPage = ({ history }) => { | |||
| const dispatch = useDispatch(); | |||
| const [trigger, setTrigger] = useState(0); | |||
| const [openCreateCategoryModal, setOpenCreateCategoryModal] = useState(false); | |||
| const [openCreateTagModal, setOpenCreateTagModal] = useState(false); | |||
| const [createCategoryName, setCreateCategoryName] = useState(""); | |||
| const [createTagName, setCreateTagName] = useState(""); | |||
| let { id } = useParams(); | |||
| const theme = useTheme(); | |||
| const matches = useMediaQuery(theme.breakpoints.down("370")); | |||
| @@ -58,6 +61,10 @@ const FilesPage = ({ history }) => { | |||
| setOpenCreateCategoryModal((oldState) => !oldState); | |||
| }; | |||
| const changeOpenCreateTagModal = () => { | |||
| setOpenCreateTagModal((oldState) => !oldState); | |||
| }; | |||
| const getNameHandler = (name) => { | |||
| if (matches) { | |||
| if (name.length > 7) return name.substr(0, 7) + "..."; | |||
| @@ -79,6 +86,10 @@ const FilesPage = ({ history }) => { | |||
| setOpenCreateCategoryModal(false); | |||
| }; | |||
| const onSuccessCreatingTagHandler = () => { | |||
| setOpenCreateTagModal(false); | |||
| }; | |||
| const createCategoryHandler = () => { | |||
| dispatch( | |||
| createCategoryReq({ | |||
| @@ -90,6 +101,16 @@ const FilesPage = ({ history }) => { | |||
| setCreateCategoryName(""); | |||
| }; | |||
| const createTagHandler = () => { | |||
| dispatch( | |||
| createTagReq({ | |||
| name: createTagName, | |||
| onSuccess: onSuccessCreatingTagHandler, | |||
| }) | |||
| ); | |||
| setCreateTagName(""); | |||
| }; | |||
| const ColoredLine = () => ( | |||
| <hr | |||
| style={{ | |||
| @@ -102,8 +123,14 @@ const FilesPage = ({ history }) => { | |||
| return ( | |||
| <> | |||
| <div className="l-t-rectangle"></div> | |||
| <div className="r-b-rectangle" style={{width:matches ? 100 : 180}}></div> | |||
| <div | |||
| className="l-t-rectangle" | |||
| style={{ height: matches ? 140 : 180 }} | |||
| ></div> | |||
| <div | |||
| className="r-b-rectangle" | |||
| style={{ width: matches ? 100 : 180 }} | |||
| ></div> | |||
| <CustomModal | |||
| classes="files-custom-modal" | |||
| open={openCreateCategoryModal} | |||
| @@ -152,6 +179,54 @@ const FilesPage = ({ history }) => { | |||
| </Button> | |||
| </div> | |||
| </CustomModal> | |||
| <CustomModal | |||
| classes="files-custom-modal" | |||
| open={openCreateTagModal} | |||
| onCloseModal={changeOpenCreateTagModal} | |||
| > | |||
| <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>{t("files.createTagModalTitle")}</p> | |||
| </div> | |||
| </div> | |||
| <div | |||
| className="add-pattern-modal-header-close" | |||
| onClick={changeOpenCreateTagModal} | |||
| > | |||
| <img src={xIcon} alt="close" /> | |||
| </div> | |||
| </div> | |||
| <div className="add-category-input"> | |||
| <input | |||
| type="text" | |||
| placeholder={t("files.createTagModalPlaceholder")} | |||
| value={createTagName} | |||
| onChange={(e) => setCreateTagName(e.target.value)} | |||
| /> | |||
| </div> | |||
| <div className="files-category-custom-modal-buttons"> | |||
| <Button | |||
| type="button" | |||
| variant="contained" | |||
| className="c-btn c-btn--primary-outlined" | |||
| onClick={changeOpenCreateTagModal} | |||
| > | |||
| {t("files.close")} | |||
| </Button> | |||
| <Button | |||
| type="button" | |||
| variant="contained" | |||
| className="c-btn c-btn--primary" | |||
| onClick={createTagHandler} | |||
| > | |||
| {t("files.createTagModalSubmitButton")} | |||
| </Button> | |||
| </div> | |||
| </CustomModal> | |||
| <div | |||
| className="pl-144" | |||
| style={{ paddingTop: "36px" }} | |||
| @@ -169,7 +244,8 @@ const FilesPage = ({ history }) => { | |||
| <div | |||
| style={{ | |||
| display: "flex", | |||
| alignItems: "center", | |||
| alignItems: matches ? "flex-start" : "center", | |||
| flexDirection: matches ? "column" : "row", | |||
| justifyContent: "space-between", | |||
| marginBottom: "15px", | |||
| }} | |||
| @@ -194,6 +270,15 @@ const FilesPage = ({ history }) => { | |||
| > | |||
| + {t("files.category")} | |||
| </IconButton> | |||
| <IconButton | |||
| className={ | |||
| `c-btn ads-page-btn c-btn--primary filesPage ` + | |||
| (matches ? "files-button-responsive" : "add-ad-btn") | |||
| } | |||
| onClick={changeOpenCreateTagModal} | |||
| > | |||
| + {t("files.tag")} | |||
| </IconButton> | |||
| </div> | |||
| </div> | |||
| <ColoredLine /> | |||
| @@ -1,6 +1,7 @@ | |||
| import { getRequest } from "."; | |||
| import { getRequest, postRequest } from "."; | |||
| import apiEndpoints from "./apiEndpoints"; | |||
| export const getFileFilters = () => getRequest(apiEndpoints.fileTags.filters); | |||
| export const getAllTags = () => | |||
| getRequest(apiEndpoints.tags.allTags); | |||
| export const getAllTags = () => getRequest(apiEndpoints.tags.allTags); | |||
| export const createTagRequest = (payload) => | |||
| postRequest(apiEndpoints.fileTags.filters, payload); | |||
| @@ -4,6 +4,9 @@ import { | |||
| FETCH_TAGS_ERR, | |||
| CHANGE_TAG_ISCHECKED_VALUE, | |||
| RESET_CHECKED_TAGS, | |||
| CREATE_TAG_ERR, | |||
| CREATE_TAG_REQ, | |||
| CREATE_TAG_SUCCESS, | |||
| } from "./tagsActionConstants"; | |||
| export const setTagsReq = () => ({ | |||
| @@ -28,3 +31,17 @@ export const changeTagIsCheckedValue = (payload) => ({ | |||
| export const resetIsCheckedTagsValue = () => ({ | |||
| type: RESET_CHECKED_TAGS, | |||
| }); | |||
| export const createTagReq = (payload) => ({ | |||
| type: CREATE_TAG_REQ, | |||
| payload, | |||
| }); | |||
| export const createTagError = () => ({ | |||
| type: CREATE_TAG_ERR, | |||
| }); | |||
| export const setCreateTag = (payload) => ({ | |||
| type: CREATE_TAG_SUCCESS, | |||
| payload, | |||
| }); | |||
| @@ -5,6 +5,7 @@ import { | |||
| } from "../actionHelpers"; | |||
| const FETCH_TAGS_SCOPE = "FETCH_TAGS"; | |||
| const CREATE_TAG_SCOPE = "CREATE_TAG"; | |||
| export const FETCH_TAGS_REQ = createFetchType(FETCH_TAGS_SCOPE); | |||
| export const FETCH_TAGS_ERR = createErrorType(FETCH_TAGS_SCOPE); | |||
| @@ -12,3 +13,7 @@ export const FETCH_TAGS_SUCCESS = createSuccessType(FETCH_TAGS_SCOPE); | |||
| export const CHANGE_TAG_ISCHECKED_VALUE = "CHANGE_TAG_ISCHECKED_VALUE"; | |||
| export const RESET_CHECKED_TAGS = "RESET_CHECKED_TAGS"; | |||
| export const CREATE_TAG_REQ = createFetchType(CREATE_TAG_SCOPE); | |||
| export const CREATE_TAG_ERR = createErrorType(CREATE_TAG_SCOPE); | |||
| export const CREATE_TAG_SUCCESS = createSuccessType(CREATE_TAG_SCOPE); | |||
| @@ -3,6 +3,8 @@ import { | |||
| FETCH_TAGS_SUCCESS, | |||
| CHANGE_TAG_ISCHECKED_VALUE, | |||
| RESET_CHECKED_TAGS, | |||
| CREATE_TAG_ERR, | |||
| CREATE_TAG_SUCCESS, | |||
| } from "../../actions/tags/tagsActionConstants"; | |||
| import createReducer from "../../utils/createReducer"; | |||
| @@ -17,6 +19,8 @@ export default createReducer( | |||
| [FETCH_TAGS_ERR]: setTagsErrorMessage, | |||
| [CHANGE_TAG_ISCHECKED_VALUE]: setIsCheckedTags, | |||
| [RESET_CHECKED_TAGS]: resetIsCheckedTags, | |||
| [CREATE_TAG_SUCCESS]: setCreateTagReducer, | |||
| [CREATE_TAG_ERR]: setCreateTagErrorMessage, | |||
| }, | |||
| initialState | |||
| ); | |||
| @@ -36,9 +40,7 @@ function setTagsErrorMessage(state, action) { | |||
| } | |||
| function setIsCheckedTags(state, action) { | |||
| const tmpIndex = state.tags.findIndex( | |||
| (x) => x.id === action.payload | |||
| ); | |||
| const tmpIndex = state.tags.findIndex((x) => x.id === action.payload); | |||
| if (tmpIndex === -1) { | |||
| return state; | |||
| @@ -58,3 +60,16 @@ function resetIsCheckedTags(state) { | |||
| tags: state.tags.map((tag) => ({ ...tag, isChecked: false })), | |||
| }; | |||
| } | |||
| function setCreateTagReducer(state) { | |||
| return { | |||
| ...state, | |||
| }; | |||
| } | |||
| function setCreateTagErrorMessage(state, action) { | |||
| return { | |||
| ...state, | |||
| errorMessage: action.payload, | |||
| }; | |||
| } | |||
| @@ -1,12 +1,17 @@ | |||
| import { all, call, put, takeLatest, takeEvery } from "redux-saga/effects"; | |||
| import { setTags, setTagsError } from "../actions/tags/tagsAction"; | |||
| import { | |||
| setTags, | |||
| setTagsError, | |||
| setCreateTag, | |||
| createTagError, | |||
| } from "../actions/tags/tagsAction"; | |||
| import { authScopeStringGetHelper } from "../../util/helpers/authScopeHelpers"; | |||
| import { JWT_TOKEN } from "../../constants/localStorage"; | |||
| import { addHeaderToken } from "../../request"; | |||
| import { rejectErrorCodeHelper } from "../../util/helpers/rejectErrorCodeHelper"; | |||
| import { FETCH_TAGS_REQ } from "../actions/tags/tagsActionConstants"; | |||
| import { FETCH_TAGS_REQ,CREATE_TAG_REQ } from "../actions/tags/tagsActionConstants"; | |||
| import { getAllTags } from "../../request/tagsRequest"; | |||
| import { getFileFilters } from "../../request/tagsRequest"; | |||
| import { getFileFilters, createTagRequest } from "../../request/tagsRequest"; | |||
| import { FILE_FILTERS_REQ } from "../actions/files/fileActionConstants"; | |||
| import { | |||
| getFileFiltersError, | |||
| @@ -39,7 +44,25 @@ export function* getFileFiltersGen() { | |||
| } | |||
| } | |||
| } | |||
| export function* createTagSaga({ payload }) { | |||
| console.log("Payload je to",payload) | |||
| try { | |||
| const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN); | |||
| yield call(addHeaderToken, JwtToken); | |||
| yield call(createTagRequest, { | |||
| name: payload.name, | |||
| }); | |||
| yield put(setCreateTag()); | |||
| if (payload.onSuccess) yield call(payload.onSuccess); | |||
| } catch (error) { | |||
| const errorMessage = yield call(rejectErrorCodeHelper, error); | |||
| yield put(createTagError(errorMessage)); | |||
| } | |||
| } | |||
| export default function* tagsSaga() { | |||
| yield all([takeLatest(FETCH_TAGS_REQ, getTags)]); | |||
| yield all([takeEvery(FILE_FILTERS_REQ, getFileFiltersGen)]); | |||
| yield all([takeEvery(CREATE_TAG_REQ, createTagSaga)]); | |||
| } | |||