| @@ -7,9 +7,13 @@ export const SidebarContainer = styled(Box)` | |||
| position: fixed; | |||
| bottom: 0; | |||
| left: 0; | |||
| min-width: 20%; | |||
| width: 20%; | |||
| min-width: 281px; | |||
| overflow-y: auto; | |||
| height: 100vh; | |||
| @media (max-width: 600px) { | |||
| display: none; | |||
| } | |||
| `; | |||
| export const SidebarHeader = styled(Box)` | |||
| @@ -37,7 +37,7 @@ const CategoryCard = (props) => { | |||
| <CategoryCardContainer className={props.className}> | |||
| <CategoryCardLeftContainer> | |||
| <CategoryCardName | |||
| categoryName={props?.category?.name} | |||
| categoryName={props?.category?.name || props?.category?.city} | |||
| onClick={navigateToCategory} | |||
| /> | |||
| <CategoryCardDetailsContainer> | |||
| @@ -48,7 +48,10 @@ const CategoryCard = (props) => { | |||
| {!props.hideSecondLabel && ( | |||
| <CategoryDetail | |||
| label={props?.secondLabel} | |||
| value={props?.category?.subcategories?.length} | |||
| value={ | |||
| props?.category?.subcategories?.length || | |||
| props?.category?.offerCount | |||
| } | |||
| /> | |||
| )} | |||
| </CategoryCardDetailsContainer> | |||
| @@ -17,7 +17,15 @@ export const ProfileCardContainer = styled(Box)` | |||
| max-height: 184px; | |||
| margin-top: 34px; | |||
| overflow: hidden; | |||
| border: 1px solid ${selectedTheme.colors.borderNormal}; | |||
| border-radius: 0 0 4px 4px; | |||
| &:nth-child(1) { | |||
| margin-top: 20px; | |||
| } | |||
| &:nth-child(2) { | |||
| margin-top: ${(props) => props.halfwidth && `20px;`}; | |||
| } | |||
| @media (max-width: 1200px) { | |||
| padding: 0; | |||
| } | |||
| @@ -64,14 +72,13 @@ export const EditButton = styled(MessageButton)` | |||
| right: 76px; | |||
| `; | |||
| export const ProfileCardWrapper = styled(Card)` | |||
| border: 1px solid ${selectedTheme.colors.borderNormal}; | |||
| background: ${(props) => | |||
| props.isMyProfile ? selectedTheme.colors.primaryPurple : "white"}; | |||
| width: 100%; | |||
| min-width: fit-content; | |||
| padding: 1rem; | |||
| position: relative; | |||
| border-radius: 0 0 4px 4px; | |||
| position: relative; | |||
| `; | |||
| export const RemoveIconContainer = styled(MessageButton)` | |||
| display: block; | |||
| @@ -20,6 +20,7 @@ import { ReactComponent as CloseIcon } from "../../../../assets/images/svg/close | |||
| import { useTranslation } from "react-i18next"; | |||
| import { | |||
| editProfile, | |||
| fetchAllProfiles, | |||
| fetchMineProfile, | |||
| } from "../../../../store/actions/profile/profileActions"; | |||
| import { useDispatch, useSelector } from "react-redux"; | |||
| @@ -35,6 +36,15 @@ import WebsiteField from "./WebsiteField/WebsiteField"; | |||
| import AppLinkField from "./AppLinkField/AppLinkField"; | |||
| import PhoneField from "./PhoneField/PhoneField"; | |||
| import FormikErrorMessage from "./FormikErrorMessage/FormikErrorMessage"; | |||
| import { | |||
| dynamicRouteMatches, | |||
| routeMatches, | |||
| } from "../../../../util/helpers/routeHelpers"; | |||
| import { | |||
| ADMIN_HOME_PAGE, | |||
| ADMIN_USERS_PAGE, | |||
| PROFILE_PAGE, | |||
| } from "../../../../constants/pages"; | |||
| const EditProfile = (props) => { | |||
| const [profileImage, setProfileImage] = useState(props.profile.image); | |||
| @@ -51,7 +61,9 @@ const EditProfile = (props) => { | |||
| }, [isMobile]); | |||
| const handleApiResponseSuccess = () => { | |||
| dispatch(fetchMineProfile(userId)); | |||
| if (dynamicRouteMatches(PROFILE_PAGE)) dispatch(fetchMineProfile(userId)); | |||
| if (routeMatches(ADMIN_USERS_PAGE) || routeMatches(ADMIN_HOME_PAGE)) | |||
| dispatch(fetchAllProfiles()); | |||
| props.reFetchProfile(); | |||
| }; | |||
| @@ -61,6 +73,7 @@ const EditProfile = (props) => { | |||
| editProfile({ | |||
| userId: props.userId, | |||
| ...values, | |||
| firmLogo: profileImage, | |||
| handleApiResponseSuccess, | |||
| }) | |||
| ); | |||
| @@ -68,6 +81,7 @@ const EditProfile = (props) => { | |||
| dispatch( | |||
| editProfile({ | |||
| ...values, | |||
| firmLogo: profileImage, | |||
| handleApiResponseSuccess, | |||
| }) | |||
| ); | |||
| @@ -22,6 +22,7 @@ const ImagePicker = (props) => { | |||
| // Check if file is type of string or File | |||
| useEffect(() => { | |||
| if (props.image) { | |||
| if (typeof props.image === "string") { | |||
| setImage(getImageUrl(props.image, variants.offerCard)); | |||
| } else { | |||
| @@ -2,7 +2,6 @@ import React, { useMemo } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { | |||
| ButtonContainer, | |||
| // ButtonContainer, | |||
| CategoryHeaderIcon, | |||
| CategoryIcon, | |||
| HeaderAltLocation, | |||
| @@ -17,11 +16,11 @@ import { | |||
| HeaderSelect, | |||
| HeaderSubcategoryString, | |||
| HeaderText, | |||
| // HeaderText, | |||
| HeaderTitleContainer, | |||
| HeaderTitleText, | |||
| HeaderWrapperContainer, | |||
| IconStyled, | |||
| LocationIcon, | |||
| PageTitleContainer, | |||
| SelectOption, | |||
| SubcategoryIcon, | |||
| @@ -71,6 +70,39 @@ const Header = (props) => { | |||
| return `: ${t("header.newOffers")}`; | |||
| }, [sorting?.selectedSortOption]); | |||
| const headerTitle = useMemo(() => { | |||
| return props.users | |||
| ? t("admin.users.headerTitle") | |||
| : props.categories | |||
| ? t("admin.categories.headerTitle") | |||
| : props.subcategories | |||
| ? t("admin.subcategories.subcategoriesHeaderTitle") | |||
| : props.category | |||
| ? t("admin.subcategories.headerTitle") | |||
| : props.location | |||
| ? t("admin.locations.headerTitle") | |||
| : !isMobile | |||
| ? t("header.myOffers") | |||
| : props.myOffers | |||
| ? t("header.myOffers") | |||
| : t("offer.offers"); | |||
| }, [props, t, isMobile]); | |||
| const headerIcon = useMemo(() => { | |||
| return props.users ? ( | |||
| <UserIcon /> | |||
| ) : props.categories || props.category ? ( | |||
| <CategoryIcon /> | |||
| ) : props.subcategories ? ( | |||
| <SubcategoryIcon /> | |||
| ) : props.location ? ( | |||
| <LocationIcon /> | |||
| ) : isMobile ? ( | |||
| <SwapsIcon /> | |||
| ) : ( | |||
| <SwapsHeaderIcon /> | |||
| ); | |||
| }); | |||
| const handleChangeSelect = (event) => { | |||
| if (!props.users) sorting?.changeSorting(event.target.value); | |||
| }; | |||
| @@ -132,26 +164,8 @@ const Header = (props) => { | |||
| <> | |||
| {!isMobile ? ( | |||
| <HeaderTitleContainer> | |||
| {props.users ? ( | |||
| <UserIcon /> | |||
| ) : props.categories || props.category ? ( | |||
| <CategoryIcon /> | |||
| ) : props.subcategories ? ( | |||
| <SubcategoryIcon /> | |||
| ) : ( | |||
| <SwapsHeaderIcon /> | |||
| )} | |||
| <HeaderTitleText> | |||
| {props.users | |||
| ? t("admin.users.headerTitle") | |||
| : props.categories | |||
| ? t("admin.categories.headerTitle") | |||
| : props.subcategories | |||
| ? t("admin.subcategories.subcategoriesHeaderTitle") | |||
| : props.category | |||
| ? t("admin.subcategories.headerTitle") | |||
| : t("header.myOffers")} | |||
| </HeaderTitleText> | |||
| {headerIcon} | |||
| <HeaderTitleText>{headerTitle}</HeaderTitleText> | |||
| </HeaderTitleContainer> | |||
| ) : ( | |||
| !props.hideBackButton && ( | |||
| @@ -231,28 +245,8 @@ const Header = (props) => { | |||
| </HeaderContainer> | |||
| {isMobile && ( | |||
| <PageTitleContainer> | |||
| {props.users ? ( | |||
| <UserIcon /> | |||
| ) : props.categories || props.category ? ( | |||
| <CategoryIcon /> | |||
| ) : props.subcategories ? ( | |||
| <SubcategoryIcon /> | |||
| ) : ( | |||
| <SwapsIcon /> | |||
| )} | |||
| <SwapsTitle> | |||
| {props.users | |||
| ? t("admin.users.headerTitle") | |||
| : props.categories | |||
| ? t("admin.categories.headerTitle") | |||
| : props.subcategories | |||
| ? t("admin.subcategories.subcategoriesHeaderTitle") | |||
| : props.category | |||
| ? t("admin.subcategories.headerTitle") | |||
| : props?.myOffers | |||
| ? t("header.myOffers") | |||
| : t("offer.offers")} | |||
| </SwapsTitle> | |||
| {headerIcon} | |||
| <SwapsTitle>{headerTitle}</SwapsTitle> | |||
| </PageTitleContainer> | |||
| )} | |||
| </HeaderWrapperContainer> | |||
| @@ -277,6 +271,7 @@ Header.propTypes = { | |||
| category: PropTypes.bool, | |||
| subcategories: PropTypes.bool, | |||
| hideSorting: PropTypes.bool, | |||
| location: PropTypes.bool, | |||
| }; | |||
| Header.defaultProps = { | |||
| isGrid: false, | |||
| @@ -9,6 +9,7 @@ import { ReactComponent as CategoryHeader } from "../../../assets/images/svg/cat | |||
| import { ReactComponent as User } from "../../../assets/images/svg/user.svg"; | |||
| import { ReactComponent as Category } from "../../../assets/images/svg/category.svg"; | |||
| import { ReactComponent as Subcategory } from "../../../assets/images/svg/subcategory.svg"; | |||
| import { ReactComponent as Location } from "../../../assets/images/svg/location.svg"; | |||
| export const HeaderWrapperContainer = styled(Box)` | |||
| display: ${(props) => (props.skeleton ? "none" : "block")}; | |||
| @@ -274,3 +275,11 @@ export const UserIcon = styled(User)` | |||
| stroke: ${selectedTheme.colors.primaryText}; | |||
| } | |||
| `; | |||
| export const LocationIcon = styled(Location)` | |||
| position: relative; | |||
| top: 3px; | |||
| margin-right: 5px; | |||
| & path { | |||
| stroke: ${selectedTheme.colors.primaryText}; | |||
| } | |||
| `; | |||
| @@ -20,8 +20,7 @@ const DeleteCategory = (props) => { | |||
| props.setOpenedDeleteModal(false); | |||
| }; | |||
| const reassuranceText = useMemo(() => { | |||
| if (props.subcategory) return t("admin.subcategories.reassuranceDelete"); | |||
| return t("admin.categories.reassuranceDelete"); | |||
| return t(`admin.${props.type}.reassuranceDelete`); | |||
| }, [props]); | |||
| return ( | |||
| <> | |||
| @@ -32,7 +31,7 @@ const DeleteCategory = (props) => { | |||
| /> | |||
| <DeleteCategoryContainer> | |||
| <LabeledCard icon={<DeleteIcon />}> | |||
| <CategoryName>{props.category.name}</CategoryName> | |||
| <CategoryName>{props.category?.name || props.category?.city}</CategoryName> | |||
| </LabeledCard> | |||
| <ReassuranceText>{reassuranceText}</ReassuranceText> | |||
| <ButtonsContainer> | |||
| @@ -57,6 +56,7 @@ DeleteCategory.propTypes = { | |||
| setOpenedDeleteModal: PropTypes.func, | |||
| category: PropTypes.object, | |||
| subcategory: PropTypes.bool, | |||
| type: PropTypes.string, | |||
| }; | |||
| export default DeleteCategory; | |||
| @@ -453,15 +453,15 @@ export default { | |||
| title: "Izmena Kategorije", | |||
| fieldTitle: "Naslov", | |||
| placeholder: "Naziv kategorije...", | |||
| save: "Izmeni" | |||
| save: "Izmeni", | |||
| }, | |||
| add: { | |||
| title: "Nova Kategorija", | |||
| fieldTitle: "Naslov", | |||
| placeholder: "Naziv kategorije...", | |||
| save: "Dodaj", | |||
| next: "Sledeća" | |||
| } | |||
| next: "Sledeća", | |||
| }, | |||
| }, | |||
| subcategories: { | |||
| noOfOffers: "Broj objava: ", | |||
| @@ -469,20 +469,42 @@ export default { | |||
| subcategoriesHeaderTitle: "Podkategorije", | |||
| placeholder: "Pretražite podkategorije...", | |||
| addSubcategory: "Dodaj podkategoriju", | |||
| reassuranceDelete: "Da li ste sigurni da želite da obrišete odabranu podkategoriju?", | |||
| reassuranceDelete: | |||
| "Da li ste sigurni da želite da obrišete odabranu podkategoriju?", | |||
| edit: { | |||
| title: "Izmena Podkategorije", | |||
| fieldTitle: "Naslov", | |||
| placeholder: "Naziv podkategorije...", | |||
| save: "Izmeni" | |||
| save: "Izmeni", | |||
| }, | |||
| add: { | |||
| title: "Nova Podkategorija", | |||
| fieldTitle: "Naslov", | |||
| placeholder: "Naziv podkategorije...", | |||
| save: "Dodaj", | |||
| next: "Sledeća" | |||
| } | |||
| next: "Sledeća", | |||
| }, | |||
| }, | |||
| locations: { | |||
| headerTitle: "Lokacije", | |||
| noOfCompanies: "Broj firmi u gradu: ", | |||
| placeholder: "Pretražite lokacije...", | |||
| addLocation: "Dodaj lokaciju", | |||
| reassuranceDelete: | |||
| "Da li ste sigurni da želite da obrišete odabranu lokaciju?", | |||
| edit: { | |||
| title: "Izmena Lokacije", | |||
| fieldTitle: "Naslov", | |||
| placeholder: "Naziv lokacije...", | |||
| save: "Izmeni", | |||
| }, | |||
| add: { | |||
| title: "Nova Lokacija", | |||
| fieldTitle: "Naslov", | |||
| placeholder: "Naziv lokacije...", | |||
| save: "Dodaj", | |||
| next: "Sledeća", | |||
| }, | |||
| }, | |||
| }, | |||
| }; | |||
| @@ -1,23 +1,24 @@ | |||
| import React from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import CategoryCard from "../../components/Cards/CategoryCard/CategoryCard"; | |||
| 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 { fetchCategories } from "../../../store/actions/categories/categoriesActions"; | |||
| import { selectCategories } from "../../../store/selectors/categoriesSelectors"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { | |||
| AdminCategoriesHeader, | |||
| AdminCategoriesPageContainer, | |||
| AdminCategoriesSearchField, | |||
| CategoriesList, | |||
| NewCategoryButton, | |||
| } from "./AdminCategoriesPage.styled"; | |||
| import { selectManualSearchString } from "../../store/selectors/filtersSelectors"; | |||
| import { selectManualSearchString } from "../../../store/selectors/filtersSelectors"; | |||
| import { useMemo } from "react"; | |||
| import { setManualSearchString } from "../../store/actions/filters/filtersActions"; | |||
| import selectedTheme from "../../themes"; | |||
| import { setManualSearchString } from "../../../store/actions/filters/filtersActions"; | |||
| import selectedTheme from "../../../themes"; | |||
| import { useState } from "react"; | |||
| import EditCategory from "../../components/Modals/EditCategory/EditCategory"; | |||
| import EditCategory from "../../../components/Modals/EditCategory/EditCategory"; | |||
| const AdminCategoriesPage = () => { | |||
| const { t } = useTranslation(); | |||
| @@ -34,8 +35,6 @@ const AdminCategoriesPage = () => { | |||
| }; | |||
| const categoriesToShow = useMemo(() => { | |||
| if (categories) { | |||
| console.log(categories); | |||
| console.log(manualSearchString); | |||
| if (manualSearchString) | |||
| return categories.filter((item) => | |||
| item.name.toLowerCase().includes(manualSearchString.toLowerCase()) | |||
| @@ -46,43 +45,45 @@ const AdminCategoriesPage = () => { | |||
| }, [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} | |||
| type="categories" | |||
| secondLabel={t("admin.categories.noOfSubcategories")} | |||
| <AdminCategoriesPageContainer> | |||
| <AdminCategoriesSearchField | |||
| isAdmin | |||
| handleSearch={handleSearch} | |||
| placeholder={t("admin.categories.placeholder")} | |||
| /> | |||
| ))} | |||
| <NewCategoryButton | |||
| variant="contained" | |||
| buttoncolor={selectedTheme.colors.iconYellowColor} | |||
| textcolor={selectedTheme.colors.messageText} | |||
| onClick={() => setOpenedAddModal(true)} | |||
| > | |||
| {t("admin.categories.addCategory")} | |||
| </NewCategoryButton> | |||
| </AdminCategoriesPageContainer> | |||
| {openedAddModal && ( | |||
| <EditCategory | |||
| setOpenedEditModal={setOpenedAddModal} | |||
| type={"categories"} | |||
| method="add" | |||
| /> | |||
| )} | |||
| <AdminCategoriesHeader | |||
| myOffers | |||
| categories | |||
| hideGrid | |||
| isAdmin | |||
| hideBackButton | |||
| /> | |||
| <CategoriesList> | |||
| {categoriesToShow.map((category) => ( | |||
| <CategoryCard | |||
| key={category._id} | |||
| category={category} | |||
| type="categories" | |||
| secondLabel={t("admin.categories.noOfSubcategories")} | |||
| /> | |||
| ))} | |||
| </CategoriesList> | |||
| <NewCategoryButton | |||
| variant="contained" | |||
| buttoncolor={selectedTheme.colors.iconYellowColor} | |||
| textcolor={selectedTheme.colors.messageText} | |||
| onClick={() => setOpenedAddModal(true)} | |||
| > | |||
| {t("admin.categories.addCategory")} | |||
| </NewCategoryButton> | |||
| </AdminCategoriesPageContainer> | |||
| {openedAddModal && ( | |||
| <EditCategory | |||
| setOpenedEditModal={setOpenedAddModal} | |||
| type={"categories"} | |||
| method="add" | |||
| /> | |||
| )} | |||
| </> | |||
| ); | |||
| }; | |||
| @@ -1,19 +1,20 @@ | |||
| import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import { PrimaryButton } from "../../components/Buttons/PrimaryButton/PrimaryButton"; | |||
| import Header from "../../components/MarketPlace/Header/Header"; | |||
| import SearchField from "../../components/TextFields/SearchField/SearchField"; | |||
| import { PrimaryButton } from "../../../components/Buttons/PrimaryButton/PrimaryButton"; | |||
| import Header from "../../../components/MarketPlace/Header/Header"; | |||
| import SearchField from "../../../components/TextFields/SearchField/SearchField"; | |||
| export const AdminCategoriesPageContainer = styled(Box)` | |||
| padding: 60px; | |||
| padding-top: 38px; | |||
| min-height: 100vh; | |||
| position: relative; | |||
| padding-bottom: 100px; | |||
| position: relative; | |||
| @media (max-width: 600px) { | |||
| padding: 18px; | |||
| min-height: calc(100vh - 72px); | |||
| top: 65px; | |||
| padding-bottom: 54px; | |||
| top: 65px; | |||
| } | |||
| `; | |||
| export const AdminCategoriesHeader = styled(Header)` | |||
| @@ -21,8 +22,9 @@ export const AdminCategoriesHeader = styled(Header)` | |||
| top: 0; | |||
| @media (max-width: 600px) { | |||
| top: -10px; | |||
| margin-top: 18px; | |||
| & div { | |||
| margin-top: 0; | |||
| margin-top: 10px; | |||
| } | |||
| & div div:nth-child(1) { | |||
| top: 22px; | |||
| @@ -49,3 +51,6 @@ export const NewCategoryButton = styled(PrimaryButton)` | |||
| right: 16px; | |||
| } | |||
| ` | |||
| export const CategoriesList = styled(Box)` | |||
| padding-top: 10px | |||
| ` | |||
| @@ -7,7 +7,7 @@ import { MainLayoutAdminHomePage } from "./AdminHomePage.styled"; | |||
| import { useSelector } from "react-redux"; | |||
| // import { selectIsLoadingByActionType } from "../../store/selectors/loadingSelectors"; | |||
| // 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 { Switch, useHistory } from "react-router-dom"; | |||
| import { | |||
| @@ -19,7 +19,7 @@ import { | |||
| HOME_PAGE, | |||
| } from "../../constants/pages"; | |||
| import { selectUserId } from "../../store/selectors/loginSelectors"; | |||
| import AdminCategoriesPage from "../AdminCategoriesPage/AdminCategoriesPage"; | |||
| import AdminCategoriesPage from "./AdminCategoriesPage/AdminCategoriesPage"; | |||
| import AdminRoute from "../../components/Router/AdminRoute"; | |||
| import AdminSubcategoriesPage from "./AdminSubcategoriesPage/AdminSubcategoriesPage"; | |||
| import AdminLocationsPage from "./AdminLocationsPage/AdminLocationsPage"; | |||
| @@ -1,10 +1,88 @@ | |||
| import React from "react"; | |||
| import React, { useEffect, useMemo, useState } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import { AdminLocationsPageContainer } from "./AdminLocationsPage.styled"; | |||
| import { | |||
| AdminLocationsHeader, | |||
| AdminLocationsPageContainer, | |||
| AdminLocationsSearchField, | |||
| LocationsList, | |||
| NewLocationButton, | |||
| } from "./AdminLocationsPage.styled"; | |||
| import { useTranslation } from "react-i18next"; | |||
| import { useDispatch, useSelector } from "react-redux"; | |||
| import { selectLocations } from "../../../store/selectors/locationsSelectors"; | |||
| import { fetchLocations } from "../../../store/actions/locations/locationsActions"; | |||
| import CategoryCard from "../../../components/Cards/CategoryCard/CategoryCard"; | |||
| import selectedTheme from "../../../themes"; | |||
| import EditCategory from "../../../components/Modals/EditCategory/EditCategory"; | |||
| import { setManualSearchString } from "../../../store/actions/filters/filtersActions"; | |||
| import { selectManualSearchString } from "../../../store/selectors/filtersSelectors"; | |||
| const AdminLocationsPage = () => { | |||
| const [openedAddModal, setOpenedAddModal] = useState(false); | |||
| const { t } = useTranslation(); | |||
| const dispatch = useDispatch(); | |||
| const locations = useSelector(selectLocations); | |||
| const manualSearchString = useSelector(selectManualSearchString); | |||
| useEffect(() => { | |||
| dispatch(fetchLocations()); | |||
| }, []); | |||
| const handleSearch = (value) => { | |||
| console.log(value); | |||
| dispatch(setManualSearchString(value)); | |||
| }; | |||
| const locationsToShow = useMemo(() => { | |||
| if (locations) { | |||
| if (manualSearchString) | |||
| return locations.filter((item) => | |||
| item.city.toLowerCase().includes(manualSearchString.toLowerCase()) | |||
| ); | |||
| return locations; | |||
| } | |||
| }, [locations, manualSearchString]); | |||
| return ( | |||
| <AdminLocationsPageContainer>Admin locations</AdminLocationsPageContainer> | |||
| <> | |||
| <AdminLocationsPageContainer> | |||
| <AdminLocationsSearchField | |||
| isAdmin | |||
| handleSearch={handleSearch} | |||
| placeholder={t("admin.locations.placeholder")} | |||
| /> | |||
| <AdminLocationsHeader | |||
| myOffers | |||
| location | |||
| hideGrid | |||
| isAdmin | |||
| hideBackButton | |||
| /> | |||
| <LocationsList> | |||
| {locationsToShow.map((category) => ( | |||
| <CategoryCard | |||
| key={category._id} | |||
| category={category} | |||
| type="locations" | |||
| hideCheckButton | |||
| secondLabel={t("admin.locations.noOfCompanies")} | |||
| /> | |||
| ))} | |||
| </LocationsList> | |||
| <NewLocationButton | |||
| variant="contained" | |||
| buttoncolor={selectedTheme.colors.iconYellowColor} | |||
| textcolor={selectedTheme.colors.messageText} | |||
| onClick={() => setOpenedAddModal(true)} | |||
| > | |||
| {t("admin.locations.addLocation")} | |||
| </NewLocationButton> | |||
| </AdminLocationsPageContainer> | |||
| {openedAddModal && ( | |||
| <EditCategory | |||
| hideImagePicker | |||
| setOpenedEditModal={setOpenedAddModal} | |||
| type={"locations"} | |||
| method="add" | |||
| /> | |||
| )} | |||
| </> | |||
| ); | |||
| }; | |||
| @@ -1,6 +1,56 @@ | |||
| import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| import { PrimaryButton } from "../../../components/Buttons/PrimaryButton/PrimaryButton"; | |||
| import Header from "../../../components/MarketPlace/Header/Header"; | |||
| import SearchField from "../../../components/TextFields/SearchField/SearchField"; | |||
| export const AdminLocationsPageContainer = styled(Box)` | |||
| ` | |||
| padding: 60px; | |||
| position: relative; | |||
| padding-bottom: 100px; | |||
| padding-top: 38px; | |||
| min-height: 100vh; | |||
| flex-direction: column; | |||
| @media (max-width: 600px) { | |||
| padding: 18px; | |||
| min-height: (100vh - 72px); | |||
| padding-bottom: 54px; | |||
| top: 65px; | |||
| } | |||
| `; | |||
| export const AdminLocationsHeader = styled(Header)` | |||
| top: 0; | |||
| @media (max-width: 600px) { | |||
| top: -10px; | |||
| margin-top: 18px; | |||
| & div { | |||
| margin-top: 10px; | |||
| } | |||
| & div div:nth-child(1) { | |||
| top: 22px; | |||
| } | |||
| } | |||
| `; | |||
| export const LocationsList = styled(Box)` | |||
| padding-top: 10px; | |||
| ` | |||
| export const AdminLocationsSearchField = styled(SearchField)` | |||
| top: -15px; | |||
| @media (max-width: 600px) { | |||
| display: none; | |||
| } | |||
| `; | |||
| export const NewLocationButton = styled(PrimaryButton)` | |||
| position: absolute; | |||
| bottom: 18px; | |||
| right: 33px; | |||
| height: 48px; | |||
| width: 224px; | |||
| & button { | |||
| font-weight: 700; | |||
| } | |||
| @media (max-width: 600px) { | |||
| bottom: 18px; | |||
| right: 16px; | |||
| } | |||
| `; | |||
| @@ -11,6 +11,7 @@ import { | |||
| AdminSubcategoriesSearchField, | |||
| NewSubcategoryButton, | |||
| SponsoredCategoryCard, | |||
| SubcategoriesList, | |||
| } from "./AdminSubcategoriesPage.styled"; | |||
| import { selectManualSearchString } from "../../../store/selectors/filtersSelectors"; | |||
| import { useMemo } from "react"; | |||
| @@ -75,13 +76,15 @@ const AdminSubcategoriesPage = () => { | |||
| isAdmin | |||
| hideBackButton | |||
| /> | |||
| <SponsoredCategoryCard | |||
| subcategory | |||
| category={category} | |||
| hideSecondLabel | |||
| type="categories" | |||
| hideCheckButton | |||
| /> | |||
| <SubcategoriesList> | |||
| <SponsoredCategoryCard | |||
| subcategory | |||
| category={category} | |||
| hideSecondLabel | |||
| type="categories" | |||
| hideCheckButton | |||
| /> | |||
| </SubcategoriesList> | |||
| <AdminSubcategoriesHeader | |||
| hideSorting | |||
| myOffers | |||
| @@ -90,16 +93,18 @@ const AdminSubcategoriesPage = () => { | |||
| isAdmin | |||
| hideBackButton | |||
| /> | |||
| {subcategories.map((category) => ( | |||
| <CategoryCard | |||
| subcategory | |||
| key={category._id} | |||
| category={category} | |||
| type="subcategories" | |||
| hideSecondLabel | |||
| hideCheckButton | |||
| /> | |||
| ))} | |||
| <SubcategoriesList> | |||
| {subcategories.map((category) => ( | |||
| <CategoryCard | |||
| subcategory | |||
| key={category._id} | |||
| category={category} | |||
| type="subcategories" | |||
| hideSecondLabel | |||
| hideCheckButton | |||
| /> | |||
| ))} | |||
| </SubcategoriesList> | |||
| <NewSubcategoryButton | |||
| variant="contained" | |||
| buttoncolor={selectedTheme.colors.iconYellowColor} | |||
| @@ -8,8 +8,9 @@ import selectedTheme from "../../../themes"; | |||
| export const AdminSubcategoriesPageContainer = styled(Box)` | |||
| padding: 60px; | |||
| display: flex; | |||
| /* display: flex; */ | |||
| position: relative; | |||
| padding-top: 38px; | |||
| padding-bottom: 100px; | |||
| min-height: 100vh; | |||
| flex-direction: column; | |||
| @@ -21,8 +22,7 @@ export const AdminSubcategoriesPageContainer = styled(Box)` | |||
| } | |||
| `; | |||
| export const AdminSubcategoriesHeader = styled(Header)` | |||
| /* top: 40px; */ | |||
| top: 0; | |||
| top: 4px; | |||
| @media (max-width: 600px) { | |||
| top: -10px; | |||
| margin-top: 18px; | |||
| @@ -40,6 +40,9 @@ export const AdminSubcategoriesSearchField = styled(SearchField)` | |||
| display: none; | |||
| } | |||
| `; | |||
| export const SubcategoriesList = styled(Box)` | |||
| padding-top: 18px; | |||
| ` | |||
| export const SponsoredCategoryCard = styled(CategoryCard)` | |||
| background: ${selectedTheme.colors.backgroundSponsoredColor}; | |||
| border: 1px solid ${selectedTheme.colors.borderSponsoredColor}; | |||
| @@ -1,9 +1,10 @@ | |||
| import React, { useEffect } from "react"; | |||
| import PropTypes from "prop-types"; | |||
| import MarketPlace from "../../components/MarketPlace/MarketPlace"; | |||
| import MarketPlace from "../../../components/MarketPlace/MarketPlace"; | |||
| import { useDispatch, useSelector } from "react-redux"; | |||
| import { selectAllProfiles } from "../../store/selectors/profileSelectors"; | |||
| import { fetchAllProfiles } from "../../store/actions/profile/profileActions"; | |||
| import { selectAllProfiles } from "../../../store/selectors/profileSelectors"; | |||
| import { fetchAllProfiles } from "../../../store/actions/profile/profileActions"; | |||
| import { AdminUsersPageContainer } from "./AdminUsersPage.styled"; | |||
| const AdminUsersPage = () => { | |||
| const dispatch = useDispatch(); | |||
| @@ -13,12 +14,14 @@ const AdminUsersPage = () => { | |||
| }, []); | |||
| return ( | |||
| <MarketPlace | |||
| isAdmin | |||
| myOffers | |||
| users | |||
| allUsers={Array.isArray(allUsers) ? allUsers : []} | |||
| /> | |||
| <AdminUsersPageContainer> | |||
| <MarketPlace | |||
| isAdmin | |||
| myOffers | |||
| users | |||
| allUsers={Array.isArray(allUsers) ? allUsers : []} | |||
| /> | |||
| </AdminUsersPageContainer> | |||
| ); | |||
| }; | |||
| @@ -0,0 +1,13 @@ | |||
| import { Box } from "@mui/material"; | |||
| import styled from "styled-components"; | |||
| export const AdminUsersPageContainer = styled(Box)` | |||
| & > div { | |||
| margin-left: 60px; | |||
| margin-right: 60px; | |||
| margin-top: 43px; | |||
| } | |||
| & > div > div:nth-child(2) { | |||
| top: 77px; | |||
| } | |||
| ` | |||