Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Контроль и ограничения (часть 1) #7

Merged
merged 1 commit into from
Mar 9, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 4 additions & 9 deletions src/components/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,27 +6,22 @@ import { Route, Routes } from 'react-router-dom';
import { AppRoute, authorizationStatus } from '../const';
import NotFoundPage from '../pages/not-found-page';
import ProtectedRoute from './protected-route';
import { Offer } from '../types/offer';

type TAppProps = {
offers: Offer[];
}

export default function App({ offers }: TAppProps) {
export default function App() {
return (
<Routes>
<Route path='/'>
<Route
index
element={<MainPage offers={offers} />}
element={<MainPage />}
/>
<Route
path={`/${AppRoute.Offer}/:offerId`}
element={<OfferPage offers={offers} />}
element={<OfferPage />}
/>
<Route
path={AppRoute.Favorites}
element={<ProtectedRoute hasAccess={authorizationStatus.AUTH}> <FavoritePage offers={offers} /></ProtectedRoute>}
element={<ProtectedRoute hasAccess={authorizationStatus.AUTH}> <FavoritePage /></ProtectedRoute>}
/>
<Route
path={AppRoute.Login}
Expand Down
38 changes: 24 additions & 14 deletions src/components/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,40 +9,50 @@
width: string;
height: string;
};
handelPointCardMouseOver?: (currentOffer: OfferPreviews | null) => void;
}

export default function Card({ offer, optionCard }: TCardProps) {
export default function Card({ offer, optionCard, handelPointCardMouseOver }: TCardProps) {
const { width, height, classCard } = optionCard;

const onPointCardMouseOver = () => {
handelPointCardMouseOver(offer);

Check failure on line 19 in src/components/card.tsx

View workflow job for this annotation

GitHub Actions / build

Cannot invoke an object which is possibly 'undefined'.
};

const onPointCardMouseLeave = () => {
handelPointCardMouseOver(null);

Check failure on line 23 in src/components/card.tsx

View workflow job for this annotation

GitHub Actions / build

Cannot invoke an object which is possibly 'undefined'.
};

return (
<article className={`${classCard} place-card`} data-id={offer.id}>
<article className={`${classCard} place-card`} onMouseOver={onPointCardMouseOver} onMouseLeave={onPointCardMouseLeave}>
{offer.isPremium &&
<div className="place-card__mark">
<span>Premium</span>
</div>}

<div className="cities__image-wrapper place-card__image-wrapper">
<Link to={`/${AppRoute.Offer}/${offer.id}`}>
<img className="place-card__image" src={`${offer.previewImage}`} width={width} height={height} alt="Place image" data-id={offer.id} />
<img className="place-card__image" src={`${offer.previewImage}`} width={width} height={height} alt="Place image" />
</Link>
</div>
<div className="place-card__info" data-id={offer.id}>
<div className="place-card__price-wrapper" data-id={offer.id}>
<div className="place-card__price" data-id={offer.id}>
<b className="place-card__price-value" data-id={offer.id}>&euro;{offer.price}</b>
<span className="place-card__price-text" data-id={offer.id}>&#47;&nbsp;night</span>
<div className="place-card__info" >
<div className="place-card__price-wrapper" >
<div className="place-card__price" >
<b className="place-card__price-value" >&euro;{offer.price}</b>
<span className="place-card__price-text" >&#47;&nbsp;night</span>
</div>
<button className="place-card__bookmark-button button" type="button" data-id={offer.id}>
<svg className="place-card__bookmark-icon" width="18" height="19" data-id={offer.id}>
<button className="place-card__bookmark-button button" type="button" >
<svg className="place-card__bookmark-icon" width="18" height="19" >
<use xlinkHref="#icon-bookmark"></use>
</svg>
<span className="visually-hidden">To bookmarks</span>
</button>
</div>
<Rating ratingClass="place-card" rating={offer.rating} data-id={offer.id} />
<h2 className="place-card__name" data-id={offer.id}>
<Link to={`/${AppRoute.Offer}/${offer.id}`} state={offer} data-id={offer.id}>{offer.title}</Link>
<Rating ratingClass="place-card" rating={offer.rating} />
<h2 className="place-card__name" >
<Link to={`/${AppRoute.Offer}/${offer.id}`} state={offer} >{offer.title}</Link>
</h2>
<p className="place-card__type" data-id={offer.id}>{offer.type}</p>
<p className="place-card__type" >{offer.type}</p>
</div>
</article>
);
Expand Down
21 changes: 7 additions & 14 deletions src/components/list-cards.tsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,23 @@
import { MouseEvent, useState } from 'react';
import { optionCard } from '../const';
import { OptionCard } from '../const';
import { Offer } from '../types/offer';
import Card from './card';
import { OfferPreviews } from '../types/offer-preview';

type ListOfferNearbyProps = {
offers: Offer[];
onListItemHover: (currentCard: Offer) => void;
onListItemHover: (currentCard: OfferPreviews | null) => void;
extraClass: string;
}

export default function ListCards({ offers, onListItemHover, extraClass }: ListOfferNearbyProps) {
const [cardId, setCardId] = useState('');

const onPointingCardMouseOver = ({ target }: MouseEvent<HTMLDivElement>) => {
setCardId(target.dataset.id);
const handelPointingCardMouseOver = (offer: OfferPreviews | null) => {
onListItemHover(offer);
};

const currentCard = offers.find((offer) => offer.id === cardId);

if (currentCard !== undefined) {
onListItemHover(currentCard);
}

return (
<div className={extraClass} onMouseOver={onPointingCardMouseOver}>
{offers.map((offer) => <Card key={offer.id} optionCard={optionCard.CITIES_CARD} offer={offer} />)}
<div className={extraClass}>
{offers.map((offer) => <Card key={offer.id} optionCard={OptionCard.CITIES_CARD} offer={offer} handelPointCardMouseOver={handelPointingCardMouseOver} />)}
</div>
);
}
15 changes: 15 additions & 0 deletions src/components/list-location.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import Location from './location';
import { MouseEvent } from 'react';

type ListLocation = {
listLocations: string[];
handleCurrentCityClick: (evt: MouseEvent<HTMLSpanElement>) => void;
}

export default function ListLocation({ listLocations, handleCurrentCityClick }: ListLocation) {
return (
<ul className="locations__list tabs__list" onClick={handleCurrentCityClick}>
{listLocations.map((location) => <Location key={location} city={location} />)}
</ul>
);
}
14 changes: 14 additions & 0 deletions src/components/location.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
type LocationProps = {
city: string;
}

export default function Location({ city }: LocationProps) {
return (
<li className="locations__item">
<a className="locations__item-link tabs__item" href="#">
<span>{city}</span>
</a>
</li>
);
}

19 changes: 13 additions & 6 deletions src/components/map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@
import { URL_MARKER_DEFAULT, URL_MARKER_CURRENT } from '../const';
import { City } from '../types/city';
import useMap from '../hooks/useMap';
import { OfferPreviews } from '../types/offer-preview';
import { MapSize } from '../const';

type MapProps = {
city: City;
offers: Offer[];
selectedOffer: Offer | undefined;
selectedOffer: OfferPreviews | null;
};

const defaultCustomIcon = leaflet.icon({
Expand All @@ -26,30 +28,35 @@

export default function Map(props: MapProps): JSX.Element {
const { city, offers, selectedOffer } = props;

console.log(city);

Check failure on line 31 in src/components/map.tsx

View workflow job for this annotation

GitHub Actions / Check

Unexpected console statement
const mapRef = useRef(null);
const map = useMap(mapRef, city);

useEffect(() => {
if (map) {
const markerLayer = leaflet.layerGroup().addTo(map);
offers.forEach((offer) => {
leaflet.marker({
lat: offer.location.latitude,
lng: offer.location.longitude
}, {
icon: (selectedOffer !== undefined && offer.title === selectedOffer.title)
icon: (selectedOffer !== null && offer.title === selectedOffer.title)
? currentCustomIcon
: defaultCustomIcon,
})
.addTo(map);
.addTo(markerLayer);
});
return () => {
map.removeLayer(markerLayer);
mapRef.current = null;
};
}
}, [map, offers, selectedOffer]);
}, [map, offers, selectedOffer, city]);

return (
<div
ref={mapRef}
style={{ width: '100%', height: '100%' }}
style={{ width: MapSize.WIDTH, height: MapSize.HEIGHT }}
>

</div>
Expand Down
10 changes: 8 additions & 2 deletions src/const.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const AuthorizationStatus = {
NO_AUTH: false,
};

const optionCard = {
const OptionCard = {
CITIES_CARD: {
classCard: 'cities__card',
width: '260',
Expand All @@ -23,6 +23,12 @@ const optionCard = {
}
};

const MapSize = {
WIDTH: '100%',
HEIGHT: '100%',
};


const OptionListCard = {
FAVORITES_CARD: 'near-places__list places__list',
CITIES_CARD: 'cities__places-list places__list tabs__content',
Expand All @@ -35,4 +41,4 @@ const URL_MARKER_CURRENT = '../markup/img/pin-active.svg';

const CountStar: number = 5;

export { CountStar, AppRoute, AuthorizationStatus as authorizationStatus, optionCard, URL_MARKER_DEFAULT, URL_MARKER_CURRENT, OptionListCard };
export { CountStar, AppRoute, AuthorizationStatus as authorizationStatus, OptionCard, URL_MARKER_DEFAULT, URL_MARKER_CURRENT, OptionListCard, MapSize };
9 changes: 9 additions & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { TypedUseSelectorHook, useDispatch, useSelector } from 'react-redux';
import type { State, AppDispatch } from '../types/state';

const useAppDispatch = () => useDispatch<AppDispatch>();

const useAppSelector: TypedUseSelectorHook<State> = useSelector;

export { useAppDispatch, useAppSelector };

9 changes: 6 additions & 3 deletions src/hooks/useMap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,10 @@
): Map | null {
const [map, setMap] = useState<Map | null>(null);
const isRenderedRef = useRef<boolean>(false);

console.log('1 условие:', isRenderedRef.current, '2 условие: ', mapRef.current);

Check failure on line 11 in src/hooks/useMap.tsx

View workflow job for this annotation

GitHub Actions / Check

Unexpected console statement
useEffect(() => {
if (mapRef.current !== null && !isRenderedRef.current) {
console.log('rfhnf', city);

Check failure on line 14 in src/hooks/useMap.tsx

View workflow job for this annotation

GitHub Actions / Check

Unexpected console statement
const instance = new Map(mapRef.current, {
center: {
lat: city.location.latitude,
Expand All @@ -28,10 +29,12 @@
);

instance.addLayer(layer);

setMap(instance);
}
isRenderedRef.current = true;

return () => {
isRenderedRef.current = true;
};
}, [mapRef, city]);

return map;
Expand Down
14 changes: 9 additions & 5 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,21 @@
import { BrowserRouter } from 'react-router-dom';
import { HelmetProvider } from 'react-helmet-async';
import { offers } from './mocks/offers';
import { Provider } from 'react-redux';
import { store } from './store';

const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);

root.render(
<React.StrictMode>
<HelmetProvider>
<BrowserRouter>
<App offers={offers} />
</BrowserRouter>
</HelmetProvider>
<Provider store={store}>
<HelmetProvider>
<BrowserRouter>
<App offers={offers} />

Check failure on line 19 in src/index.tsx

View workflow job for this annotation

GitHub Actions / build

Type '{ offers: Offer[]; }' is not assignable to type 'IntrinsicAttributes'.
</BrowserRouter>
</HelmetProvider>
</Provider>
</React.StrictMode>
);
1 change: 1 addition & 0 deletions src/mocks/locations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export const locations = ['Paris', 'Cologne', 'Brussels', 'Amsterdam', 'Hamburg', 'Dusseldorf',];
13 changes: 6 additions & 7 deletions src/pages/favorite-page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,15 @@ import Container from '../components/container';
import Card from '../components/card';
import FavoriteItems from '../components/favorite-items';
import { Helmet } from 'react-helmet-async';
import { Offer } from '../types/offer';
import { optionCard } from '../const';
import { OptionCard } from '../const';
import FavoritesEmpty from '../components/favorites-empty';
import { getFavoritesByLocation } from '../utils/utils';
import { useAppSelector } from '../hooks';

type TOfferPageProps = {
offers: Offer[];
}

export default function FavoritePage({ offers }: TOfferPageProps) {
export default function FavoritePage() {
const offers = useAppSelector((state) => state.offers);

const favorites = getFavoritesByLocation(offers);
return (
<Container mainClass='favorites'>
Expand All @@ -26,7 +25,7 @@ export default function FavoritePage({ offers }: TOfferPageProps) {
<ul className="favorites__list">
{Object.entries(favorites).map(([location, gropedFavorites]) => (
<FavoriteItems key={location} city={location}>
{gropedFavorites.map((favorite) => <Card key={favorite.id} optionCard={optionCard.FAVORITES_CARD} offer={favorite} />)}
{gropedFavorites.map((favorite) => <Card key={favorite.id} optionCard={OptionCard.FAVORITES_CARD} offer={favorite} />)}
</FavoriteItems>
)
)}
Expand Down
Loading
Loading