-
diff --git a/src/components/spinner/Spinner.tsx b/src/components/spinner/Spinner.tsx
new file mode 100644
index 0000000..acaccd1
--- /dev/null
+++ b/src/components/spinner/Spinner.tsx
@@ -0,0 +1,12 @@
+interface SpinnerProps {
+ caption?: string;
+}
+
+export function Spinner({ caption }: SpinnerProps) {
+ return (
+ <>
+
+ {caption && {caption}}
+ >
+ );
+}
diff --git a/src/components/spinner/spinner.css b/src/components/spinner/spinner.css
new file mode 100644
index 0000000..ba49813
--- /dev/null
+++ b/src/components/spinner/spinner.css
@@ -0,0 +1,14 @@
+.spinner {
+ border: 4px solid rgba(0, 0, 0, 0.1);
+ border-left-color: #09f;
+ border-radius: 50%;
+ width: 50px;
+ height: 50px;
+ animation: spin 1s linear infinite;
+}
+
+@keyframes spin {
+ to {
+ transform: rotate(360deg);
+ }
+}
diff --git a/src/dataTypes/enums/api-routes.ts b/src/dataTypes/enums/api-routes.ts
new file mode 100644
index 0000000..e4f8343
--- /dev/null
+++ b/src/dataTypes/enums/api-routes.ts
@@ -0,0 +1,3 @@
+export enum ApiRoutes {
+ Offers = '/offers',
+}
diff --git a/src/index.tsx b/src/index.tsx
index e7a9153..456f533 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -1,14 +1,17 @@
import React from 'react';
import ReactDOM from 'react-dom/client';
import { App } from './components/app.tsx';
-import { offerMocks } from './mocks/offers.ts';
+import { store } from './store/store.ts';
+import { fetchOffers } from './store/actions.ts';
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement,
);
+store.dispatch(fetchOffers());
+
root.render(
- {currentOffer.isPremium && (
-
+
- Premium
+ {!currentOffer ? (
+
+ ) : (
+ <>
+
+
+
@@ -27,7 +22,7 @@ export function App({ offers }: AppProps): React.JSX.Element {
path={AppRoutes.Favorites}
element={
-
+
}
/>
diff --git a/src/components/offer/offer-card.tsx b/src/components/offer/offer-card.tsx
index af73a91..baed48e 100644
--- a/src/components/offer/offer-card.tsx
+++ b/src/components/offer/offer-card.tsx
@@ -40,7 +40,7 @@ export function OfferCard({
onMouseLeave={handleMouseLeave}
className={cn(
'place-card',
- { 'cities__card': isOnMainPage },
+ { cities__card: isOnMainPage },
{ 'near-places__card': !isOnMainPage },
)}
>
@@ -59,7 +59,7 @@ export function OfferCard({
€{price}
/ night
-
+ ({
+ location: x.location,
+ id: x.id,
+ }))}
+ selectedPoint={{
+ location: currentOffer.location,
+ id: currentOffer.id,
+ }}
/>
-
-
diff --git a/src/api/api.ts b/src/api/api.ts
new file mode 100644
index 0000000..50ee062
--- /dev/null
+++ b/src/api/api.ts
@@ -0,0 +1,13 @@
+import axios, {AxiosInstance} from 'axios';
+
+const BACKEND_URL = 'https://14.design.htmlacademy.pro/six-cities';
+const REQUEST_TIMEOUT = 5000;
+
+export const createAPI = (): AxiosInstance => {
+ const api = axios.create({
+ baseURL: BACKEND_URL,
+ timeout: REQUEST_TIMEOUT,
+ });
+
+ return api;
+};
diff --git a/src/components/app.tsx b/src/components/app.tsx
index dccd602..95ce034 100644
--- a/src/components/app.tsx
+++ b/src/components/app.tsx
@@ -7,15 +7,10 @@ import { NotFoundPage } from '../pages/not-found-page/not-found-page.tsx';
import { AuthorizationWrapper } from './authorization-wrapper.tsx';
import { AppRoutes } from '../dataTypes/enums/app-routes.ts';
import { HelmetProvider } from 'react-helmet-async';
-import { Offer } from '../dataTypes/offer.ts';
import { Provider } from 'react-redux';
import { store } from '../store/store.ts';
-interface AppProps {
- offers: Offer[];
-}
-
-export function App({ offers }: AppProps): React.JSX.Element {
+export function App(): React.JSX.Element {
return (
+ {currentOffer.isPremium && (
+
+
+
- )}
-
+ Premium
+
+ )}
+
+
+
+ {currentOffer.title}
+-
+
- + {capitalize(currentOffer.type)} + +
- + {pluralizeAndCombine('bedroom', currentOffer.bedrooms)} + +
- + Max{' '} + {pluralizeAndCombine('adult', currentOffer.maxAdults)} + +
+
+ €{currentOffer.price}
+
+ night
+
+
+
+
+
+
+ + {currentOffer.description} +
+
-
- {currentOffer.title}
--
-
- - {capitalize(currentOffer.type)} - -
- - {pluralizeAndCombine('bedroom', currentOffer.bedrooms)} - -
- - Max {pluralizeAndCombine('adult', currentOffer.maxAdults)} - -
-
- €{currentOffer.price}
-
- night
-
-
-
-
-
-
-
- - A quiet cozy and picturesque that hides behind a a river - by the unique lightness of Amsterdam. The building is - green and from 18th century. -
-- An independent House, strategically located between - Rembrand Square and National Opera, but where the bustle - of the city comes to rest in this alley flowery and - colorful. -
+ +
+
+
- + Other places in the neighbourhood +
+
+ {nearbyOffers && }
-