| // STATS_PAGE, | // STATS_PAGE, | ||||
| REGISTER_PAGE, | REGISTER_PAGE, | ||||
| // CREATE_AD_PAGE, | // CREATE_AD_PAGE, | ||||
| FILES_PAGE, | |||||
| FILES_VIEW_PAGE, | FILES_VIEW_PAGE, | ||||
| ADD_FILE, | |||||
| FILES_PAGE, | |||||
| } from "./constants/pages"; | } from "./constants/pages"; | ||||
| import LoginPage from "./pages/LoginPage/LoginPageMUI"; | import LoginPage from "./pages/LoginPage/LoginPageMUI"; | ||||
| // import StatsPage from "./pages/StatsPage/StatsPage"; | // import StatsPage from "./pages/StatsPage/StatsPage"; | ||||
| import RegisterPage from "./pages/RegisterPage/RegisterPage"; | import RegisterPage from "./pages/RegisterPage/RegisterPage"; | ||||
| // import CreateAdPage from "./pages/AdsPage/CreateAdPage"; | // import CreateAdPage from "./pages/AdsPage/CreateAdPage"; | ||||
| import FilesPage from "./pages/FilesPage/FilesPage"; | |||||
| import FilesViewPage from "./pages/FilesPage/FilesViewPage"; | import FilesViewPage from "./pages/FilesPage/FilesViewPage"; | ||||
| import AddFile from "./pages/FilesPage/AddFile"; | |||||
| import FilesPage from "./pages/FilesPage/FilesPage"; | |||||
| const AppRoutes = () => { | const AppRoutes = () => { | ||||
| const dispatch = useDispatch(); | const dispatch = useDispatch(); | ||||
| <PrivateRoute exact path={USERS_PAGE} component={UsersPage} /> | <PrivateRoute exact path={USERS_PAGE} component={UsersPage} /> | ||||
| {/* <PrivateRoute exact path={CANDIDATES_PAGE} component={CandidatesPage} /> | {/* <PrivateRoute exact path={CANDIDATES_PAGE} component={CandidatesPage} /> | ||||
| <PrivateRoute exact path={CREATE_AD_PAGE} component={CreateAdPage} /> */} | <PrivateRoute exact path={CREATE_AD_PAGE} component={CreateAdPage} /> */} | ||||
| <PrivateRoute exact path={FILES_PAGE} component={FilesPage} /> | |||||
| {/* <PrivateRoute exact path={FILES_PAGE} component={FilesPage} /> */} | |||||
| <PrivateRoute exact path={FILES_VIEW_PAGE} component={FilesViewPage} /> | <PrivateRoute exact path={FILES_VIEW_PAGE} component={FilesViewPage} /> | ||||
| <PrivateRoute exact path={ADD_FILE} component={AddFile}/> | |||||
| <PrivateRoute exact path={FILES_PAGE} component={FilesPage}/> | |||||
| {/* <PrivateRoute | {/* <PrivateRoute | ||||
| exact | exact | ||||
| path={CANDIDATES_DETAILS_PAGE} | path={CANDIDATES_DETAILS_PAGE} |
| const NavbarComponent = () => { | const NavbarComponent = () => { | ||||
| const navItems = [ | const navItems = [ | ||||
| "users", | "users", | ||||
| "filesView", | |||||
| // "signOut" | |||||
| "files" | |||||
| ]; | ]; | ||||
| const { pathname } = useLocation(); | const { pathname } = useLocation(); | ||||
| const [openDrawer, setOpenDrawer] = useState(false); | const [openDrawer, setOpenDrawer] = useState(false); |
| export const REGISTER_PAGE = '/register'; | export const REGISTER_PAGE = '/register'; | ||||
| export const CREATE_AD_PAGE = '/create-ad'; | export const CREATE_AD_PAGE = '/create-ad'; | ||||
| export const FILES_PAGE = '/files'; | export const FILES_PAGE = '/files'; | ||||
| export const FILES_VIEW_PAGE = '/filesView'; | |||||
| export const FILES_VIEW_PAGE = '/files-view'; | |||||
| export const ADD_FILE = '/add-file'; |
| users: "Users", | users: "Users", | ||||
| signOut: "Sign Out", | signOut: "Sign Out", | ||||
| schedule:"Schedule", | schedule:"Schedule", | ||||
| files:"Files", | |||||
| filesView:"Files View", | |||||
| files:"Files" | |||||
| }, | }, | ||||
| ads: { | ads: { | ||||
| activeAds: "Active Ads", | activeAds: "Active Ads", |
| patterns: "Šabloni", | patterns: "Šabloni", | ||||
| statistics: "Statistika", | statistics: "Statistika", | ||||
| users: "Korisnici", | users: "Korisnici", | ||||
| files:"Fajlovi", | |||||
| signOut: "Izloguj se", | signOut: "Izloguj se", | ||||
| filesView:"Pregled fajlova", | |||||
| files:"Fajlovi" | |||||
| }, | }, | ||||
| ads: { | ads: { | ||||
| activeAds: "Aktivni Oglasi", | activeAds: "Aktivni Oglasi", |
| import React, { useState } from "react"; | |||||
| import { Checkbox, FormControlLabel, MenuItem, Select } from "@mui/material"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| import uploadIcon from "../../assets/images/upload.png"; | |||||
| import IconButton from "../../components/IconButton/IconButton"; | |||||
| import { useSelector, useDispatch } from "react-redux"; | |||||
| import { selectCategories } from "../../store/selectors/categoriesSelector"; | |||||
| import { useEffect } from "react"; | |||||
| import { setCategoriesReq } from "../../store/actions/categories/categoriesAction"; | |||||
| import { | |||||
| changeTagIsCheckedValue, | |||||
| resetIsCheckedTagsValue, | |||||
| setTagsReq, | |||||
| } 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 PropTypes from "prop-types"; | |||||
| const AddFile = ({history}) => { | |||||
| const [dropzoneActive, setDropzoneActive] = useState(false); | |||||
| const [pdfFile, setPdfFile] = useState(null); | |||||
| const [title, setTitle] = useState(""); | |||||
| const dispatch = useDispatch(); | |||||
| const categories = useSelector(selectCategories); | |||||
| const tags = useSelector(selectTags); | |||||
| const [selectedCategory, setSelectedCategory] = useState(null); | |||||
| const { t } = useTranslation(); | |||||
| useEffect(() => { | |||||
| dispatch(setCategoriesReq()); | |||||
| dispatch(setTagsReq()); | |||||
| }, []); | |||||
| const onSuccessUploadFile = () => { | |||||
| dispatch(resetIsCheckedTagsValue()); | |||||
| setPdfFile(null); | |||||
| setTitle("") | |||||
| }; | |||||
| const handleDrop = (e) => { | |||||
| e.preventDefault(); | |||||
| const selectedFile = e.dataTransfer.files[0]; | |||||
| setPdfFile(selectedFile); | |||||
| }; | |||||
| const handleChangeInputFile = (e) => { | |||||
| const selectedFile = e.target.files[0]; | |||||
| setPdfFile(selectedFile); | |||||
| }; | |||||
| const selectCategoryHandler = (e) => { | |||||
| setSelectedCategory(e.target.value); | |||||
| }; | |||||
| const onChangeTagsCheckbox = (id) => { | |||||
| dispatch(changeTagIsCheckedValue(id)); | |||||
| }; | |||||
| const uploadFileHandler = () => { | |||||
| const tagsIds = tags | |||||
| .filter((tag) => tag.isChecked === true) | |||||
| .map((tag) => Number(tag.id)); | |||||
| dispatch( | |||||
| uploadFileReq({ | |||||
| title, | |||||
| categoryId: selectedCategory, | |||||
| tagsIds, | |||||
| fileToUpload: pdfFile, | |||||
| onSuccessUploadFile, | |||||
| }) | |||||
| ); | |||||
| }; | |||||
| return ( | |||||
| <div className="files-page"> | |||||
| <div className="files-page-card"> | |||||
| <div className="files-page-card-title"> | |||||
| <h1>Title</h1> | |||||
| </div> | |||||
| <div className="files-page-card-content"> | |||||
| <input | |||||
| type="text" | |||||
| className="create-ad-form-control-first-step-input" | |||||
| onChange={(e) => setTitle(e.target.value)} | |||||
| value={title} | |||||
| placeholder="Document Title" | |||||
| /> | |||||
| </div> | |||||
| </div> | |||||
| <div className="files-page-card"> | |||||
| <div className="files-page-card-title"> | |||||
| <h1>Categories</h1> | |||||
| </div> | |||||
| <div className="files-page-card-content"> | |||||
| <Select | |||||
| labelId="files-page-card-content-select" | |||||
| id="files-page-card-content-selectt" | |||||
| sx={{ width: "100%", borderColor: "#e4e4e4 !important" }} | |||||
| onChange={selectCategoryHandler} | |||||
| value={selectedCategory} | |||||
| > | |||||
| {categories && | |||||
| categories.map((category, index) => ( | |||||
| <MenuItem | |||||
| key={index} | |||||
| sx={{ textAlign: "left" }} | |||||
| value={category.id} | |||||
| > | |||||
| {category.name} | |||||
| </MenuItem> | |||||
| ))} | |||||
| </Select> | |||||
| </div> | |||||
| </div> | |||||
| <div className="files-page-card"> | |||||
| <div className="files-page-card-title"> | |||||
| <h1>Tags</h1> | |||||
| </div> | |||||
| <div className="files-page-card-content"> | |||||
| <div className="files-page-card-content-checkboxes"> | |||||
| {tags && | |||||
| tags.map((tag) => ( | |||||
| <FormControlLabel | |||||
| key={tag.id} | |||||
| control={ | |||||
| <Checkbox | |||||
| value={tag.name} | |||||
| checked={tag.isChecked} | |||||
| onChange={onChangeTagsCheckbox.bind(this, tag.id)} | |||||
| className="create-ad-second-step-checkbox" | |||||
| /> | |||||
| } | |||||
| label={tag.name} | |||||
| /> | |||||
| ))} | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div className="files-page-card"> | |||||
| <div className="files-page-card-title"> | |||||
| <h1>Drag & Drop File</h1> | |||||
| </div> | |||||
| <div className="files-page-card-content"> | |||||
| <div | |||||
| className="uploadCV-input files-page-drag-and-drop" | |||||
| onDragOver={(e) => { | |||||
| setDropzoneActive(true); | |||||
| e.preventDefault(); | |||||
| }} | |||||
| onDragLeave={(e) => { | |||||
| setDropzoneActive(false); | |||||
| e.preventDefault(); | |||||
| }} | |||||
| onDrop={(e) => handleDrop(e)} | |||||
| style={{ | |||||
| backgroundColor: dropzoneActive ? "#F4F4F4" : "#ffffff", | |||||
| }} | |||||
| > | |||||
| <div className="uploadCV-input-sub-container"> | |||||
| <img src={uploadIcon} /> | |||||
| <div className="uploadCV-input-sub-container"> | |||||
| {pdfFile !== null ? ( | |||||
| <p>{pdfFile.name}</p> | |||||
| ) : ( | |||||
| <> | |||||
| <p> | |||||
| {t("ads.dragPdf1")} | |||||
| <label | |||||
| htmlFor="upload-file" | |||||
| style={{ | |||||
| cursor: "pointer", | |||||
| textDecoration: "underline", | |||||
| color: "#1E92D0", | |||||
| }} | |||||
| > | |||||
| {t("common.search")} | |||||
| </label> | |||||
| {t("ads.dragPdf2")} | |||||
| </p> | |||||
| <input | |||||
| type="file" | |||||
| name="photo" | |||||
| id="upload-file" | |||||
| style={{ display: "none", zIndex: -1 }} | |||||
| value={pdfFile} | |||||
| data-testid="apply-for-ad-modal-fourth-stage-pdf-input" | |||||
| // accept=".pdf" | |||||
| onChange={handleChangeInputFile} | |||||
| /> | |||||
| </> | |||||
| )} | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div className="files-page-card"> | |||||
| <div className="files-page-card-add-button" style={{alignItems:'center'}}> | |||||
| <p | |||||
| className="applicant-ads-back-button" | |||||
| onClick={() => history.push(FILES_VIEW_PAGE)} | |||||
| > | |||||
| Nazad na sve fajlove | |||||
| </p> | |||||
| <IconButton | |||||
| className="c-btn ads-page-btn c-btn--primary add-ad-btn" | |||||
| onClick={uploadFileHandler} | |||||
| > | |||||
| + {t("files.addFile")} | |||||
| </IconButton> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| ); | |||||
| }; | |||||
| AddFile.propTypes = { | |||||
| history: PropTypes.shape({ | |||||
| replace: PropTypes.func, | |||||
| push: PropTypes.func, | |||||
| location: PropTypes.shape({ | |||||
| pathname: PropTypes.string, | |||||
| }), | |||||
| }), | |||||
| }; | |||||
| export default AddFile; |
| import React, { useState } from "react"; | |||||
| import { Checkbox, FormControlLabel, MenuItem, Select } from "@mui/material"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| import uploadIcon from "../../assets/images/upload.png"; | |||||
| import IconButton from "../../components/IconButton/IconButton"; | |||||
| import { useSelector, useDispatch } from "react-redux"; | |||||
| import { selectCategories } from "../../store/selectors/categoriesSelector"; | |||||
| import { useEffect } from "react"; | |||||
| import React, { useEffect } from 'react' | |||||
| import { setCategoriesReq } from "../../store/actions/categories/categoriesAction"; | import { setCategoriesReq } from "../../store/actions/categories/categoriesAction"; | ||||
| import { | |||||
| changeTagIsCheckedValue, | |||||
| resetIsCheckedTagsValue, | |||||
| setTagsReq, | |||||
| } 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 PropTypes from "prop-types"; | |||||
| import { selectCategories } from "../../store/selectors/categoriesSelector"; | |||||
| import { useDispatch, useSelector } from 'react-redux'; | |||||
| const FilesPage = ({history}) => { | |||||
| const [dropzoneActive, setDropzoneActive] = useState(false); | |||||
| const [pdfFile, setPdfFile] = useState(null); | |||||
| const [title, setTitle] = useState(""); | |||||
| const dispatch = useDispatch(); | |||||
| const FilesPage = () => { | |||||
| const dispatch = useDispatch() | |||||
| const categories = useSelector(selectCategories); | const categories = useSelector(selectCategories); | ||||
| const tags = useSelector(selectTags); | |||||
| const [selectedCategory, setSelectedCategory] = useState(null); | |||||
| const { t } = useTranslation(); | |||||
| useEffect(() => { | useEffect(() => { | ||||
| dispatch(setCategoriesReq()); | dispatch(setCategoriesReq()); | ||||
| dispatch(setTagsReq()); | |||||
| }, []); | |||||
| const onSuccessUploadFile = () => { | |||||
| dispatch(resetIsCheckedTagsValue()); | |||||
| setPdfFile(null); | |||||
| setTitle("") | |||||
| }; | |||||
| const handleDrop = (e) => { | |||||
| e.preventDefault(); | |||||
| const selectedFile = e.dataTransfer.files[0]; | |||||
| setPdfFile(selectedFile); | |||||
| }; | |||||
| const handleChangeInputFile = (e) => { | |||||
| const selectedFile = e.target.files[0]; | |||||
| setPdfFile(selectedFile); | |||||
| }; | |||||
| const selectCategoryHandler = (e) => { | |||||
| setSelectedCategory(e.target.value); | |||||
| }; | |||||
| const onChangeTagsCheckbox = (id) => { | |||||
| dispatch(changeTagIsCheckedValue(id)); | |||||
| }; | |||||
| const uploadFileHandler = () => { | |||||
| const tagsIds = tags | |||||
| .filter((tag) => tag.isChecked === true) | |||||
| .map((tag) => Number(tag.id)); | |||||
| dispatch( | |||||
| uploadFileReq({ | |||||
| title, | |||||
| categoryId: selectedCategory, | |||||
| tagsIds, | |||||
| fileToUpload: pdfFile, | |||||
| onSuccessUploadFile, | |||||
| }) | |||||
| ); | |||||
| }; | |||||
| }) | |||||
| return ( | return ( | ||||
| <div className="files-page"> | |||||
| <div className="files-page-card"> | |||||
| <div className="files-page-card-title"> | |||||
| <h1>Title</h1> | |||||
| </div> | |||||
| <div className="files-page-card-content"> | |||||
| <input | |||||
| type="text" | |||||
| className="create-ad-form-control-first-step-input" | |||||
| onChange={(e) => setTitle(e.target.value)} | |||||
| value={title} | |||||
| placeholder="Document Title" | |||||
| /> | |||||
| </div> | |||||
| </div> | |||||
| <div className="files-page-card"> | |||||
| <div className="files-page-card-title"> | |||||
| <h1>Categories</h1> | |||||
| </div> | |||||
| <div className="files-page-card-content"> | |||||
| <Select | |||||
| labelId="files-page-card-content-select" | |||||
| id="files-page-card-content-selectt" | |||||
| sx={{ width: "100%", borderColor: "#e4e4e4 !important" }} | |||||
| onChange={selectCategoryHandler} | |||||
| value={selectedCategory} | |||||
| > | |||||
| {categories && | |||||
| categories.map((category, index) => ( | |||||
| <MenuItem | |||||
| key={index} | |||||
| sx={{ textAlign: "left" }} | |||||
| value={category.id} | |||||
| > | |||||
| {category.name} | |||||
| </MenuItem> | |||||
| ))} | |||||
| </Select> | |||||
| </div> | |||||
| </div> | |||||
| <div className="files-page-card"> | |||||
| <div className="files-page-card-title"> | |||||
| <h1>Tags</h1> | |||||
| </div> | |||||
| <div className="files-page-card-content"> | |||||
| <div className="files-page-card-content-checkboxes"> | |||||
| {tags && | |||||
| tags.map((tag) => ( | |||||
| <FormControlLabel | |||||
| key={tag.id} | |||||
| control={ | |||||
| <Checkbox | |||||
| value={tag.name} | |||||
| checked={tag.isChecked} | |||||
| onChange={onChangeTagsCheckbox.bind(this, tag.id)} | |||||
| className="create-ad-second-step-checkbox" | |||||
| /> | |||||
| } | |||||
| label={tag.name} | |||||
| /> | |||||
| ))} | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div className="files-page-card"> | |||||
| <div className="files-page-card-title"> | |||||
| <h1>Drag & Drop File</h1> | |||||
| </div> | |||||
| <div className="files-page-card-content"> | |||||
| <div | |||||
| className="uploadCV-input files-page-drag-and-drop" | |||||
| onDragOver={(e) => { | |||||
| setDropzoneActive(true); | |||||
| e.preventDefault(); | |||||
| }} | |||||
| onDragLeave={(e) => { | |||||
| setDropzoneActive(false); | |||||
| e.preventDefault(); | |||||
| }} | |||||
| onDrop={(e) => handleDrop(e)} | |||||
| style={{ | |||||
| backgroundColor: dropzoneActive ? "#F4F4F4" : "#ffffff", | |||||
| }} | |||||
| > | |||||
| <div className="uploadCV-input-sub-container"> | |||||
| <img src={uploadIcon} /> | |||||
| <div className="uploadCV-input-sub-container"> | |||||
| {pdfFile !== null ? ( | |||||
| <p>{pdfFile.name}</p> | |||||
| ) : ( | |||||
| <> | |||||
| <p> | |||||
| {t("ads.dragPdf1")} | |||||
| <label | |||||
| htmlFor="upload-file" | |||||
| style={{ | |||||
| cursor: "pointer", | |||||
| textDecoration: "underline", | |||||
| color: "#1E92D0", | |||||
| }} | |||||
| > | |||||
| {t("common.search")} | |||||
| </label> | |||||
| {t("ads.dragPdf2")} | |||||
| </p> | |||||
| <input | |||||
| type="file" | |||||
| name="photo" | |||||
| id="upload-file" | |||||
| style={{ display: "none", zIndex: -1 }} | |||||
| value={pdfFile} | |||||
| data-testid="apply-for-ad-modal-fourth-stage-pdf-input" | |||||
| // accept=".pdf" | |||||
| onChange={handleChangeInputFile} | |||||
| /> | |||||
| </> | |||||
| )} | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| </div> | |||||
| <div className="files-page-card"> | |||||
| <div className="files-page-card-add-button" style={{alignItems:'center'}}> | |||||
| <p | |||||
| className="applicant-ads-back-button" | |||||
| onClick={() => history.push(FILES_VIEW_PAGE)} | |||||
| > | |||||
| Nazad na sve fajlove | |||||
| </p> | |||||
| <IconButton | |||||
| className="c-btn ads-page-btn c-btn--primary add-ad-btn" | |||||
| onClick={uploadFileHandler} | |||||
| > | |||||
| + {t("files.addFile")} | |||||
| </IconButton> | |||||
| </div> | |||||
| </div> | |||||
| <div> | |||||
| {categories.map((category,index) => ( | |||||
| <p key={index}>{category.name}</p> | |||||
| )) } | |||||
| </div> | </div> | ||||
| ); | |||||
| }; | |||||
| FilesPage.propTypes = { | |||||
| history: PropTypes.shape({ | |||||
| replace: PropTypes.func, | |||||
| push: PropTypes.func, | |||||
| location: PropTypes.shape({ | |||||
| pathname: PropTypes.string, | |||||
| }), | |||||
| }), | |||||
| }; | |||||
| ) | |||||
| } | |||||
| export default FilesPage; | |||||
| export default FilesPage |
| import { useTranslation } from "react-i18next"; | import { useTranslation } from "react-i18next"; | ||||
| import searchImage from "../../assets/images/search.png"; | import searchImage from "../../assets/images/search.png"; | ||||
| import IconButton from "../../components/IconButton/IconButton"; | import IconButton from "../../components/IconButton/IconButton"; | ||||
| import { FILES_PAGE } from "../../constants/pages"; | |||||
| import { ADD_FILE } from "../../constants/pages"; | |||||
| import PropTypes from "prop-types"; | import PropTypes from "prop-types"; | ||||
| const FilesViewPage = ({history}) => { | const FilesViewPage = ({history}) => { | ||||
| /> | /> | ||||
| <IconButton | <IconButton | ||||
| className="c-btn ads-page-btn c-btn--primary add-ad-btn filesPage" | className="c-btn ads-page-btn c-btn--primary add-ad-btn filesPage" | ||||
| onClick={() => history.push(FILES_PAGE)} | |||||
| onClick={() => history.push(ADD_FILE)} | |||||
| > | > | ||||
| + Fajl | + Fajl | ||||
| </IconButton> | </IconButton> |
| fetchGoogleUser, | fetchGoogleUser, | ||||
| } from "../../store/actions/login/loginActions"; | } from "../../store/actions/login/loginActions"; | ||||
| import { selectLoginError } from "../../store/selectors/loginSelectors"; | import { selectLoginError } from "../../store/selectors/loginSelectors"; | ||||
| import { FORGOT_PASSWORD_PAGE,FILES_VIEW_PAGE } from "../../constants/pages"; | |||||
| import { FORGOT_PASSWORD_PAGE,FILES_VIEW_PAGE, FILES_PAGE } from "../../constants/pages"; | |||||
| import { | import { | ||||
| Box, | Box, | ||||
| Button, | Button, | ||||
| const handleApiResponseSuccess = () => { | const handleApiResponseSuccess = () => { | ||||
| history.push({ | history.push({ | ||||
| pathname: FILES_VIEW_PAGE, | |||||
| pathname: FILES_VIEW_PAGE, | |||||
| pathname: FILES_PAGE, | |||||
| state: { | state: { | ||||
| from: history.location.pathname, | from: history.location.pathname, | ||||
| }, | }, |