bronjaermin 2 лет назад
Родитель
Сommit
7c7ce2adce

+ 21
- 0
src/assets/styles/components/_files.scss Просмотреть файл

@@ -116,4 +116,25 @@
border-radius:6px;
outline:none;
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;
}

+ 138
- 24
src/pages/FilesPage/FilesViewPage.js Просмотреть файл

@@ -1,4 +1,4 @@
import { Pagination } from "@mui/material";
import { Button, Pagination } from "@mui/material";
import React from "react";
import { useEffect } from "react";
import { useState } from "react";
@@ -11,6 +11,7 @@ import {
deleteFileReq,
getFileFiltersReq,
getFilesReq,
updateFileReq,
} from "../../store/actions/files/fileActions";
import { setContent } from "../../store/actions/files/fileActions";
import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors";
@@ -23,7 +24,10 @@ import PropTypes from "prop-types";
import FileViewer from "react-file-viewer";
import { useLocation } from "react-router";
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 CustomModal from "../../components/UI/CustomModal";

const FilesViewPage = ({ history }) => {
const [toggleFiltersDrawer, setToggleFiltersDrawer] = useState(false);
@@ -33,7 +37,16 @@ const FilesViewPage = ({ history }) => {
const { t } = useTranslation();
const [isSearchFieldVisible, setIsSearchFieldVisible] = useState(false);
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 dispatch = useDispatch();
@@ -183,6 +196,20 @@ const FilesViewPage = ({ history }) => {
}
};

const updateFileNoteHandler = () => {
dispatch(
updateFileReq({ id: openNoteModal.streamId, data: openNoteModal.note, onSuccessOpenNoteModal })
);
};

const onSuccessOpenNoteModal = () => {
setOpenNoteModal({
open: false,
note: null,
streamId: "",
});
};

return isLoading ? (
<div>
<div className="l-t-rectangle"></div>
@@ -200,13 +227,74 @@ const FilesViewPage = ({ history }) => {
imgSrc={deleteIcon}
content="Da li ste sigurni za brisanje dokumenta?"
onClose={() => {
setFileForDelete({open: false, title: '', streamId: null});
setFileForDelete({ open: false, title: "", streamId: null });
}}
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 className="l-t-rectangle"></div>
<div className="r-b-rectangle"></div>
@@ -286,6 +374,7 @@ const FilesViewPage = ({ history }) => {
<th>Tip dokumenta</th>
{file === null ? <th>Veličina dokumenta</th> : ""}
<th>Obrisi dokument</th>
<th>Note</th>
<th>Preuzmi dokument</th>
</tr>
</thead>
@@ -296,7 +385,9 @@ const FilesViewPage = ({ history }) => {
<tr
key={index}
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.title}</td>
@@ -309,7 +400,13 @@ const FilesViewPage = ({ history }) => {
<td className="profession">
<IconButton
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
style={{ width: "12px", height: "12px" }}
@@ -317,25 +414,42 @@ const FilesViewPage = ({ history }) => {
/>
</IconButton>
</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>
))}
</tbody>

+ 1
- 0
src/request/apiEndpoints.js Просмотреть файл

@@ -83,6 +83,7 @@ export default {
},
files: {
uploadFile: base + "/files",
updateFile: base + "/files/update-note",
all: base + "/files/filtered",
deleteFile: base + "/files/delete-file",
},

+ 3
- 1
src/request/filesRequest.js Просмотреть файл

@@ -1,7 +1,9 @@
import { deleteRequest, postRequest } from ".";
import { deleteRequest, postRequest, putRequest } from ".";
import apiEndpoints from "./apiEndpoints";

export const uploadFileRequest = (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) =>
deleteRequest(apiEndpoints.files.deleteFile + "/" + id);

+ 6
- 0
src/store/actions/files/fileActionConstants.js Просмотреть файл

@@ -21,6 +21,12 @@ export const FETCH_FILES_ERR = createErrorType(FETCH_FILES_SCOPE);
export const FETCH_FILES_SUCCESS = createSuccessType(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"
export const DELETE_FILE_REQ = createFetchType(DELETE_FILE_SCOPE)
export const DELETE_FILE_ERR = createErrorType(DELETE_FILE_SCOPE)

+ 19
- 1
src/store/actions/files/fileActions.js Просмотреть файл

@@ -11,7 +11,10 @@ import {
SET_CONTENT,
DELETE_FILE_REQ,
DELETE_FILE_ERR,
DELETE_FILE_SUCCESS
DELETE_FILE_SUCCESS,
UPDATE_FILE_REQ,
UPDATE_FILE_ERR,
UPDATE_FILE_SUCCESS
} from "./fileActionConstants";

export const getFileFiltersReq = () => ({
@@ -61,6 +64,21 @@ export const setContent = (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) => ({
type: DELETE_FILE_REQ,
payload

+ 28
- 2
src/store/reducers/files/getFilesReducer.js Просмотреть файл

@@ -3,6 +3,10 @@ import {
FETCH_FILES_ERR,
FETCH_FILES_SUCCESS,
} from "../../actions/files/fileActionConstants";
import {
UPDATE_FILE_SUCCESS,
UPDATE_FILE_ERR,
} from "../../actions/files/fileActionConstants";
import {
DELETE_FILE_ERR,
DELETE_FILE_SUCCESS,
@@ -17,6 +21,8 @@ export default createReducer(
{
[FETCH_FILES_SUCCESS]: setFiles,
[FETCH_FILES_ERR]: setFilesErrorMessage,
[UPDATE_FILE_SUCCESS]: updateFileReducer,
[UPDATE_FILE_ERR]: updateFileError,
[DELETE_FILE_SUCCESS]: deleteFileReducer,
[DELETE_FILE_ERR]: deleteFileReducerError,
},
@@ -37,9 +43,29 @@ function setFilesErrorMessage(state, action) {
};
}

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) {
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) {

+ 34
- 4
src/store/saga/filesSaga.js Просмотреть файл

@@ -8,10 +8,24 @@ import { JWT_TOKEN } from "../../constants/localStorage";
import { addHeaderToken } from "../../request";
import { rejectErrorCodeHelper } from "../../util/helpers/rejectErrorCodeHelper";
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 { 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 }) {
try {
@@ -48,12 +62,27 @@ export function* getAll({ payload }) {
}
}

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 }) {
try {
const JwtToken = yield call(authScopeStringGetHelper, JWT_TOKEN);
yield call(addHeaderToken, JwtToken);
yield call(deleteFileRequest, payload.id);
yield put(deleteFileAction(payload.id))
yield put(deleteFileAction(payload.id));
} catch (error) {
if (error.response && error.response.data) {
const errorMessage = yield call(rejectErrorCodeHelper, error);
@@ -65,5 +94,6 @@ export function* deleteFileSaga({ payload }) {
export default function* filesSaga() {
yield all([takeLatest(UPLOAD_FILE_REQ, uploadFileSaga)]);
yield all([takeEvery(FETCH_FILES_REQ, getAll)]);
yield all([takeEvery(UPDATE_FILE_REQ, updateFileSaga)]);
yield all([takeLatest(DELETE_FILE_REQ, deleteFileSaga)]);
}

Загрузка…
Отмена
Сохранить