Skip to content

Commit

Permalink
Merge pull request #7 from fed1v/module6-task1
Browse files Browse the repository at this point in the history
  • Loading branch information
keksobot authored Nov 15, 2024
2 parents 68b6e0f + ddb15b3 commit 07b66e5
Show file tree
Hide file tree
Showing 15 changed files with 344 additions and 84 deletions.
11 changes: 9 additions & 2 deletions src/components/app/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,27 @@ import {AppRoute, AuthorizationStatus} from '../../consts.ts';
import {PrivateRoute} from '../private-route/private-route.tsx';
import {FavoritesScreen} from '../../pages/favorites-screen/favorites-screen.tsx';
import {Offer} from '../../types/offer.ts';
import {fillOffersList} from '../../store/action.ts';
import {useAppDispatch} from '../../hooks';
import {OFFERS} from '../../mocks/offers.ts';

type AppScreenProps = {
offers: Offer[];
cityNames: string[];
};

export function App({offers}: AppScreenProps) {
export function App({offers, cityNames}: AppScreenProps) {
const dispatch = useAppDispatch();
dispatch(fillOffersList({offers: OFFERS}));

return (
<BrowserRouter>
<Routes>
<Route
path={AppRoute.Main}
element={
<MainScreen
offers={offers}
cityNames={cityNames}
/>
}
/>
Expand Down
26 changes: 26 additions & 0 deletions src/components/cities-list/cities-list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import {CityItem} from './city-item.tsx';

type CitiesListProps = {
cityNames: string[];
onCityClick: (city: string) => void;
}

export function CitiesList({cityNames, onCityClick}: CitiesListProps) {

return (
<section className="locations container">
<ul className="locations__list tabs__list">
{
cityNames
.map((cityName) => (
<CityItem
key={cityName}
name={cityName}
onCityClick={onCityClick}
/>
))
}
</ul>
</section>
);
}
19 changes: 19 additions & 0 deletions src/components/cities-list/city-item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
type CityItemProps = {
name: string;
onCityClick: (city: string) => void;
}

export function CityItem({name, onCityClick}: CityItemProps) {
return (
<li
className="locations__item"
onClick={() => {
onCityClick(name);
}}
>
<a className="locations__item-link tabs__item" href="#">
<span>{name}</span>
</a>
</li>
);
}
2 changes: 1 addition & 1 deletion src/components/map/map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import leaflet from 'leaflet';
import 'leaflet/dist/leaflet.css';
import {Offer} from '../../types/offer.ts';
import {useEffect, useRef} from 'react';
import {useMap} from './use-map.ts';
import {useMap} from '../../hooks/use-map.ts';
import {Nullable} from 'vitest';
import {City} from '../../types/city.ts';

Expand Down
36 changes: 0 additions & 36 deletions src/components/map/use-map.ts

This file was deleted.

2 changes: 2 additions & 0 deletions src/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ export enum PlaceCardType{
City,
Near
}

export const CITY_NAMES = ['Paris', 'Cologne', 'Brussels', 'Amsterdam', 'Hamburg', 'Dusseldorf'];
7 changes: 7 additions & 0 deletions src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import {TypedUseSelectorHook, useDispatch, useSelector} from 'react-redux';
import {AppDispatch, State} from '../types/state.ts';


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

export const useAppSelector: TypedUseSelectorHook<State> = useSelector;
46 changes: 46 additions & 0 deletions src/hooks/use-map.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import {MutableRefObject, useEffect, useRef, useState} from 'react';
import {Nullable} from 'vitest';
import leaflet from 'leaflet';
import {City} from '../types/city.ts';

export function useMap(mapRef: MutableRefObject<HTMLElement | null>, city: City) {
const [map, setMap] = useState<Nullable<leaflet.Map>>(null);
const isRenderedRef = useRef(false);

useEffect(
() => {
if (mapRef.current !== null) {
if (!isRenderedRef.current) {
const instance = leaflet.map(mapRef.current, {
center: {
lat: city.location.latitude,
lng: city.location.longitude
},
zoom: city.location.zoom
});

leaflet
.tileLayer(
'https://{s}.basemaps.cartocdn.com/rastertiles/voyager/{z}/{x}/{y}{r}.png',
{
attribution: '&copy; <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors &copy; <a href="https://carto.com/attributions">CARTO</a>',
},
)
.addTo(instance);

setMap(instance);
isRenderedRef.current = true;
} else {
map?.setView(
{
lat: city.location.latitude,
lng: city.location.longitude
},
city.location.zoom
);
}
}
}, [mapRef, city]);

Check warning on line 43 in src/hooks/use-map.ts

View workflow job for this annotation

GitHub Actions / Check

React Hook useEffect has a missing dependency: 'map'. Either include it or remove the dependency array

return map;
}
13 changes: 10 additions & 3 deletions src/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@ import React from 'react';
import ReactDOM from 'react-dom/client';
import {App} from './components/app/app.tsx';
import {OFFERS} from './mocks/offers.ts';
import {Provider} from 'react-redux';
import {store} from './store';
import {CITY_NAMES} from './consts.ts';

export const Setting = {
Offers: OFFERS,
CityNames: CITY_NAMES
} as const;

const root = ReactDOM.createRoot(
Expand All @@ -13,8 +17,11 @@ const root = ReactDOM.createRoot(

root.render(
<React.StrictMode>
<App
offers={Setting.Offers}
/>
<Provider store={store}>
<App
offers={Setting.Offers}
cityNames={Setting.CityNames}
/>
</Provider>
</React.StrictMode>
);
167 changes: 166 additions & 1 deletion src/mocks/offers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,5 +95,170 @@ export const OFFERS: Offer[] = [
'isPremium': true,
'rating': 5,
'previewImage': './img/amsterdam.jpg'
}
},

{
'id': '0eb825a8-a18f-4da6-8db9-704a26508c7b',
'title': 'The Pondhouse - A Magical Place',
'type': 'house',
'price': 661,
'previewImage': 'https://14.design.htmlacademy.pro/static/hotel/4.jpg',
'city': {
'name': 'Paris',
'location': {
'latitude': 48.85661,
'longitude': 2.351499,
'zoom': 13
}
},
'location': {
'latitude': 48.86861,
'longitude': 2.342499,
'zoom': 16
},
'isFavorite': false,
'isPremium': false,
'rating': 4.7
},

{
'id': 'f0d0f0b0-3a54-4ab5-9690-16c62136628f',
'title': 'The Joshua Tree House',
'type': 'house',
'price': 958,
'previewImage': 'https://14.design.htmlacademy.pro/static/hotel/4.jpg',
'city': {
'name': 'Paris',
'location': {
'latitude': 48.85661,
'longitude': 2.351499,
'zoom': 13
}
},
'location': {
'latitude': 48.85861,
'longitude': 2.330499,
'zoom': 16
},
'isFavorite': false,
'isPremium': true,
'rating': 4.5
},

{
'id': '876f1446-1ef4-4c7a-9683-731b6b8a084a',
'title': 'Amazing and Extremely Central Flat',
'type': 'hotel',
'price': 168,
'previewImage': 'https://14.design.htmlacademy.pro/static/hotel/10.jpg',
'city': {
'name': 'Cologne',
'location': {
'latitude': 50.938361,
'longitude': 6.959974,
'zoom': 13
}
},
'location': {
'latitude': 50.950361,
'longitude': 6.961974,
'zoom': 16
},
'isFavorite': false,
'isPremium': false,
'rating': 2.6
},
{
'id': '7b079972-abcc-4cfe-9bb4-c388a14cc775',
'title': 'The Joshua Tree House',
'type': 'hotel',
'price': 383,
'previewImage': 'https://14.design.htmlacademy.pro/static/hotel/6.jpg',
'city': {
'name': 'Cologne',
'location': {
'latitude': 50.938361,
'longitude': 6.959974,
'zoom': 13
}
},
'location': {
'latitude': 50.932361,
'longitude': 6.937974,
'zoom': 16
},
'isFavorite': false,
'isPremium': true,
'rating': 3
},

{
'id': '5196b487-e57f-41d5-b8be-7d655a00c1bf',
'title': 'Wood and stone place',
'type': 'hotel',
'price': 240,
'previewImage': 'https://14.design.htmlacademy.pro/static/hotel/6.jpg',
'city': {
'name': 'Brussels',
'location': {
'latitude': 50.846557,
'longitude': 4.351697,
'zoom': 13
}
},
'location': {
'latitude': 50.854557,
'longitude': 4.364697,
'zoom': 16
},
'isFavorite': false,
'isPremium': false,
'rating': 4.9
},
{
'id': '073f58fc-02ee-4129-ad61-7dfb0dff89f5',
'title': 'House in countryside',
'type': 'hotel',
'price': 265,
'previewImage': 'https://14.design.htmlacademy.pro/static/hotel/10.jpg',
'city': {
'name': 'Hamburg',
'location': {
'latitude': 53.550341,
'longitude': 10.000654,
'zoom': 13
}
},
'location': {
'latitude': 53.528341,
'longitude': 10.018654,
'zoom': 16
},
'isFavorite': false,
'isPremium': true,
'rating': 3.2
},
{
'id': '6f496522-722b-43be-b9ba-78075861a892',
'title': 'Canal View Prinsengracht',
'type': 'apartment',
'price': 464,
'previewImage': 'https://14.design.htmlacademy.pro/static/hotel/1.jpg',
'city': {
'name': 'Dusseldorf',
'location': {
'latitude': 51.225402,
'longitude': 6.776314,
'zoom': 13
}
},
'location': {
'latitude': 51.236402,
'longitude': 6.784314,
'zoom': 16
},
'isFavorite': false,
'isPremium': true,
'rating': 2.9
},
];
Loading

0 comments on commit 07b66e5

Please sign in to comment.