| border-radius:6px; | border-radius:6px; | ||||
| outline:none; | outline:none; | ||||
| font-size: 18px; | font-size: 18px; | ||||
| } | |||||
| .files-custom-modal { | |||||
| width: 500px !important; | |||||
| } | |||||
| .files-edit-note { | |||||
| margin-bottom: 12px; | |||||
| } | |||||
| .files-edit-note textarea { | |||||
| width: 100%; | |||||
| } | |||||
| .files-custom-modal-buttons { | |||||
| display: flex; | |||||
| justify-content: flex-end; | |||||
| } | |||||
| .files-custom-modal-buttons button { | |||||
| margin-left: 8px; | |||||
| } | } |
| import { Pagination } from "@mui/material"; | |||||
| import { Button, Pagination } from "@mui/material"; | |||||
| import React from "react"; | import React from "react"; | ||||
| import { useEffect } from "react"; | import { useEffect } from "react"; | ||||
| import { useState } from "react"; | import { useState } from "react"; | ||||
| deleteFileReq, | deleteFileReq, | ||||
| getFileFiltersReq, | getFileFiltersReq, | ||||
| getFilesReq, | getFilesReq, | ||||
| updateFileReq, | |||||
| } from "../../store/actions/files/fileActions"; | } from "../../store/actions/files/fileActions"; | ||||
| import { setContent } from "../../store/actions/files/fileActions"; | import { setContent } from "../../store/actions/files/fileActions"; | ||||
| import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors"; | import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors"; | ||||
| import FileViewer from "react-file-viewer"; | import FileViewer from "react-file-viewer"; | ||||
| import { useLocation } from "react-router"; | import { useLocation } from "react-router"; | ||||
| import deleteIcon from "../../assets/images/delete.png"; | import deleteIcon from "../../assets/images/delete.png"; | ||||
| import editIcon from "../../assets/images/edit.png"; | |||||
| import xIcon from "../../assets/images/x.png"; | |||||
| import ConfirmDialog from "../../components/MUI/ConfirmDialog"; | import ConfirmDialog from "../../components/MUI/ConfirmDialog"; | ||||
| import CustomModal from "../../components/UI/CustomModal"; | |||||
| const FilesViewPage = ({ history }) => { | const FilesViewPage = ({ history }) => { | ||||
| const [toggleFiltersDrawer, setToggleFiltersDrawer] = useState(false); | const [toggleFiltersDrawer, setToggleFiltersDrawer] = useState(false); | ||||
| const { t } = useTranslation(); | const { t } = useTranslation(); | ||||
| const [isSearchFieldVisible, setIsSearchFieldVisible] = useState(false); | const [isSearchFieldVisible, setIsSearchFieldVisible] = useState(false); | ||||
| const [file, setFile] = useState(null); | const [file, setFile] = useState(null); | ||||
| const [fileForDelete, setFileForDelete] = useState({open: false, title: '', streamId: null}); | |||||
| const [openNoteModal, setOpenNoteModal] = useState({ | |||||
| open: false, | |||||
| note: null, | |||||
| streamId: "", | |||||
| }); | |||||
| const [fileForDelete, setFileForDelete] = useState({ | |||||
| open: false, | |||||
| title: "", | |||||
| streamId: null, | |||||
| }); | |||||
| const { state } = useLocation(); | const { state } = useLocation(); | ||||
| const dispatch = useDispatch(); | const dispatch = useDispatch(); | ||||
| } | } | ||||
| }; | }; | ||||
| const updateFileNoteHandler = () => { | |||||
| dispatch( | |||||
| updateFileReq({ id: openNoteModal.streamId, data: openNoteModal.note, onSuccessOpenNoteModal }) | |||||
| ); | |||||
| }; | |||||
| const onSuccessOpenNoteModal = () => { | |||||
| setOpenNoteModal({ | |||||
| open: false, | |||||
| note: null, | |||||
| streamId: "", | |||||
| }); | |||||
| }; | |||||
| return isLoading ? ( | return isLoading ? ( | ||||
| <div> | <div> | ||||
| <div className="l-t-rectangle"></div> | <div className="l-t-rectangle"></div> | ||||
| imgSrc={deleteIcon} | imgSrc={deleteIcon} | ||||
| content="Da li ste sigurni za brisanje dokumenta?" | content="Da li ste sigurni za brisanje dokumenta?" | ||||
| onClose={() => { | onClose={() => { | ||||
| setFileForDelete({open: false, title: '', streamId: null}); | |||||
| setFileForDelete({ open: false, title: "", streamId: null }); | |||||
| }} | }} | ||||
| onConfirm={() => { | onConfirm={() => { | ||||
| deleteFileHandler(fileForDelete.streamId) | |||||
| setFileForDelete({open: false, title: '', streamId: null}); | |||||
| deleteFileHandler(fileForDelete.streamId); | |||||
| setFileForDelete({ open: false, title: "", streamId: null }); | |||||
| }} | }} | ||||
| /> | /> | ||||
| <CustomModal | |||||
| classes="files-custom-modal" | |||||
| open={openNoteModal.open} | |||||
| onCloseModal={() => | |||||
| setOpenNoteModal({ open: false, note: null, streamId: "" }) | |||||
| } | |||||
| > | |||||
| <div className="add-pattern-modal-header"> | |||||
| <div className="add-pattern-modal-header-title"> | |||||
| <div className="add-pattern-modal-header-title-image"> | |||||
| <img src={editIcon} alt="plus" /> | |||||
| </div> | |||||
| <div className="add-pattern-modal-header-title-title"> | |||||
| <p>Edit text</p> | |||||
| </div> | |||||
| <div className="add-pattern-modal-header-title-sub"> | |||||
| <sub> | Note</sub> | |||||
| </div> | |||||
| </div> | |||||
| <div | |||||
| className="add-pattern-modal-header-close" | |||||
| onClick={() => | |||||
| setOpenNoteModal({ open: false, note: null, streamId: "" }) | |||||
| } | |||||
| > | |||||
| <img src={xIcon} alt="close" /> | |||||
| </div> | |||||
| </div> | |||||
| <div className="files-edit-note"> | |||||
| <textarea | |||||
| className="files-note" | |||||
| value={openNoteModal.note} | |||||
| onChange={(e) => | |||||
| setOpenNoteModal((oldState) => ({ | |||||
| ...oldState, | |||||
| note: e.target.value, | |||||
| })) | |||||
| } | |||||
| /> | |||||
| </div> | |||||
| <div className="files-custom-modal-buttons"> | |||||
| <Button | |||||
| type="button" | |||||
| variant="contained" | |||||
| className="c-btn c-btn--primary-outlined" | |||||
| onClick={() => | |||||
| setOpenNoteModal({ open: false, note: null, streamId: "" }) | |||||
| } | |||||
| > | |||||
| Close | |||||
| </Button> | |||||
| <Button | |||||
| type="button" | |||||
| variant="contained" | |||||
| className="c-btn c-btn--primary" | |||||
| onClick={updateFileNoteHandler} | |||||
| > | |||||
| Save Changes | |||||
| </Button> | |||||
| </div> | |||||
| </CustomModal> | |||||
| <div onClick={() => setIsSearchFieldVisible(false)}> | <div onClick={() => setIsSearchFieldVisible(false)}> | ||||
| <div className="l-t-rectangle"></div> | <div className="l-t-rectangle"></div> | ||||
| <div className="r-b-rectangle"></div> | <div className="r-b-rectangle"></div> | ||||
| <th>Tip dokumenta</th> | <th>Tip dokumenta</th> | ||||
| {file === null ? <th>Veličina dokumenta</th> : ""} | {file === null ? <th>Veličina dokumenta</th> : ""} | ||||
| <th>Obrisi dokument</th> | <th>Obrisi dokument</th> | ||||
| <th>Note</th> | |||||
| <th>Preuzmi dokument</th> | <th>Preuzmi dokument</th> | ||||
| </tr> | </tr> | ||||
| </thead> | </thead> | ||||
| <tr | <tr | ||||
| key={index} | key={index} | ||||
| className="secondaryRow" | className="secondaryRow" | ||||
| onClick={() => displayFile(n.file_stream, n.stream_id, n.file_type)} | |||||
| onClick={() => | |||||
| displayFile(n.file_stream, n.stream_id, n.file_type) | |||||
| } | |||||
| > | > | ||||
| <td className="docs-name">{n.fileName}</td> | <td className="docs-name">{n.fileName}</td> | ||||
| <td className="docs-name">{n.title}</td> | <td className="docs-name">{n.title}</td> | ||||
| <td className="profession"> | <td className="profession"> | ||||
| <IconButton | <IconButton | ||||
| className="c-btn c-btn--primary-outlined files-view-page-delete-btn" | className="c-btn c-btn--primary-outlined files-view-page-delete-btn" | ||||
| onClick={() => /* deleteFileHandler(n.stream_id) */setFileForDelete({open: true, title: n.title, streamId: n.stream_id})} | |||||
| onClick={() => | |||||
| setFileForDelete({ | |||||
| open: true, | |||||
| title: n.title, | |||||
| streamId: n.stream_id, | |||||
| }) | |||||
| } | |||||
| > | > | ||||
| <img | <img | ||||
| style={{ width: "12px", height: "12px" }} | style={{ width: "12px", height: "12px" }} | ||||
| /> | /> | ||||
| </IconButton> | </IconButton> | ||||
| </td> | </td> | ||||
| <td> | |||||
| <div onClick={stopPropagation}> | |||||
| <a | |||||
| className="applicant-cv-button" | |||||
| style={{ | |||||
| width: "100px", | |||||
| height: "40px", | |||||
| padding: 8, | |||||
| <td className="profession"> | |||||
| <IconButton | |||||
| className="c-btn c-btn--primary-outlined files-view-page-delete-btn" | |||||
| onClick={() => { | |||||
| setOpenNoteModal({ | |||||
| open: true, | |||||
| note: n.note, | |||||
| streamId: n.stream_id, | |||||
| }); | |||||
| }} | }} | ||||
| download={n.title} | |||||
| href={getHrefForDownload( | |||||
| n.file_type, | |||||
| n.file_stream | |||||
| )} | |||||
| > | > | ||||
| {t("common.download")} | |||||
| </a> | |||||
| </div> | |||||
| </td> | |||||
| <img | |||||
| style={{ width: "12px", height: "12px" }} | |||||
| src={editIcon} | |||||
| /> | |||||
| </IconButton> | |||||
| </td> | |||||
| <td> | |||||
| <div onClick={stopPropagation}> | |||||
| <a | |||||
| className="applicant-cv-button" | |||||
| style={{ | |||||
| width: "100px", | |||||
| height: "40px", | |||||
| padding: 8, | |||||
| }} | |||||
| download={n.title} | |||||
| href={getHrefForDownload( | |||||
| n.file_type, | |||||
| n.file_stream | |||||
| )} | |||||
| > | |||||
| {t("common.download")} | |||||
| </a> | |||||
| </div> | |||||
| </td> | |||||
| </tr> | </tr> | ||||
| ))} | ))} | ||||
| </tbody> | </tbody> |
| }, | }, | ||||
| files: { | files: { | ||||
| uploadFile: base + "/files", | uploadFile: base + "/files", | ||||
| updateFile: base + "/files/update-note", | |||||
| all: base + "/files/filtered", | all: base + "/files/filtered", | ||||
| deleteFile: base + "/files/delete-file", | deleteFile: base + "/files/delete-file", | ||||
| }, | }, |
| import { deleteRequest, postRequest } from "."; | |||||
| import { deleteRequest, postRequest, putRequest } from "."; | |||||
| import apiEndpoints from "./apiEndpoints"; | import apiEndpoints from "./apiEndpoints"; | ||||
| export const uploadFileRequest = (payload) => | export const uploadFileRequest = (payload) => | ||||
| postRequest(apiEndpoints.files.uploadFile, payload); | postRequest(apiEndpoints.files.uploadFile, payload); | ||||
| export const updateFileRequest = (payload) => | |||||
| putRequest(apiEndpoints.files.uploadFile + "/update-note/" + payload.id, {note: payload.data}); | |||||
| export const deleteFileRequest = (id) => | export const deleteFileRequest = (id) => | ||||
| deleteRequest(apiEndpoints.files.deleteFile + "/" + id); | deleteRequest(apiEndpoints.files.deleteFile + "/" + id); |
| export const FETCH_FILES_SUCCESS = createSuccessType(FETCH_FILES_SCOPE); | export const FETCH_FILES_SUCCESS = createSuccessType(FETCH_FILES_SCOPE); | ||||
| export const FETCH_FILES_LOADING = createLoadingType(FETCH_FILES_SCOPE); | export const FETCH_FILES_LOADING = createLoadingType(FETCH_FILES_SCOPE); | ||||
| const UPDATE_FILE_SCOPE = "UPDATE_FILE"; | |||||
| export const UPDATE_FILE_REQ = createFetchType(UPDATE_FILE_SCOPE); | |||||
| export const UPDATE_FILE_ERR = createErrorType(UPDATE_FILE_SCOPE); | |||||
| export const UPDATE_FILE_SUCCESS = createSuccessType(UPDATE_FILE_SCOPE); | |||||
| export const UPDATE_FILE_LOADING = createLoadingType(UPDATE_FILE_SCOPE); | |||||
| const DELETE_FILE_SCOPE = "DELETE_FILE" | const DELETE_FILE_SCOPE = "DELETE_FILE" | ||||
| export const DELETE_FILE_REQ = createFetchType(DELETE_FILE_SCOPE) | export const DELETE_FILE_REQ = createFetchType(DELETE_FILE_SCOPE) | ||||
| export const DELETE_FILE_ERR = createErrorType(DELETE_FILE_SCOPE) | export const DELETE_FILE_ERR = createErrorType(DELETE_FILE_SCOPE) |
| SET_CONTENT, | SET_CONTENT, | ||||
| DELETE_FILE_REQ, | DELETE_FILE_REQ, | ||||
| DELETE_FILE_ERR, | DELETE_FILE_ERR, | ||||
| DELETE_FILE_SUCCESS | |||||
| DELETE_FILE_SUCCESS, | |||||
| UPDATE_FILE_REQ, | |||||
| UPDATE_FILE_ERR, | |||||
| UPDATE_FILE_SUCCESS | |||||
| } from "./fileActionConstants"; | } from "./fileActionConstants"; | ||||
| export const getFileFiltersReq = () => ({ | export const getFileFiltersReq = () => ({ | ||||
| payload | payload | ||||
| }) | }) | ||||
| export const updateFileReq = (payload) => ({ | |||||
| type: UPDATE_FILE_REQ, | |||||
| payload | |||||
| }); | |||||
| export const updateFileError = (payload) => ({ | |||||
| type: UPDATE_FILE_ERR, | |||||
| payload, | |||||
| }); | |||||
| export const updateFileAction = (payload) => ({ | |||||
| type: UPDATE_FILE_SUCCESS, | |||||
| payload | |||||
| }); | |||||
| export const deleteFileReq = (payload) => ({ | export const deleteFileReq = (payload) => ({ | ||||
| type: DELETE_FILE_REQ, | type: DELETE_FILE_REQ, | ||||
| payload | payload |
| FETCH_FILES_ERR, | FETCH_FILES_ERR, | ||||
| FETCH_FILES_SUCCESS, | FETCH_FILES_SUCCESS, | ||||
| } from "../../actions/files/fileActionConstants"; | } from "../../actions/files/fileActionConstants"; | ||||
| import { | |||||
| UPDATE_FILE_SUCCESS, | |||||
| UPDATE_FILE_ERR, | |||||
| } from "../../actions/files/fileActionConstants"; | |||||
| import { | import { | ||||
| DELETE_FILE_ERR, | DELETE_FILE_ERR, | ||||
| DELETE_FILE_SUCCESS, | DELETE_FILE_SUCCESS, | ||||
| { | { | ||||
| [FETCH_FILES_SUCCESS]: setFiles, | [FETCH_FILES_SUCCESS]: setFiles, | ||||
| [FETCH_FILES_ERR]: setFilesErrorMessage, | [FETCH_FILES_ERR]: setFilesErrorMessage, | ||||
| [UPDATE_FILE_SUCCESS]: updateFileReducer, | |||||
| [UPDATE_FILE_ERR]: updateFileError, | |||||
| [DELETE_FILE_SUCCESS]: deleteFileReducer, | [DELETE_FILE_SUCCESS]: deleteFileReducer, | ||||
| [DELETE_FILE_ERR]: deleteFileReducerError, | [DELETE_FILE_ERR]: deleteFileReducerError, | ||||
| }, | }, | ||||
| }; | }; | ||||
| } | } | ||||
| function updateFileReducer(state, action) { | |||||
| const newData = state.data.data.map((dat) => | |||||
| dat.stream_id === action.payload.id | |||||
| ? { ...dat, note: action.payload.data } | |||||
| : dat | |||||
| ); | |||||
| return { | |||||
| ...state, | |||||
| data: { ...state.data, data: newData }, | |||||
| }; | |||||
| } | |||||
| function updateFileError(state, action) { | |||||
| return { | |||||
| ...state, | |||||
| fetchFilesErrorMessage: action.payload, | |||||
| }; | |||||
| } | |||||
| function deleteFileReducer(state, action) { | function deleteFileReducer(state, action) { | ||||
| const newArr = state.data.data.filter(x => x.stream_id !== action.payload) | |||||
| return { ...state, data: {...state.data, data: newArr} }; | |||||
| const newArr = state.data.data.filter((x) => x.stream_id !== action.payload); | |||||
| return { ...state, data: { ...state.data, data: newArr } }; | |||||
| } | } | ||||
| function deleteFileReducerError(state, action) { | function deleteFileReducerError(state, action) { |
| import { addHeaderToken } from "../../request"; | import { addHeaderToken } from "../../request"; | ||||
| import { rejectErrorCodeHelper } from "../../util/helpers/rejectErrorCodeHelper"; | import { rejectErrorCodeHelper } from "../../util/helpers/rejectErrorCodeHelper"; | ||||
| import { UPLOAD_FILE_REQ } from "../actions/uploadFile/uploadFileActionConstants"; | import { UPLOAD_FILE_REQ } from "../actions/uploadFile/uploadFileActionConstants"; | ||||
| import { deleteFileRequest, uploadFileRequest } from "../../request/filesRequest"; | |||||
| import { | |||||
| deleteFileRequest, | |||||
| updateFileRequest, | |||||
| uploadFileRequest, | |||||
| } from "../../request/filesRequest"; | |||||
| import { getAllFilesReq } from "../../request/fileRequests"; | import { getAllFilesReq } from "../../request/fileRequests"; | ||||
| import { DELETE_FILE_REQ, FETCH_FILES_REQ } from "../actions/files/fileActionConstants"; | |||||
| import { deleteFileAction, deleteFileError, getFileError, getFileSuccess } from "../actions/files/fileActions"; | |||||
| import { | |||||
| DELETE_FILE_REQ, | |||||
| FETCH_FILES_REQ, | |||||
| UPDATE_FILE_REQ, | |||||
| } from "../actions/files/fileActionConstants"; | |||||
| import { | |||||
| deleteFileAction, | |||||
| deleteFileError, | |||||
| getFileError, | |||||
| getFileSuccess, | |||||
| updateFileAction, | |||||
| } from "../actions/files/fileActions"; | |||||
| export function* uploadFileSaga({ payload }) { | export function* uploadFileSaga({ payload }) { | ||||
| try { | try { | ||||
| } | } | ||||
| } | } | ||||
| export function* updateFileSaga({ payload }) { | |||||
| try { | |||||
| const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN); | |||||
| yield call(addHeaderToken, JwtToken); | |||||
| yield call(updateFileRequest, { id: payload.id, data: payload.data }); | |||||
| yield put(updateFileAction(payload)); | |||||
| payload.onSuccessOpenNoteModal(); | |||||
| } catch (error) { | |||||
| if (error.response && error.response.data) { | |||||
| const errorMessage = yield call(rejectErrorCodeHelper, error); | |||||
| yield put(deleteFileError(errorMessage)); | |||||
| } | |||||
| } | |||||
| } | |||||
| export function* deleteFileSaga({ payload }) { | export function* deleteFileSaga({ payload }) { | ||||
| try { | try { | ||||
| const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN); | const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN); | ||||
| yield call(addHeaderToken, JwtToken); | yield call(addHeaderToken, JwtToken); | ||||
| yield call(deleteFileRequest, payload.id); | yield call(deleteFileRequest, payload.id); | ||||
| yield put(deleteFileAction(payload.id)) | |||||
| yield put(deleteFileAction(payload.id)); | |||||
| } catch (error) { | } catch (error) { | ||||
| if (error.response && error.response.data) { | if (error.response && error.response.data) { | ||||
| const errorMessage = yield call(rejectErrorCodeHelper, error); | const errorMessage = yield call(rejectErrorCodeHelper, error); | ||||
| export default function* filesSaga() { | export default function* filesSaga() { | ||||
| yield all([takeLatest(UPLOAD_FILE_REQ, uploadFileSaga)]); | yield all([takeLatest(UPLOAD_FILE_REQ, uploadFileSaga)]); | ||||
| yield all([takeEvery(FETCH_FILES_REQ, getAll)]); | yield all([takeEvery(FETCH_FILES_REQ, getAll)]); | ||||
| yield all([takeEvery(UPDATE_FILE_REQ, updateFileSaga)]); | |||||
| yield all([takeLatest(DELETE_FILE_REQ, deleteFileSaga)]); | yield all([takeLatest(DELETE_FILE_REQ, deleteFileSaga)]); | ||||
| } | } |