| ABOUT_PAGE, | ABOUT_PAGE, | ||||
| ADMIN_HOME_PAGE, | ADMIN_HOME_PAGE, | ||||
| ADMIN_USERS_PAGE, | ADMIN_USERS_PAGE, | ||||
| ADMIN_CATEGORIES_PAGE, | |||||
| // POLICY_PRIVACY_PAGE, | // POLICY_PRIVACY_PAGE, | ||||
| } from "./constants/pages"; | } from "./constants/pages"; | ||||
| import LoginPage from "./pages/LoginPage/LoginPage"; | import LoginPage from "./pages/LoginPage/LoginPage"; | ||||
| import AuthRoute from "./components/Router/AuthRoute"; | import AuthRoute from "./components/Router/AuthRoute"; | ||||
| import AdminRoute from "./components/Router/AdminRoute"; | import AdminRoute from "./components/Router/AdminRoute"; | ||||
| import AdminHomePage from "./pages/AdminHomePage/AdminHomePage"; | import AdminHomePage from "./pages/AdminHomePage/AdminHomePage"; | ||||
| // import AdminUsersPage from "./pages/AdminUsersPage/AdminUsersPage"; | |||||
| // import PrivacyPolicyPage from "./pages/PrivacyPolicy/PrivacyPolicyPage"; | // import PrivacyPolicyPage from "./pages/PrivacyPolicy/PrivacyPolicyPage"; | ||||
| const AppRoutes = () => { | const AppRoutes = () => { | ||||
| <AuthRoute exact path={LOGIN_PAGE} component={LoginPage} /> | <AuthRoute exact path={LOGIN_PAGE} component={LoginPage} /> | ||||
| <AuthRoute exact path={ADMIN_LOGIN_PAGE} component={AdminLoginPage} /> | <AuthRoute exact path={ADMIN_LOGIN_PAGE} component={AdminLoginPage} /> | ||||
| <AdminRoute path={ADMIN_HOME_PAGE} component={AdminHomePage} /> | <AdminRoute path={ADMIN_HOME_PAGE} component={AdminHomePage} /> | ||||
| {/* <AdminRoute path={ADMIN_USERS_PAGE} component={AdminUsersPage} /> */} | |||||
| <Route path={NOT_FOUND_PAGE} component={NotFoundPage} /> | <Route path={NOT_FOUND_PAGE} component={NotFoundPage} /> | ||||
| <Route path={ERROR_PAGE} component={ErrorPage} /> | <Route path={ERROR_PAGE} component={ErrorPage} /> | ||||
| <AuthRoute | <AuthRoute |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { | |||||
| CategoryCardContainer, | |||||
| CategoryCardDetailsContainer, | |||||
| CategoryCardLeftContainer, | |||||
| CategoryCardRightContainer, | |||||
| } from "./CategoryCard.styled"; | |||||
| import CategoryCardName from "./CategoryCardName/CategoryCardName"; | |||||
| import CategoryDetail from "./CategoryDetail/CategoryDetail"; | |||||
| import CategoryCheckButton from "./CategoryCheckButton/CategoryCheckButton"; | |||||
| import CategoryEditButton from "./CategoryEditButton/CategoryEditButton"; | |||||
| import CategoryRemoveButton from "./CategoryRemoveButton/CategoryRemoveButton"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const CategoryCard = (props) => { | |||||
| const { t } = useTranslation(); | |||||
| return ( | |||||
| <CategoryCardContainer> | |||||
| <CategoryCardLeftContainer> | |||||
| <CategoryCardName categoryName={props?.category?.name} /> | |||||
| <CategoryCardDetailsContainer> | |||||
| <CategoryDetail | |||||
| label={t("admin.categories.noOfOffers")} | |||||
| value={props?.category?.offerCount} | |||||
| /> | |||||
| {!props.hideSecondLabel && ( | |||||
| <CategoryDetail | |||||
| label={props?.secondLabel} | |||||
| value={props?.category?.subcategories?.length} | |||||
| /> | |||||
| )} | |||||
| </CategoryCardDetailsContainer> | |||||
| </CategoryCardLeftContainer> | |||||
| <CategoryCardRightContainer> | |||||
| <CategoryRemoveButton /> | |||||
| <CategoryEditButton /> | |||||
| {!props.hideCheckButton && <CategoryCheckButton />} | |||||
| </CategoryCardRightContainer> | |||||
| </CategoryCardContainer> | |||||
| ); | |||||
| }; | |||||
| CategoryCard.propTypes = { | |||||
| children: PropTypes.node, | |||||
| category: PropTypes.object, | |||||
| hideCheckButton: PropTypes.bool, | |||||
| secondLabel: PropTypes.string, | |||||
| hideSecondLabel: PropTypes.bool, | |||||
| }; | |||||
| export default CategoryCard; |
| import { Box } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| import selectedTheme from "../../../themes"; | |||||
| export const CategoryCardContainer = styled(Box)` | |||||
| background: white; | |||||
| height: 84px; | |||||
| width: calc(100% - 10px); | |||||
| margin: 5px; | |||||
| margin-top: 13px; | |||||
| margin-bottom: 13px; | |||||
| border: 1px solid ${selectedTheme.colors.borderNormal}; | |||||
| border-radius: 4px; | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| justify-content: space-between; | |||||
| position: relative; | |||||
| @media (max-width: 600px) { | |||||
| height: 102px; | |||||
| } | |||||
| `; | |||||
| export const CategoryCardLeftContainer = styled(Box)` | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| `; | |||||
| export const CategoryCardRightContainer = styled(Box)` | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| `; | |||||
| export const CategoryCardDetailsContainer = styled(Box)` | |||||
| display: flex; | |||||
| flex-direction: row; | |||||
| @media (max-width: 600px) { | |||||
| position: absolute; | |||||
| bottom: 18px; | |||||
| left: 0; | |||||
| max-height: 16px; | |||||
| } | |||||
| `; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { | |||||
| CategoryCardNameContainer, | |||||
| CategoryCardNameText, | |||||
| } from "./CategoryCardName.styled"; | |||||
| const CategoryCardName = (props) => { | |||||
| return ( | |||||
| <CategoryCardNameContainer> | |||||
| <CategoryCardNameText>{props.categoryName}</CategoryCardNameText> | |||||
| </CategoryCardNameContainer> | |||||
| ); | |||||
| }; | |||||
| CategoryCardName.propTypes = { | |||||
| children: PropTypes.node, | |||||
| categoryName: PropTypes.string, | |||||
| }; | |||||
| export default CategoryCardName; |
| import { Box, Typography } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| import selectedTheme from "../../../../themes"; | |||||
| export const CategoryCardNameContainer = styled(Box)` | |||||
| padding: 18px; | |||||
| min-width: 234px; | |||||
| `; | |||||
| export const CategoryCardNameText = styled(Typography)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| font-weight: 700; | |||||
| font-size: 16px; | |||||
| line-height: 21px; | |||||
| padding-top: 12px; | |||||
| color: ${selectedTheme.colors.primaryPurple}; | |||||
| cursor: pointer; | |||||
| @media (max-width: 600px) { | |||||
| font-size: 18px; | |||||
| padding: 0; | |||||
| } | |||||
| `; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import selectedTheme from "../../../../themes"; | |||||
| import { CheckButton } from "./CategoryCheckButton.styled"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const CategoryCheckButton = () => { | |||||
| const { t } = useTranslation(); | |||||
| return ( | |||||
| <CheckButton | |||||
| variant={"outlined"} | |||||
| buttoncolor={selectedTheme.colors.primaryPurple} | |||||
| textcolor={selectedTheme.colors.primaryPurple} | |||||
| style={{ fontWeight: "600" }} | |||||
| > | |||||
| {t("admin.categories.checkCategory")} | |||||
| </CheckButton> | |||||
| ); | |||||
| }; | |||||
| CategoryCheckButton.propTypes = { | |||||
| category: PropTypes.any, | |||||
| }; | |||||
| export default CategoryCheckButton; |
| import styled from "styled-components"; | |||||
| import selectedTheme from "../../../../themes"; | |||||
| import { PrimaryButton } from "../../../Buttons/PrimaryButton/PrimaryButton"; | |||||
| export const CheckButton = styled(PrimaryButton)` | |||||
| width: 224px; | |||||
| height: 48px; | |||||
| margin-top: 9px; | |||||
| margin-right: 9px; | |||||
| & button:hover { | |||||
| background-color: ${selectedTheme.colors.primaryPurple} !important; | |||||
| color: white !important; | |||||
| } | |||||
| @media (max-width: 850px) { | |||||
| display: none; | |||||
| } | |||||
| `; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { | |||||
| CategoryDetailContainer, | |||||
| CategoryDetailLabel, | |||||
| CategoryDetailValue, | |||||
| } from "./CategoryDetail.styled"; | |||||
| const CategoryDetail = (props) => { | |||||
| return ( | |||||
| <CategoryDetailContainer> | |||||
| <CategoryDetailLabel>{props.label}</CategoryDetailLabel> | |||||
| <CategoryDetailValue>{props.value}</CategoryDetailValue> | |||||
| </CategoryDetailContainer> | |||||
| ); | |||||
| }; | |||||
| CategoryDetail.propTypes = { | |||||
| label: PropTypes.string, | |||||
| value: PropTypes.string, | |||||
| }; | |||||
| export default CategoryDetail; |
| import { Box, Typography } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| import selectedTheme from "../../../../themes"; | |||||
| import { hexToRGB } from "../../../../util/helpers/colorHelper"; | |||||
| export const CategoryDetailContainer = styled(Box)` | |||||
| /* display: flex; | |||||
| flex-direction: row; */ | |||||
| margin-top: 20px; | |||||
| margin-bottom: 20px; | |||||
| min-width: 150px; | |||||
| text-align: center; | |||||
| border-left: 1px solid ${hexToRGB(selectedTheme.colors.primaryText, 0.13)}; | |||||
| @media (max-width: 600px) { | |||||
| margin: 0; | |||||
| min-width: 123px; | |||||
| &:nth-child(1) { | |||||
| border-left: 0; | |||||
| } | |||||
| &:nth-child(2) { | |||||
| padding-left: 18px; | |||||
| } | |||||
| } | |||||
| `; | |||||
| export const CategoryDetailLabel = styled(Typography)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| color: ${selectedTheme.colors.primaryText}; | |||||
| font-size: 12px; | |||||
| letter-spacing: 0.01rem; | |||||
| padding-top: 14px; | |||||
| padding-right: 3px; | |||||
| @media (max-width: 600px) { | |||||
| position: relative; | |||||
| bottom: 2.5px; | |||||
| padding-top: 0; | |||||
| } | |||||
| `; | |||||
| export const CategoryDetailValue = styled(Typography)` | |||||
| font-family: ${selectedTheme.fonts.textFont}; | |||||
| font-weight: 700; | |||||
| font-size: 16px; | |||||
| line-height: 21px; | |||||
| padding-top: 11px; | |||||
| color: ${selectedTheme.colors.primaryPurple}; | |||||
| @media (max-width: 600px) { | |||||
| position: relative; | |||||
| bottom: 2.5px; | |||||
| padding: 0; | |||||
| font-size: 12px; | |||||
| font-weight: 600; | |||||
| } | |||||
| `; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { | |||||
| CategoryEditButtonContainer, | |||||
| EditIcon, | |||||
| } from "./CategoryEditButton.styled"; | |||||
| const CategoryEditButton = () => { | |||||
| return ( | |||||
| <CategoryEditButtonContainer> | |||||
| <EditIcon /> | |||||
| </CategoryEditButtonContainer> | |||||
| ); | |||||
| }; | |||||
| CategoryEditButton.propTypes = { | |||||
| category: PropTypes.any, | |||||
| }; | |||||
| export default CategoryEditButton; |
| import styled from "styled-components"; | |||||
| import selectedTheme from "../../../../themes"; | |||||
| import { IconButton } from "../../../Buttons/IconButton/IconButton"; | |||||
| import { ReactComponent as Edit } from "../../../../assets/images/svg/edit.svg"; | |||||
| export const CategoryEditButtonContainer = styled(IconButton)` | |||||
| width: 40px; | |||||
| height: 40px; | |||||
| background-color: ${selectedTheme.colors.primaryIconBackgroundColor}; | |||||
| border-radius: 100%; | |||||
| position: relative; | |||||
| top: 22px; | |||||
| margin-right: 18px; | |||||
| padding-top: 2px; | |||||
| text-align: center; | |||||
| @media (max-width: 600px) { | |||||
| width: 32px; | |||||
| height: 32px; | |||||
| top: 18px; | |||||
| right: 18px; | |||||
| margin-right: 0; | |||||
| padding: 0; | |||||
| ${(props) => | |||||
| props.vertical && | |||||
| ` | |||||
| display: none; | |||||
| `} | |||||
| & button svg { | |||||
| width: 16px; | |||||
| height: 16px; | |||||
| position: relative; | |||||
| top: -3px; | |||||
| left: -1.5px; | |||||
| } | |||||
| } | |||||
| `; | |||||
| export const EditIcon = styled(Edit)` | |||||
| ` |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import { | |||||
| CategoryRemoveButtonContainer, | |||||
| RemoveIcon, | |||||
| } from "./CategoryRemoveButton.styled"; | |||||
| const CategoryRemoveButton = () => { | |||||
| return ( | |||||
| <CategoryRemoveButtonContainer> | |||||
| <RemoveIcon /> | |||||
| </CategoryRemoveButtonContainer> | |||||
| ); | |||||
| }; | |||||
| CategoryRemoveButton.propTypes = { | |||||
| category: PropTypes.any, | |||||
| }; | |||||
| export default CategoryRemoveButton; |
| import styled from "styled-components"; | |||||
| import selectedTheme from "../../../../themes"; | |||||
| import { IconButton } from "../../../Buttons/IconButton/IconButton"; | |||||
| import { ReactComponent as Remove } from "../../../../assets/images/svg/trash.svg"; | |||||
| export const CategoryRemoveButtonContainer = styled(IconButton)` | |||||
| width: 40px; | |||||
| height: 40px; | |||||
| background-color: ${selectedTheme.colors.primaryIconBackgroundColor}; | |||||
| border-radius: 100%; | |||||
| position: relative; | |||||
| top: 22px; | |||||
| margin-right: 18px; | |||||
| padding-top: 2px; | |||||
| text-align: center; | |||||
| @media (max-width: 600px) { | |||||
| width: 32px; | |||||
| height: 32px; | |||||
| top: 18px; | |||||
| right: 12px; | |||||
| padding: 0; | |||||
| ${(props) => | |||||
| props.vertical && | |||||
| ` | |||||
| display: none; | |||||
| `} | |||||
| & button svg { | |||||
| width: 16px; | |||||
| height: 16px; | |||||
| position: relative; | |||||
| top: -3px; | |||||
| left: -1.5px; | |||||
| } | |||||
| } | |||||
| `; | |||||
| export const RemoveIcon = styled(Remove)` | |||||
| ` |
| const blockUser = () => {}; | const blockUser = () => {}; | ||||
| return ( | return ( | ||||
| <> | <> | ||||
| <ProfileCardContainer> | |||||
| <ProfileCardContainer halfwidth={props.halfwidth}> | |||||
| <ProfileCardWrapper variant="outlined"> | <ProfileCardWrapper variant="outlined"> | ||||
| <EditButton onClick={() => setEditProfileModal(true)}> | <EditButton onClick={() => setEditProfileModal(true)}> | ||||
| <EditIcon /> | <EditIcon /> | ||||
| <ProfileContact profile={props.profile} isAdmin /> | <ProfileContact profile={props.profile} isAdmin /> | ||||
| </ProfileInfoContainer> | </ProfileInfoContainer> | ||||
| <CheckButton | <CheckButton | ||||
| halfwidth={props.halfwidth} | |||||
| variant={"outlined"} | variant={"outlined"} | ||||
| buttoncolor={selectedTheme.colors.primaryPurple} | buttoncolor={selectedTheme.colors.primaryPurple} | ||||
| textcolor={selectedTheme.colors.primaryPurple} | textcolor={selectedTheme.colors.primaryPurple} | ||||
| BigProfileCard.propTypes = { | BigProfileCard.propTypes = { | ||||
| profile: PropTypes.any, | profile: PropTypes.any, | ||||
| halfwidth: PropTypes.bool, | |||||
| }; | }; | ||||
| export default BigProfileCard; | export default BigProfileCard; |
| // import { ReactComponent as Location } from "../../../assets/images/svg/location.svg"; | // import { ReactComponent as Location } from "../../../assets/images/svg/location.svg"; | ||||
| export const ProfileCardContainer = styled(Box)` | export const ProfileCardContainer = styled(Box)` | ||||
| width: 100%; | |||||
| width: ${(props) => (props.halfwidth ? `49%` : `100%`)}; | |||||
| box-sizing: border-box; | box-sizing: border-box; | ||||
| max-height: 184px; | max-height: 184px; | ||||
| margin-top: 34px; | margin-top: 34px; | ||||
| } | } | ||||
| `; | `; | ||||
| export const MessageButton = styled(IconButton)` | export const MessageButton = styled(IconButton)` | ||||
| width: 40px; | width: 40px; | ||||
| height: 40px; | height: 40px; | ||||
| position: absolute; | position: absolute; | ||||
| bottom: 25px; | bottom: 25px; | ||||
| right: 9px; | right: 9px; | ||||
| display: ${(props) => (props.halfwidth ? `none` : `block`)}; | |||||
| & button:hover { | & button:hover { | ||||
| background-color: ${selectedTheme.colors.primaryPurple} !important; | background-color: ${selectedTheme.colors.primaryPurple} !important; | ||||
| color: white !important; | color: white !important; |
| import UserButton from "./UserButton/UserButton"; | import UserButton from "./UserButton/UserButton"; | ||||
| import LoginButton from "./LoginButton/LoginButton"; | import LoginButton from "./LoginButton/LoginButton"; | ||||
| import RegisterButton from "./RegisterButton/RegisterButton"; | import RegisterButton from "./RegisterButton/RegisterButton"; | ||||
| import useIsMobile from "../../hooks/useIsMobile"; | |||||
| const Header = () => { | const Header = () => { | ||||
| const [showCreateOfferModal, setShowCreateOfferModal] = useState(false); | const [showCreateOfferModal, setShowCreateOfferModal] = useState(false); | ||||
| const drawerRef = useRef(null); | const drawerRef = useRef(null); | ||||
| const [shouldShow, setShouldShow] = useState(true); | const [shouldShow, setShouldShow] = useState(true); | ||||
| const routeMatch = useRouteMatch(); | const routeMatch = useRouteMatch(); | ||||
| const { isMobile } = useIsMobile(); | |||||
| // Dont show header on auth routes(login, register, etc.) and admin routes | // Dont show header on auth routes(login, register, etc.) and admin routes | ||||
| useEffect(() => { | useEffect(() => { | ||||
| if (isAuthRoute() || isAdminRoute()) setShouldShow(false); | |||||
| if (isAuthRoute() || (isAdminRoute() && !isMobile)) setShouldShow(false); | |||||
| else setShouldShow(true); | else setShouldShow(true); | ||||
| }, [routeMatch]); | |||||
| }, [routeMatch, isMobile]); | |||||
| // Fetch mine profile on loading home page | // Fetch mine profile on loading home page | ||||
| useEffect(() => { | useEffect(() => { | ||||
| } | } | ||||
| // Handling search when user is on marketplace and when he is not | // Handling search when user is on marketplace and when he is not | ||||
| const handleSearch = (value) => { | const handleSearch = (value) => { | ||||
| if (!routeMatches(HOME_PAGE) && !routeMatches(BASE_PAGE)) { | |||||
| const newQueryString = new URLSearchParams({ search: value }); | |||||
| history.push({ | |||||
| pathname: HOME_PAGE, | |||||
| search: newQueryString.toString(), | |||||
| }); | |||||
| if (isAdminRoute()) { | |||||
| console.log("admin"); | |||||
| search.setSearchStringManually(value); | |||||
| } else { | } else { | ||||
| search.searchOffersImmediately(value); | |||||
| if (!routeMatches(HOME_PAGE) && !routeMatches(BASE_PAGE)) { | |||||
| const newQueryString = new URLSearchParams({ search: value }); | |||||
| history.push({ | |||||
| pathname: HOME_PAGE, | |||||
| search: newQueryString.toString(), | |||||
| }); | |||||
| } else { | |||||
| search.searchOffersImmediately(value); | |||||
| } | |||||
| } | } | ||||
| }; | }; | ||||
| }; | }; | ||||
| if (!shouldShow) { | if (!shouldShow) { | ||||
| return (<></>) | |||||
| return <></>; | |||||
| } | } | ||||
| return ( | return ( | ||||
| Header.propTypes = { | Header.propTypes = { | ||||
| isGrid: PropTypes.bool, | isGrid: PropTypes.bool, | ||||
| showModalHandler: PropTypes.func, | showModalHandler: PropTypes.func, | ||||
| manualSearch: PropTypes.func, | |||||
| }; | }; | ||||
| export default Header; | export default Header; |
| ButtonContainer, | ButtonContainer, | ||||
| // ButtonContainer, | // ButtonContainer, | ||||
| CategoryHeaderIcon, | CategoryHeaderIcon, | ||||
| CategoryIcon, | |||||
| HeaderAltLocation, | HeaderAltLocation, | ||||
| HeaderButton, | HeaderButton, | ||||
| HeaderButtons, | HeaderButtons, | ||||
| <> | <> | ||||
| <SkeletonHeader skeleton={props?.skeleton} myOffers={props?.myOffers} /> | <SkeletonHeader skeleton={props?.skeleton} myOffers={props?.myOffers} /> | ||||
| <HeaderWrapperContainer | <HeaderWrapperContainer | ||||
| className={props.className} | |||||
| skeleton={props?.skeleton} | skeleton={props?.skeleton} | ||||
| isAdmin={props?.isAdmin} | isAdmin={props?.isAdmin} | ||||
| > | > | ||||
| <> | <> | ||||
| {!isMobile ? ( | {!isMobile ? ( | ||||
| <HeaderTitleContainer> | <HeaderTitleContainer> | ||||
| {props.users ? <UserIcon /> : <SwapsHeaderIcon />} | |||||
| {props.users ? ( | |||||
| <UserIcon /> | |||||
| ) : props.categories ? ( | |||||
| <CategoryIcon /> | |||||
| ) : ( | |||||
| <SwapsHeaderIcon /> | |||||
| )} | |||||
| <HeaderTitleText> | <HeaderTitleText> | ||||
| {props.users | {props.users | ||||
| ? t("admin.users.headerTitle") | ? t("admin.users.headerTitle") | ||||
| : props.categories | |||||
| ? t("admin.categories.headerTitle") | |||||
| : t("header.myOffers")} | : t("header.myOffers")} | ||||
| </HeaderTitleText> | </HeaderTitleText> | ||||
| </HeaderTitleContainer> | </HeaderTitleContainer> | ||||
| ) : ( | ) : ( | ||||
| <ButtonContainer onClick={goBack}> | |||||
| <ArrowButton side={"left"}></ArrowButton> | |||||
| <HeaderText>{t("messages.goBack")}</HeaderText> | |||||
| </ButtonContainer> | |||||
| !props.hideBackButton && ( | |||||
| <ButtonContainer onClick={goBack}> | |||||
| <ArrowButton side={"left"}></ArrowButton> | |||||
| <HeaderText>{t("messages.goBack")}</HeaderText> | |||||
| </ButtonContainer> | |||||
| ) | |||||
| )} | )} | ||||
| </> | </> | ||||
| )} | )} | ||||
| {/* ^^^^^^ */} | {/* ^^^^^^ */} | ||||
| <HeaderOptions> | <HeaderOptions> | ||||
| <HeaderButtons> | |||||
| {/* Setting display of offer cards to full width */} | |||||
| <HeaderButton | |||||
| iconColor={ | |||||
| props?.isGrid | |||||
| ? selectedTheme.colors.iconStrokeColor | |||||
| : selectedTheme.colors.primaryPurple | |||||
| } | |||||
| onClick={() => props?.setIsGrid(false)} | |||||
| > | |||||
| <GridLine /> | |||||
| </HeaderButton> | |||||
| {/* ^^^^^^ */} | |||||
| {!props.hideGrid && ( | |||||
| <HeaderButtons> | |||||
| {/* Setting display of offer cards to full width */} | |||||
| <HeaderButton | |||||
| iconColor={ | |||||
| props?.isGrid | |||||
| ? selectedTheme.colors.iconStrokeColor | |||||
| : selectedTheme.colors.primaryPurple | |||||
| } | |||||
| onClick={() => props?.setIsGrid(false)} | |||||
| > | |||||
| <GridLine /> | |||||
| </HeaderButton> | |||||
| {/* ^^^^^^ */} | |||||
| {/* Setting display of offer cards to half width (Grid) */} | |||||
| <HeaderButton | |||||
| iconColor={ | |||||
| props?.isGrid | |||||
| ? selectedTheme.colors.primaryPurple | |||||
| : selectedTheme.colors.iconStrokeColor | |||||
| } | |||||
| onClick={() => props?.setIsGrid(true)} | |||||
| > | |||||
| <GridSquare /> | |||||
| </HeaderButton> | |||||
| {/* ^^^^^^ */} | |||||
| </HeaderButtons> | |||||
| {/* Setting display of offer cards to half width (Grid) */} | |||||
| <HeaderButton | |||||
| iconColor={ | |||||
| props?.isGrid | |||||
| ? selectedTheme.colors.primaryPurple | |||||
| : selectedTheme.colors.iconStrokeColor | |||||
| } | |||||
| onClick={() => props?.setIsGrid(true)} | |||||
| > | |||||
| <GridSquare /> | |||||
| </HeaderButton> | |||||
| {/* ^^^^^^ */} | |||||
| </HeaderButtons> | |||||
| )} | |||||
| {/* Select option to choose sorting */} | {/* Select option to choose sorting */} | ||||
| <HeaderSelect | <HeaderSelect | ||||
| </HeaderContainer> | </HeaderContainer> | ||||
| {isMobile && ( | {isMobile && ( | ||||
| <PageTitleContainer> | <PageTitleContainer> | ||||
| <SwapsIcon /> | |||||
| {props.users ? ( | |||||
| <UserIcon /> | |||||
| ) : props.categories ? ( | |||||
| <CategoryIcon /> | |||||
| ) : ( | |||||
| <SwapsIcon /> | |||||
| )} | |||||
| <SwapsTitle> | <SwapsTitle> | ||||
| {props?.myOffers ? t("header.myOffers") : t("offer.offers")} | |||||
| {props.users | |||||
| ? t("admin.users.headerTitle") | |||||
| : props.categories | |||||
| ? t("admin.categories.headerTitle") | |||||
| : props?.myOffers | |||||
| ? t("header.myOffers") | |||||
| : t("offer.offers")} | |||||
| </SwapsTitle> | </SwapsTitle> | ||||
| </PageTitleContainer> | </PageTitleContainer> | ||||
| )} | )} | ||||
| setIsGrid: PropTypes.func, | setIsGrid: PropTypes.func, | ||||
| isGrid: PropTypes.bool, | isGrid: PropTypes.bool, | ||||
| offers: PropTypes.any, | offers: PropTypes.any, | ||||
| category: PropTypes.string, | |||||
| myOffers: PropTypes.bool, | myOffers: PropTypes.bool, | ||||
| skeleton: PropTypes.bool, | skeleton: PropTypes.bool, | ||||
| sorting: PropTypes.any, | sorting: PropTypes.any, | ||||
| isAdmin: PropTypes.bool, | isAdmin: PropTypes.bool, | ||||
| users: PropTypes.bool, | users: PropTypes.bool, | ||||
| categories: PropTypes.bool, | |||||
| hideGrid: PropTypes.bool, | |||||
| className: PropTypes.string, | |||||
| hideBackButton: PropTypes.bool, | |||||
| }; | }; | ||||
| Header.defaultProps = { | Header.defaultProps = { | ||||
| isGrid: false, | isGrid: false, |
| import { ReactComponent as Swaps } from "../../../assets/images/svg/swaps.svg"; | import { ReactComponent as Swaps } from "../../../assets/images/svg/swaps.svg"; | ||||
| import { ReactComponent as CategoryHeader } from "../../../assets/images/svg/category-header.svg"; | import { ReactComponent as CategoryHeader } from "../../../assets/images/svg/category-header.svg"; | ||||
| import { ReactComponent as User } from "../../../assets/images/svg/user.svg"; | import { ReactComponent as User } from "../../../assets/images/svg/user.svg"; | ||||
| import { ReactComponent as Category } from "../../../assets/images/svg/category.svg"; | |||||
| export const HeaderWrapperContainer = styled(Box)` | export const HeaderWrapperContainer = styled(Box)` | ||||
| display: ${(props) => (props.skeleton ? "none" : "block")}; | display: ${(props) => (props.skeleton ? "none" : "block")}; | ||||
| top: 1px; | top: 1px; | ||||
| } | } | ||||
| `; | `; | ||||
| export const CategoryIcon = styled(Category)` | |||||
| position: relative; | |||||
| top: 4px; | |||||
| right: 2px; | |||||
| `; | |||||
| export const PageTitleContainer = styled(Box)` | export const PageTitleContainer = styled(Box)` | ||||
| position: relative; | position: relative; | ||||
| left: 6px; | left: 6px; | ||||
| margin-top: 36px; | margin-top: 36px; | ||||
| width: 100px; | width: 100px; | ||||
| @media (max-width: 600px) { | |||||
| & svg { | |||||
| width: 12px; | |||||
| height: 12px; | |||||
| top: 2px; | |||||
| } | |||||
| } | |||||
| `; | `; | ||||
| export const SwapsIcon = styled(RefreshIcon)` | export const SwapsIcon = styled(RefreshIcon)` | ||||
| width: 12px; | width: 12px; |
| import { selectUserId } from "../../../store/selectors/loginSelectors"; | import { selectUserId } from "../../../store/selectors/loginSelectors"; | ||||
| import { startChat } from "../../../util/helpers/chatHelper"; | import { startChat } from "../../../util/helpers/chatHelper"; | ||||
| import OffersNotFound from "./OffersNotFound"; | import OffersNotFound from "./OffersNotFound"; | ||||
| import HeadersMyOffers from "./HeaderMyOffers.js/HeadersMyOffers"; | |||||
| // import HeadersMyOffers from "./SearchBar/SearchBar"; | |||||
| import SkeletonOfferCard from "../../Cards/OfferCard/SkeletonOfferCard/SkeletonOfferCard"; | import SkeletonOfferCard from "../../Cards/OfferCard/SkeletonOfferCard/SkeletonOfferCard"; | ||||
| import BigProfileCard from "../../Cards/ProfileCard/BigProfileCard/BigProfileCard"; | import BigProfileCard from "../../Cards/ProfileCard/BigProfileCard/BigProfileCard"; | ||||
| import SearchField from "../../TextFields/SearchField/SearchField"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| const Offers = (props) => { | const Offers = (props) => { | ||||
| const chats = useSelector(selectLatestChats); | const chats = useSelector(selectLatestChats); | ||||
| const offersRef = useRef(null); | const offersRef = useRef(null); | ||||
| const userId = useSelector(selectUserId); | const userId = useSelector(selectUserId); | ||||
| const { t } = useTranslation(); | |||||
| const offers = props?.offers; | const offers = props?.offers; | ||||
| // For skeleton screen | // For skeleton screen | ||||
| const arrayForMapping = Array.apply(null, Array(4)).map(() => {}); | const arrayForMapping = Array.apply(null, Array(4)).map(() => {}); | ||||
| <FilterIcon /> | <FilterIcon /> | ||||
| </FilterContainer> | </FilterContainer> | ||||
| {(props?.myOffers || props?.isAdmin) && ( | {(props?.myOffers || props?.isAdmin) && ( | ||||
| <HeadersMyOffers | |||||
| // <HeadersMyOffers | |||||
| <SearchField | |||||
| searchMyOffers={offers?.search?.searchOffers} | searchMyOffers={offers?.search?.searchOffers} | ||||
| handleSearch={offers?.apply} | handleSearch={offers?.apply} | ||||
| isAdmin={props?.isAdmin} | isAdmin={props?.isAdmin} | ||||
| offers={offers} | offers={offers} | ||||
| isUsers={props.isUsers} | isUsers={props.isUsers} | ||||
| placeholder={ | |||||
| props.isUsers | |||||
| ? t("admin.users.searchPlaceholder") | |||||
| : t("header.searchOffers") | |||||
| } | |||||
| /> | /> | ||||
| )} | )} | ||||
| {offers?.allOffersToShow?.length === 0 ? ( | {offers?.allOffersToShow?.length === 0 ? ( | ||||
| <OffersContainer ref={offersRef}> | <OffersContainer ref={offersRef}> | ||||
| {props.isUsers | {props.isUsers | ||||
| ? props.users?.map((item) => ( | ? props.users?.map((item) => ( | ||||
| <BigProfileCard key={item._id} profile={item} /> | |||||
| <BigProfileCard | |||||
| key={item._id} | |||||
| profile={item} | |||||
| halfwidth={props?.isGrid} | |||||
| /> | |||||
| )) | )) | ||||
| : offers?.allOffersToShow?.map((item) => { | : offers?.allOffersToShow?.map((item) => { | ||||
| return ( | return ( | ||||
| Offers.defaultProps = { | Offers.defaultProps = { | ||||
| myOffers: false, | myOffers: false, | ||||
| users: [] | |||||
| users: [], | |||||
| }; | }; | ||||
| export default Offers; | export default Offers; |
| import React, { useCallback, useEffect, useRef } from "react"; | import React, { useCallback, useEffect, useRef } from "react"; | ||||
| import PropTypes from "prop-types"; | import PropTypes from "prop-types"; | ||||
| import { EndIcon, SearchIcon, SearchInput } from "./HeadersMyOffers.styled"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| import useSearch from "../../../../hooks/useOffers/useSearch"; | |||||
| import { EndIcon, SearchIcon, SearchInput } from "./SearchField.styled"; | |||||
| import useSearch from "../../../hooks/useOffers/useSearch"; | |||||
| const HeadersMyOffers = (props) => { | |||||
| const SearchField = (props) => { | |||||
| const searchRef = useRef(null); | const searchRef = useRef(null); | ||||
| const search = useSearch(() => {}); | const search = useSearch(() => {}); | ||||
| const { t } = useTranslation(); | |||||
| let listener = useCallback( | let listener = useCallback( | ||||
| (event) => { | (event) => { | ||||
| // Event keycode 13 = ENTER keycode | // Event keycode 13 = ENTER keycode | ||||
| const handleSearch = () => { | const handleSearch = () => { | ||||
| if (props.isAdmin) { | if (props.isAdmin) { | ||||
| console.log(searchRef.current.value); | console.log(searchRef.current.value); | ||||
| search.searchOffersImmediately(searchRef.current.value); | |||||
| if (props.handleSearch) props.handleSearch(searchRef.current.value); | |||||
| else search.searchOffersImmediately(searchRef.current.value); | |||||
| } else { | } else { | ||||
| props.searchMyOffers(searchRef.current.value); | props.searchMyOffers(searchRef.current.value); | ||||
| props.handleSearch(); | props.handleSearch(); | ||||
| return ( | return ( | ||||
| <SearchInput | <SearchInput | ||||
| isAdmin={props.isAdmin} | isAdmin={props.isAdmin} | ||||
| fullWidth | |||||
| fullWidth={props.fullWidth} | |||||
| InputProps={{ | InputProps={{ | ||||
| endAdornment: ( | endAdornment: ( | ||||
| <EndIcon size="36px"> | <EndIcon size="36px"> | ||||
| </EndIcon> | </EndIcon> | ||||
| ), | ), | ||||
| }} | }} | ||||
| placeholder={ | |||||
| props.isUsers | |||||
| ? t("admin.users.searchPlaceholder") | |||||
| : t("header.searchOffers") | |||||
| } | |||||
| placeholder={props.placeholder} | |||||
| onFocus={handleFocusSearch} | onFocus={handleFocusSearch} | ||||
| onBlur={handleBlurSearch} | onBlur={handleBlurSearch} | ||||
| ref={searchRef} | ref={searchRef} | ||||
| className={props.className} | |||||
| /> | /> | ||||
| ); | ); | ||||
| }; | }; | ||||
| HeadersMyOffers.propTypes = { | |||||
| SearchField.propTypes = { | |||||
| children: PropTypes.node, | children: PropTypes.node, | ||||
| searchMyOffers: PropTypes.func, | searchMyOffers: PropTypes.func, | ||||
| handleSearch: PropTypes.func, | handleSearch: PropTypes.func, | ||||
| isAdmin: PropTypes.bool, | isAdmin: PropTypes.bool, | ||||
| offers: PropTypes.any, | offers: PropTypes.any, | ||||
| isUsers: PropTypes.bool, | isUsers: PropTypes.bool, | ||||
| fullWidth: PropTypes.bool, | |||||
| className: PropTypes.string, | |||||
| placeholder: PropTypes.string, | |||||
| }; | |||||
| SearchField.defaultProps = { | |||||
| fullWidth: true, | |||||
| }; | }; | ||||
| export default HeadersMyOffers; | |||||
| export default SearchField; |
| import { Box } from "@mui/material"; | |||||
| import styled from "styled-components"; | import styled from "styled-components"; | ||||
| import { Icon } from "../../../Icon/Icon"; | |||||
| import { ReactComponent as Search } from "../../../../assets/images/svg/magnifying-glass.svg"; | |||||
| import selectedTheme from "../../../../themes"; | |||||
| import { TextField } from "../../../TextFields/TextField/TextField"; | |||||
| import selectedTheme from "../../../themes"; | |||||
| import { Icon } from "../../Icon/Icon"; | |||||
| import { TextField } from "../TextField/TextField"; | |||||
| import { ReactComponent as Search } from "../../../assets/images/svg/magnifying-glass.svg"; | |||||
| export const HeadersMyOffersContainer = styled(Box)``; | |||||
| export const EndIcon = styled(Icon)``; | export const EndIcon = styled(Icon)``; | ||||
| export const SearchIcon = styled(Search)` | export const SearchIcon = styled(Search)` | ||||
| position: relative; | position: relative; |
| import { ReactComponent as CategoryIcon } from "../assets/images/svg/category.svg"; | import { ReactComponent as CategoryIcon } from "../assets/images/svg/category.svg"; | ||||
| import { ReactComponent as LocationIcon } from "../assets/images/svg/location.svg"; | import { ReactComponent as LocationIcon } from "../assets/images/svg/location.svg"; | ||||
| import { ReactComponent as DollarIcon } from "../assets/images/svg/dollar-sign.svg"; | import { ReactComponent as DollarIcon } from "../assets/images/svg/dollar-sign.svg"; | ||||
| import { ADMIN_USERS_PAGE } from "./pages"; | |||||
| import { | |||||
| ADMIN_CATEGORIES_PAGE, | |||||
| ADMIN_LOCATIONS_PAGE, | |||||
| ADMIN_PAYMENT_PAGE, | |||||
| ADMIN_USERS_PAGE, | |||||
| } from "./pages"; | |||||
| import i18n from "../i18n"; | |||||
| export const ADMIN_NAVIGATION = [ | export const ADMIN_NAVIGATION = [ | ||||
| { text: "Korisnici", icon: <UserIcon />, route: `${ADMIN_USERS_PAGE}` }, | |||||
| { text: "Kategorije", icon: <CategoryIcon />, route: "/admin/categoires" }, | |||||
| { text: "Lokacije", icon: <LocationIcon />, route: "/admin/locations" }, | |||||
| { text: "Uplate", icon: <DollarIcon />, route: "/admin/payment" }, | |||||
| { | |||||
| text: i18n.t("admin.navigation.users"), | |||||
| icon: <UserIcon />, | |||||
| route: `${ADMIN_USERS_PAGE}`, | |||||
| }, | |||||
| { | |||||
| text: i18n.t("admin.navigation.categories"), | |||||
| icon: <CategoryIcon />, | |||||
| route: `${ADMIN_CATEGORIES_PAGE}`, | |||||
| }, | |||||
| { | |||||
| text: i18n.t("admin.navigation.locations"), | |||||
| icon: <LocationIcon />, | |||||
| route: `${ADMIN_LOCATIONS_PAGE}`, | |||||
| }, | |||||
| { | |||||
| text: i18n.t("admin.navigation.payment"), | |||||
| icon: <DollarIcon />, | |||||
| route: `${ADMIN_PAYMENT_PAGE}`, | |||||
| }, | |||||
| ]; | ]; |
| export const POLICY_PRIVACY_PAGE = "/policy"; | export const POLICY_PRIVACY_PAGE = "/policy"; | ||||
| export const ADMIN_HOME_PAGE = "/admin"; | export const ADMIN_HOME_PAGE = "/admin"; | ||||
| export const ADMIN_USERS_PAGE = "/admin/users"; | export const ADMIN_USERS_PAGE = "/admin/users"; | ||||
| export const ADMIN_CATEGORIES_PAGE = "/admin/categories"; | |||||
| export const ADMIN_LOCATIONS_PAGE = "/admin/locations"; | |||||
| export const ADMIN_PAYMENT_PAGE = "/admin/payment"; |
| import { useHistory } from "react-router-dom"; | import { useHistory } from "react-router-dom"; | ||||
| import { BASE_PAGE, HOME_PAGE } from "../../constants/pages"; | import { BASE_PAGE, HOME_PAGE } from "../../constants/pages"; | ||||
| import { KEY_SEARCH } from "../../constants/queryStringConstants"; | import { KEY_SEARCH } from "../../constants/queryStringConstants"; | ||||
| import { setSearchString } from "../../store/actions/filters/filtersActions"; | |||||
| import { selectSearchString } from "../../store/selectors/filtersSelectors"; | |||||
| import { | |||||
| setManualSearchString, | |||||
| setSearchString, | |||||
| } from "../../store/actions/filters/filtersActions"; | |||||
| import { | |||||
| selectManualSearchString, | |||||
| selectSearchString, | |||||
| } from "../../store/selectors/filtersSelectors"; | |||||
| import { routeMatches } from "../../util/helpers/routeHelpers"; | import { routeMatches } from "../../util/helpers/routeHelpers"; | ||||
| const useSearch = (applyAllFilters) => { | const useSearch = (applyAllFilters) => { | ||||
| const dispatch = useDispatch(); | const dispatch = useDispatch(); | ||||
| const searchString = useSelector(selectSearchString); | const searchString = useSelector(selectSearchString); | ||||
| const history = useHistory(); | const history = useHistory(); | ||||
| const manualSearchString = useSelector(selectManualSearchString); | |||||
| // On every global change of search string, new request to backend should be sent | // On every global change of search string, new request to backend should be sent | ||||
| useEffect(() => { | useEffect(() => { | ||||
| }, [searchStringLocally]); | }, [searchStringLocally]); | ||||
| const searchOffers = (searchValue) => { | const searchOffers = (searchValue) => { | ||||
| console.log('searchoff') | |||||
| setIsInitiallyLoaded(true); | setIsInitiallyLoaded(true); | ||||
| setSearchStringLocally(searchValue); | setSearchStringLocally(searchValue); | ||||
| }; | }; | ||||
| const searchOffersImmediately = (searchValue) => { | const searchOffersImmediately = (searchValue) => { | ||||
| console.log('searchoffersimm'); | |||||
| setIsInitiallyLoaded(true); | setIsInitiallyLoaded(true); | ||||
| searchOffers(searchValue); | searchOffers(searchValue); | ||||
| applyAllFilters(); | applyAllFilters(); | ||||
| }; | }; | ||||
| const setSearchStringManually = (searchValue) => { | |||||
| dispatch(setManualSearchString(searchValue)); | |||||
| }; | |||||
| const clear = () => { | const clear = () => { | ||||
| setSearchStringLocally(""); | setSearchStringLocally(""); | ||||
| }; | }; | ||||
| return { | return { | ||||
| searchOffers, | searchOffers, | ||||
| setSearchStringLocally, | setSearchStringLocally, | ||||
| setSearchStringManually, | |||||
| searchOffersImmediately, | searchOffersImmediately, | ||||
| searchStringLocally, | searchStringLocally, | ||||
| searchString, | searchString, | ||||
| manualSearchString, | |||||
| clear, | clear, | ||||
| }; | }; | ||||
| }; | }; |
| navigation: { | navigation: { | ||||
| role: "Administrator", | role: "Administrator", | ||||
| menu: "Meni", | menu: "Meni", | ||||
| users: "Korisnici", | |||||
| categories: "Kategorije", | |||||
| locations: "Lokacije", | |||||
| payment: "Uplate", | |||||
| logout: "Odjavi se", | logout: "Odjavi se", | ||||
| }, | }, | ||||
| categories: { | |||||
| checkCategory: "Pogledaj podkategorije", | |||||
| noOfOffers: "Broj objava: ", | |||||
| noOfSubcategories: "Broj potkategorija: ", | |||||
| headerTitle: "Kategorije", | |||||
| placeholder: "Pretražite kategorije...", | |||||
| }, | |||||
| }, | }, | ||||
| }; | }; |
| import React from "react"; | |||||
| import PropTypes from "prop-types"; | |||||
| import CategoryCard from "../../components/Cards/CategoryCard/CategoryCard"; | |||||
| import { useDispatch, useSelector } from "react-redux"; | |||||
| import { useEffect } from "react"; | |||||
| import { fetchCategories } from "../../store/actions/categories/categoriesActions"; | |||||
| import { selectCategories } from "../../store/selectors/categoriesSelectors"; | |||||
| import { useTranslation } from "react-i18next"; | |||||
| import { | |||||
| AdminCategoriesHeader, | |||||
| AdminCategoriesPageContainer, | |||||
| AdminCategoriesSearchField, | |||||
| } from "./AdminCategoriesPage.styled"; | |||||
| import { selectManualSearchString } from "../../store/selectors/filtersSelectors"; | |||||
| import { useMemo } from "react"; | |||||
| import { setManualSearchString } from "../../store/actions/filters/filtersActions"; | |||||
| const AdminCategoriesPage = () => { | |||||
| const { t } = useTranslation(); | |||||
| const dispatch = useDispatch(); | |||||
| const categories = useSelector(selectCategories); | |||||
| const manualSearchString = useSelector(selectManualSearchString); | |||||
| useEffect(() => { | |||||
| dispatch(fetchCategories()); | |||||
| }, []); | |||||
| const handleSearch = (value) => { | |||||
| console.log(value); | |||||
| dispatch(setManualSearchString(value)); | |||||
| }; | |||||
| const categoriesToShow = useMemo(() => { | |||||
| if (categories) { | |||||
| console.log(categories); | |||||
| console.log(manualSearchString); | |||||
| if (manualSearchString) | |||||
| return categories.filter((item) => | |||||
| item.name.toLowerCase().includes(manualSearchString.toLowerCase()) | |||||
| ); | |||||
| return categories; | |||||
| } | |||||
| return []; | |||||
| }, [categories, manualSearchString]); | |||||
| return ( | |||||
| <AdminCategoriesPageContainer> | |||||
| <AdminCategoriesSearchField | |||||
| isAdmin | |||||
| handleSearch={handleSearch} | |||||
| placeholder={t("admin.categories.placeholder")} | |||||
| /> | |||||
| <AdminCategoriesHeader | |||||
| myOffers | |||||
| categories | |||||
| hideGrid | |||||
| isAdmin | |||||
| hideBackButton | |||||
| /> | |||||
| {categoriesToShow.map((category) => ( | |||||
| <CategoryCard | |||||
| key={category._id} | |||||
| category={category} | |||||
| secondLabel={t("admin.categories.noOfSubcategories")} | |||||
| /> | |||||
| ))} | |||||
| </AdminCategoriesPageContainer> | |||||
| ); | |||||
| }; | |||||
| AdminCategoriesPage.propTypes = { | |||||
| children: PropTypes.node, | |||||
| }; | |||||
| export default AdminCategoriesPage; |
| import { Box } from "@mui/material"; | |||||
| import styled from "styled-components"; | |||||
| import Header from "../../components/MarketPlace/Header/Header"; | |||||
| import SearchField from "../../components/TextFields/SearchField/SearchField"; | |||||
| export const AdminCategoriesPageContainer = styled(Box)` | |||||
| padding: 15px 60px 60px 60px; | |||||
| @media (max-width: 600px) { | |||||
| padding: 18px; | |||||
| position: relative; | |||||
| top: 65px; | |||||
| } | |||||
| `; | |||||
| export const AdminCategoriesHeader = styled(Header)` | |||||
| /* top: 40px; */ | |||||
| top: 0; | |||||
| @media (max-width: 600px) { | |||||
| top: -10px; | |||||
| & div { | |||||
| margin-top: 0; | |||||
| } | |||||
| & div div:nth-child(1) { | |||||
| top: 22px; | |||||
| } | |||||
| } | |||||
| `; | |||||
| export const AdminCategoriesSearchField = styled(SearchField)` | |||||
| top: -15px; | |||||
| @media (max-width: 600px) { | |||||
| display: none; | |||||
| } | |||||
| `; |
| // import { OFFERS_SCOPE } from "../../store/actions/offers/offersActionConstants"; | // import { OFFERS_SCOPE } from "../../store/actions/offers/offersActionConstants"; | ||||
| import AdminUsersPage from "../AdminUsersPage/AdminUsersPage"; | import AdminUsersPage from "../AdminUsersPage/AdminUsersPage"; | ||||
| import { selectMineProfile } from "../../store/selectors/profileSelectors"; | import { selectMineProfile } from "../../store/selectors/profileSelectors"; | ||||
| import { Route, useHistory } from "react-router-dom"; | |||||
| import { ADMIN_USERS_PAGE, HOME_PAGE } from "../../constants/pages"; | |||||
| import { Switch, useHistory } from "react-router-dom"; | |||||
| import { | |||||
| ADMIN_CATEGORIES_PAGE, | |||||
| ADMIN_USERS_PAGE, | |||||
| HOME_PAGE, | |||||
| } from "../../constants/pages"; | |||||
| import { selectUserId } from "../../store/selectors/loginSelectors"; | import { selectUserId } from "../../store/selectors/loginSelectors"; | ||||
| // import AdminRoute from "../../components/Router/AdminRoute"; | |||||
| import AdminCategoriesPage from "../AdminCategoriesPage/AdminCategoriesPage"; | |||||
| import AdminRoute from "../../components/Router/AdminRoute"; | |||||
| const AdminHomePage = () => { | const AdminHomePage = () => { | ||||
| const profile = useSelector(selectMineProfile); | const profile = useSelector(selectMineProfile); | ||||
| leftCard={<Sidebar />} | leftCard={<Sidebar />} | ||||
| content={ | content={ | ||||
| // <MarketPlace offers={offers} isAdmin skeleton={isLoadingOffers} /> | // <MarketPlace offers={offers} isAdmin skeleton={isLoadingOffers} /> | ||||
| <> | |||||
| <Route path={ADMIN_USERS_PAGE} component={AdminUsersPage} /> | |||||
| <Route component={AdminUsersPage} /> | |||||
| </> | |||||
| <Switch> | |||||
| <AdminRoute path={ADMIN_USERS_PAGE} component={AdminUsersPage} /> | |||||
| <AdminRoute | |||||
| path={ADMIN_CATEGORIES_PAGE} | |||||
| component={AdminCategoriesPage} | |||||
| /> | |||||
| <AdminRoute component={AdminUsersPage} /> | |||||
| </Switch> | |||||
| } | } | ||||
| /> | /> | ||||
| ); | ); |
| import { createClearType, createSetType } from "../actionHelpers" | |||||
| import { createClearType, createSetType } from "../actionHelpers"; | |||||
| const FILTERS_SCOPE = "FILTERS" | |||||
| const FILTERS_SCOPE = "FILTERS"; | |||||
| export const SET_FILTERS = createSetType(FILTERS_SCOPE); | export const SET_FILTERS = createSetType(FILTERS_SCOPE); | ||||
| export const CLEAR_FILTERS = createClearType(FILTERS_SCOPE); | export const CLEAR_FILTERS = createClearType(FILTERS_SCOPE); | ||||
| export const SET_CATEGORY = createSetType("FILTERS_SET_CATEGORY"); | export const SET_CATEGORY = createSetType("FILTERS_SET_CATEGORY"); | ||||
| export const SET_QUERY_STRING = createSetType("FILTERS_SET_QUERY_STRING"); | export const SET_QUERY_STRING = createSetType("FILTERS_SET_QUERY_STRING"); | ||||
| export const SET_HEADER_STRING = createSetType("FILTERS_SET_HEADER_STRING"); | export const SET_HEADER_STRING = createSetType("FILTERS_SET_HEADER_STRING"); | ||||
| export const SET_SEARCH_STRING = createSetType("FILTERS_SET_SEARCH"); | export const SET_SEARCH_STRING = createSetType("FILTERS_SET_SEARCH"); | ||||
| export const SET_MANUAL_SEARCH_STRING = createSetType( | |||||
| "FILTERS_SET_MANUAL_SEARCH_STRING" | |||||
| ); |
| import { CLEAR_FILTERS, SET_CATEGORY, SET_FILTERS, SET_HEADER_STRING, SET_IS_APPLIED, SET_LOCATIONS, SET_QUERY_STRING, SET_SEARCH_STRING, SET_SORT_OPTION, SET_SUBCATEGORY } from "./filtersActionConstants"; | |||||
| import { | |||||
| CLEAR_FILTERS, | |||||
| SET_CATEGORY, | |||||
| SET_FILTERS, | |||||
| SET_HEADER_STRING, | |||||
| SET_IS_APPLIED, | |||||
| SET_LOCATIONS, | |||||
| SET_MANUAL_SEARCH_STRING, | |||||
| SET_QUERY_STRING, | |||||
| SET_SEARCH_STRING, | |||||
| SET_SORT_OPTION, | |||||
| SET_SUBCATEGORY, | |||||
| } from "./filtersActionConstants"; | |||||
| export const setFilters = (payload) => ({ | export const setFilters = (payload) => ({ | ||||
| type: SET_FILTERS, | |||||
| payload, | |||||
| }) | |||||
| type: SET_FILTERS, | |||||
| payload, | |||||
| }); | |||||
| export const clearFilters = () => ({ | export const clearFilters = () => ({ | ||||
| type: CLEAR_FILTERS | |||||
| }) | |||||
| type: CLEAR_FILTERS, | |||||
| }); | |||||
| export const setFilteredCategory = (payload) => ({ | export const setFilteredCategory = (payload) => ({ | ||||
| type: SET_CATEGORY, | |||||
| payload | |||||
| }) | |||||
| type: SET_CATEGORY, | |||||
| payload, | |||||
| }); | |||||
| export const setFilteredSubcategory = (payload) => ({ | export const setFilteredSubcategory = (payload) => ({ | ||||
| type: SET_SUBCATEGORY, | |||||
| payload | |||||
| }) | |||||
| type: SET_SUBCATEGORY, | |||||
| payload, | |||||
| }); | |||||
| export const setManualSearchString = (payload) => ({ | |||||
| type: SET_MANUAL_SEARCH_STRING, | |||||
| payload, | |||||
| }); | |||||
| export const setFilteredLocations = (payload) => ({ | export const setFilteredLocations = (payload) => ({ | ||||
| type: SET_LOCATIONS, | |||||
| payload | |||||
| }) | |||||
| type: SET_LOCATIONS, | |||||
| payload, | |||||
| }); | |||||
| export const setFilteredSortOption = (payload) => ({ | export const setFilteredSortOption = (payload) => ({ | ||||
| type: SET_SORT_OPTION, | |||||
| payload | |||||
| }) | |||||
| type: SET_SORT_OPTION, | |||||
| payload, | |||||
| }); | |||||
| export const setIsAppliedStatus = (payload) => ({ | export const setIsAppliedStatus = (payload) => ({ | ||||
| type: SET_IS_APPLIED, | |||||
| payload, | |||||
| }) | |||||
| type: SET_IS_APPLIED, | |||||
| payload, | |||||
| }); | |||||
| export const setQueryString = (payload) => ({ | export const setQueryString = (payload) => ({ | ||||
| type: SET_QUERY_STRING, | |||||
| payload, | |||||
| }) | |||||
| type: SET_QUERY_STRING, | |||||
| payload, | |||||
| }); | |||||
| export const setHeaderString = (payload) => ({ | export const setHeaderString = (payload) => ({ | ||||
| type: SET_HEADER_STRING, | |||||
| payload | |||||
| }) | |||||
| type: SET_HEADER_STRING, | |||||
| payload, | |||||
| }); | |||||
| export const setSearchString = (payload) => ({ | export const setSearchString = (payload) => ({ | ||||
| type: SET_SEARCH_STRING, | |||||
| payload | |||||
| }) | |||||
| type: SET_SEARCH_STRING, | |||||
| payload, | |||||
| }); |
| SET_HEADER_STRING, | SET_HEADER_STRING, | ||||
| SET_IS_APPLIED, | SET_IS_APPLIED, | ||||
| SET_LOCATIONS, | SET_LOCATIONS, | ||||
| SET_MANUAL_SEARCH_STRING, | |||||
| SET_SEARCH_STRING, | SET_SEARCH_STRING, | ||||
| SET_SORT_OPTION, | SET_SORT_OPTION, | ||||
| SET_SUBCATEGORY, | SET_SUBCATEGORY, | ||||
| categoryString: "", | categoryString: "", | ||||
| subcategoryString: "", | subcategoryString: "", | ||||
| locationsString: "", | locationsString: "", | ||||
| text: "" | |||||
| text: "", | |||||
| }, | }, | ||||
| searchString: "" | |||||
| searchString: "", | |||||
| manualSearchString: "", | |||||
| }, | }, | ||||
| }; | }; | ||||
| [SET_IS_APPLIED]: setIsAppliedStatus, | [SET_IS_APPLIED]: setIsAppliedStatus, | ||||
| [SET_HEADER_STRING]: setHeaderString, | [SET_HEADER_STRING]: setHeaderString, | ||||
| [SET_SEARCH_STRING]: setSearchString, | [SET_SEARCH_STRING]: setSearchString, | ||||
| [SET_MANUAL_SEARCH_STRING]: setManualSearchString, | |||||
| }, | }, | ||||
| initialState | initialState | ||||
| ); | ); | ||||
| function setManualSearchString(state, { payload }) { | |||||
| return { | |||||
| ...state, | |||||
| filters: { | |||||
| ...state.filters, | |||||
| manualSearchString: payload, | |||||
| }, | |||||
| }; | |||||
| } | |||||
| function setFilters(state, { payload }) { | function setFilters(state, { payload }) { | ||||
| return { | return { | ||||
| ...state, | ...state, | ||||
| }, | }, | ||||
| }; | }; | ||||
| } | } | ||||
| function setFilteredSortOption(state, {payload}) { | |||||
| function setFilteredSortOption(state, { payload }) { | |||||
| return { | return { | ||||
| ...state, | ...state, | ||||
| filters: { | filters: { | ||||
| ...state.filters, | ...state.filters, | ||||
| sortOption: payload, | sortOption: payload, | ||||
| } | |||||
| } | |||||
| }, | |||||
| }; | |||||
| } | } | ||||
| function setIsAppliedStatus(state, {payload}) { | |||||
| function setIsAppliedStatus(state, { payload }) { | |||||
| return { | return { | ||||
| ...state, | ...state, | ||||
| filters: { | filters: { | ||||
| ...state.filters, | ...state.filters, | ||||
| isApplied: payload, | isApplied: payload, | ||||
| } | |||||
| } | |||||
| }, | |||||
| }; | |||||
| } | } | ||||
| function setHeaderString(state, {payload}) { | |||||
| function setHeaderString(state, { payload }) { | |||||
| return { | return { | ||||
| ...state, | ...state, | ||||
| filters: { | filters: { | ||||
| ...state.filters, | ...state.filters, | ||||
| headerString: payload | |||||
| } | |||||
| } | |||||
| headerString: payload, | |||||
| }, | |||||
| }; | |||||
| } | } | ||||
| function setSearchString(state, {payload}) { | |||||
| function setSearchString(state, { payload }) { | |||||
| return { | return { | ||||
| ...state, | ...state, | ||||
| filters: { | filters: { | ||||
| ...state.filters, | ...state.filters, | ||||
| searchString: payload | |||||
| } | |||||
| } | |||||
| searchString: payload, | |||||
| }, | |||||
| }; | |||||
| } | } |
| import { createSelector } from 'reselect'; | |||||
| import { createSelector } from "reselect"; | |||||
| const filtersSelector = (state) => state.filters; | const filtersSelector = (state) => state.filters; | ||||
| export const selectFilters = createSelector( | export const selectFilters = createSelector( | ||||
| filtersSelector, | filtersSelector, | ||||
| (state) => state.filters, | |||||
| (state) => state.filters | |||||
| ); | ); | ||||
| export const selectSelectedCategory = createSelector( | export const selectSelectedCategory = createSelector( | ||||
| filtersSelector, | filtersSelector, | ||||
| (state => state.filters.category) | |||||
| ) | |||||
| (state) => state.filters.category | |||||
| ); | |||||
| export const selectSelectedSubcategory = createSelector( | export const selectSelectedSubcategory = createSelector( | ||||
| filtersSelector, | filtersSelector, | ||||
| (state) => state.filters.subcategory | (state) => state.filters.subcategory | ||||
| ) | |||||
| ); | |||||
| export const selectSelectedLocations = createSelector( | export const selectSelectedLocations = createSelector( | ||||
| filtersSelector, | filtersSelector, | ||||
| (state) => state.filters.locations | (state) => state.filters.locations | ||||
| ) | |||||
| ); | |||||
| export const selectSelectedSortOption = createSelector( | export const selectSelectedSortOption = createSelector( | ||||
| filtersSelector, | filtersSelector, | ||||
| (state) => state.filters.sortOption | (state) => state.filters.sortOption | ||||
| ) | |||||
| ); | |||||
| export const selectAppliedStatus = createSelector( | export const selectAppliedStatus = createSelector( | ||||
| filtersSelector, | filtersSelector, | ||||
| (state) => state.filters.isApplied | (state) => state.filters.isApplied | ||||
| ) | |||||
| ); | |||||
| export const selectHeaderString = createSelector( | export const selectHeaderString = createSelector( | ||||
| filtersSelector, | filtersSelector, | ||||
| (state) => state.filters.headerString | (state) => state.filters.headerString | ||||
| ) | |||||
| ); | |||||
| export const selectSearchString = createSelector( | export const selectSearchString = createSelector( | ||||
| filtersSelector, | filtersSelector, | ||||
| (state) => state.filters.searchString, | |||||
| ) | |||||
| (state) => state.filters.searchString | |||||
| ); | |||||
| export const selectManualSearchString = createSelector( | |||||
| filtersSelector, | |||||
| (state) => state.filters.manualSearchString | |||||
| ); |
| export const hexToRGB = (hex, opacity) => { | |||||
| var r = parseInt(hex.slice(1, 3), 16), | |||||
| g = parseInt(hex.slice(3, 5), 16), | |||||
| b = parseInt(hex.slice(5, 7), 16); | |||||
| if (opacity) { | |||||
| return `rgba(${r}, ${g}, ${b}, ${opacity})`; | |||||
| } else { | |||||
| return `rgb(${r}, ${g}, ${b})`; | |||||
| } | |||||
| } |
| import { | import { | ||||
| ADMIN_CATEGORIES_PAGE, | |||||
| ADMIN_HOME_PAGE, | ADMIN_HOME_PAGE, | ||||
| ADMIN_LOGIN_PAGE, | ADMIN_LOGIN_PAGE, | ||||
| ADMIN_USERS_PAGE, | ADMIN_USERS_PAGE, | ||||
| if ( | if ( | ||||
| routeMatches(ADMIN_LOGIN_PAGE) || | routeMatches(ADMIN_LOGIN_PAGE) || | ||||
| routeMatches(ADMIN_HOME_PAGE) || | routeMatches(ADMIN_HOME_PAGE) || | ||||
| routeMatches(ADMIN_USERS_PAGE) | |||||
| routeMatches(ADMIN_USERS_PAGE) || | |||||
| routeMatches(ADMIN_CATEGORIES_PAGE) | |||||
| ) | ) | ||||
| return true; | return true; | ||||
| return false; | return false; |