Skip to content
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
4 changes: 2 additions & 2 deletions src/components/app/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ export default function App() {
const authorizationStatus = useAppSelector(getAuthorizationStatus);
const isLoadingOffers = useAppSelector(getIsOffersLoadingStatus);
const dispatch = useAppDispatch();
const favoritesOffers = useAppSelector(getFavoritesOffers);
const favoriteOffers = useAppSelector(getFavoritesOffers);
const isFavoritesLoaded = useAppSelector(getIsFavoritesLoaded);

useEffect(() => {
Expand All @@ -46,7 +46,7 @@ export default function App() {
return <Loader />;
}

const favoritePlacesCount = favoritesOffers.length;
const favoritePlacesCount = favoriteOffers.length;

return (
<HistoryRouter history={browserHistory}>
Expand Down
12 changes: 6 additions & 6 deletions src/components/favorites/favorites-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,27 @@ import { OfferForCardType } from '../../types/offer';
import {FavoritesListItem} from './favorites-list-item';

export type FavoritesListProps = {
offersCard: OfferForCardType[];
offerCards: OfferForCardType[];
};

export default function FavoritesList({offersCard}: FavoritesListProps): JSX.Element {
export default function FavoritesList({offerCards}: FavoritesListProps): JSX.Element {
const dispatch = useAppDispatch();

const handleFavoriteClick = (data: {id: string; status: boolean}) => {
dispatch(toggleFavoriteOffer(data));
};

const currentCitys = new Set(
offersCard
.map((offer) => (offer.isFavorite === true ? offer.city.name : ''))
offerCards
.map((offer) => (offer.city.name))
.filter(Boolean),
);

return (
<ul className="favorites__list">
{[...currentCitys].map((city) => {
const currentOffersOfCity = offersCard.filter(
(offer) => offer.isFavorite === true && offer.city.name === city,
const currentOffersOfCity = offerCards.filter(
(offer) => offer.city.name === city,
);
return (
<FavoritesListItem
Expand Down
11 changes: 7 additions & 4 deletions src/components/footer.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { Link } from 'react-router-dom';
import { AppRoute } from '../const';
import { memo } from 'react';

export default function Footer(): JSX.Element {
return (
export const Footer = memo(
(): JSX.Element => (
<footer className="footer">
<Link className="footer__logo-link" to={AppRoute.Main}>
<img
Expand All @@ -14,5 +15,7 @@ export default function Footer(): JSX.Element {
/>
</Link>
</footer>
);
}
),
);

Footer.displayName = 'Footer';
2 changes: 1 addition & 1 deletion src/components/layout-tools.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Outlet } from 'react-router-dom';
import Footer from './footer';
import {Footer} from './footer';

export default function LayoutTools() {
return (
Expand Down
9 changes: 9 additions & 0 deletions src/components/main/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { getWidthForRating } from '../../utils';
import { useAppSelector } from '../../hooks';
import { getAuthorizationStatus } from '../../store/user-process/selectors';
import { memo } from 'react';
import { getIsFavoritesLoading } from '../../store/offers/selectors';

export type CardProps = {
offer: OfferForCardType;
Expand All @@ -18,8 +19,16 @@ export const Card = memo(({ offer, onClick, onHover, className }: CardProps): JS
const {id, title, isFavorite, isPremium, type } = offer;
const auth = useAppSelector(getAuthorizationStatus);
const navigate = useNavigate();
const isFavoritesLoading = useAppSelector(getIsFavoritesLoading);

const handleFavoriteClick = () => {
if(isFavoritesLoading) {
return;
}
if(auth === AuthorizationStatus.Unknown) {
return;

}
if(auth === AuthorizationStatus.Auth) {
onClick({id, status: !isFavorite});
} else {
Expand Down
6 changes: 3 additions & 3 deletions src/pages/favorites/favorite-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import Favorites from './favorites';
import FavoritesEmpty from './favorites-empty';

export const FavoriteSection = memo(() => {
const favoritesOffers = useAppSelector(getFavoritesOffers);
const favoriteOffers = useAppSelector(getFavoritesOffers);

const isFavoriteOffers: boolean = favoritesOffers.length > 0;
const isFavoriteOffers: boolean = favoriteOffers.length > 0;
return (
<>
{isFavoriteOffers && <Favorites offersCard={favoritesOffers} />}
{isFavoriteOffers && <Favorites offerCards={favoriteOffers} />}
{!isFavoriteOffers && <FavoritesEmpty />}
</>
);
Expand Down
6 changes: 3 additions & 3 deletions src/pages/favorites/favorites.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@ import FavoritesList from '../../components/favorites/favorites-list';
import { OfferForCardType } from '../../types/offer';

export type FavoritesProps = {
offersCard: OfferForCardType[];
offerCards: OfferForCardType[];
};

export default function Favorites({offersCard}: FavoritesProps): JSX.Element {
export default function Favorites({offerCards}: FavoritesProps): JSX.Element {
return (
<main className="page__main page__main--favorites">
<div className="page__favorites-container container">
<section className="favorites">
<h1 className="favorites__title">Saved listing</h1>
<FavoritesList offersCard={offersCard} />
<FavoritesList offerCards={offerCards} />
</section>
</div>
</main>
Expand Down
9 changes: 8 additions & 1 deletion src/pages/login.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,24 @@ import { getAuthorizationStatus } from '../store/user-process/selectors';
import { AppRoute, AuthorizationStatus } from '../const';

export default function Login(): JSX.Element {
const pattern = '^(?=.*[a-zA-Z])(?=.*[0-9])[a-zA-Z0-9]+$';
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');

const dispatch = useAppDispatch();
const city = getRandomCity();
const authStatus = useAppSelector(getAuthorizationStatus);
const navigate = useNavigate();
const [isFormDisabled, setIsFormDisabled] = useState(false);

const handleSubmit = (evt: FormEvent<HTMLFormElement>) => {
evt.preventDefault();

setIsFormDisabled(true);
dispatch(loginUser({
login: email,
password:password
}));
setIsFormDisabled(false);
};

useEffect(() => {
Expand Down Expand Up @@ -74,6 +77,7 @@ export default function Login(): JSX.Element {
placeholder="Email"
required
value={email}
disabled={isFormDisabled}
onChange={(evt) => setEmail(evt.target.value)}
/>
</div>
Expand All @@ -86,12 +90,15 @@ export default function Login(): JSX.Element {
placeholder="Password"
required
value={password}
disabled={isFormDisabled}
pattern={pattern}
onChange={(evt) => setPassword(evt.target.value)}
/>
</div>
<button
className="login__submit form__submit button"
type="submit"
disabled={isFormDisabled}
>
Sign in
</button>
Expand Down
2 changes: 1 addition & 1 deletion src/store/api-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ OfferFullType,
extra: AxiosInstance;
}
>('offer/toggleOffer', async ({id, status}, {extra: api}) => {
const { data } = await api.post<OfferFullType>(`${APIRoute.Favorites}/${id}/${status ? 1 : 0}`, status);
const { data } = await api.post<OfferFullType>(`${APIRoute.Favorites}/${id}/${status ? 1 : 0}`);
return data;
});

Expand Down
24 changes: 16 additions & 8 deletions src/store/offers/offers-process.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export const initialState: OffersProcessType = {
isOffersLoadingStatus: false,
hasError: false,
isFavoritesLoading: false,
isFavoritesLoaded: false,
};

export const offersProcess = createSlice({
Expand All @@ -32,6 +33,8 @@ export const offersProcess = createSlice({
clearFavoriteOffers:(state) => {
state.favoritesOffers = [];
state.isFavoritesLoading = false;
state.isFavoritesLoaded = false;

}
},
extraReducers(builder) {
Expand All @@ -49,32 +52,37 @@ export const offersProcess = createSlice({
state.hasError = true;
})
.addCase(toggleFavoriteOffer.fulfilled, (state, action) => {
const updateOffer = action.payload;
const currentOffer = state.offers.find((offer) => offer.id === updateOffer.id);
const updatedOffer = action.payload;
const currentOffer = state.offers.find((offer) => offer.id === updatedOffer.id);

if(currentOffer) {
currentOffer.isFavorite = updateOffer.isFavorite;
currentOffer.isFavorite = updatedOffer.isFavorite;

if(updateOffer.isFavorite) {
const checkOffer = state.favoritesOffers.some((offer) => offer.id === updateOffer.id);
if(updatedOffer.isFavorite) {
const checkOffer = state.favoritesOffers.some((offer) => offer.id === updatedOffer.id);
if(!checkOffer) {
state.favoritesOffers.push(currentOffer);
}
}else {
state.favoritesOffers = state.favoritesOffers.filter((offer) => offer.id !== updateOffer.id);
}
} else {
state.favoritesOffers = state.favoritesOffers.filter((offer) => offer.id !== updatedOffer.id);
}
})
.addCase(fetchFavoriteOfferActions.fulfilled, (state, action) => {
state.favoritesOffers = action.payload;
state.isFavoritesLoading = true;
state.isFavoritesLoading = false;
state.isFavoritesLoaded = true;

state.offers.forEach((offer) => {
offer.isFavorite = state.favoritesOffers.some((favorite) => favorite.id === offer.id);
});
})
.addCase(fetchFavoriteOfferActions.pending, (state) => {
state.isFavoritesLoading = true;
})
.addCase(fetchFavoriteOfferActions.rejected, (state) => {
state.isFavoritesLoading = false;
state.isFavoritesLoaded = false;
});
},
});
Expand Down
4 changes: 3 additions & 1 deletion src/store/offers/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,6 @@ export const getActiveSortType = (state: State): SortType => state[NameSpace.Off
export const getFavoritesOffers = (state: State): OfferForCardType[] => state[NameSpace.Offers].favoritesOffers;
export const getIsOffersLoadingStatus = (state: State): boolean => state[NameSpace.Offers].isOffersLoadingStatus;
export const getOffersError = (state: State): boolean => state[NameSpace.Offers].hasError;
export const getIsFavoritesLoaded = (state: State): boolean => state[NameSpace.Offers].isFavoritesLoading;
export const getIsFavoritesLoading = (state: State): boolean => state[NameSpace.Offers].isFavoritesLoading;
export const getIsFavoritesLoaded = (state: State): boolean => state[NameSpace.Offers].isFavoritesLoaded;

1 change: 1 addition & 0 deletions src/types/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ export type OffersProcessType = {
isOffersLoadingStatus: boolean;
hasError: boolean;
isFavoritesLoading: boolean;
isFavoritesLoaded: boolean;
}

export type OfferProcessType = {
Expand Down
Loading