Skip to content

Commit

Permalink
Task 7.3 done
Browse files Browse the repository at this point in the history
  • Loading branch information
fed1v committed Dec 13, 2024
1 parent f72f452 commit 0db5fd6
Show file tree
Hide file tree
Showing 11 changed files with 184 additions and 78 deletions.
36 changes: 32 additions & 4 deletions src/components/comment-form/comment-form.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,44 @@
import {ChangeEvent, useState} from 'react';
import {ChangeEvent, FormEvent, useState} from 'react';
import {useAppDispatch} from '../../hooks';
import {sendCommentAction} from '../../store/api-actions.ts';

export function CommentForm() {
type CommentFormProps = {
offerId: string;
}

export function CommentForm({offerId}: CommentFormProps) {
const [formData, setFormData] = useState({rating: 0, review: ''});

const dispatch = useAppDispatch();

function handleOnChangeForm(event: ChangeEvent<HTMLTextAreaElement | HTMLInputElement>) {
const {name, value} = event.currentTarget;
setFormData({...formData, [name]: value});
}

function handleOnSubmit(event: FormEvent) {
event.preventDefault();

if (!formData.rating || !formData.review) {
return;
}

const comment = {
offerId: offerId,
comment: formData.review,
rating: formData.rating,
};

dispatch(sendCommentAction(comment));
}

return (
<form className="reviews__form form" action="#" method="post">
<form
className="reviews__form form"
action="#"
method="post"
onSubmit={handleOnSubmit}
>
<label className="reviews__label form__label" htmlFor="review">
Your review
</label>
Expand Down Expand Up @@ -120,7 +149,6 @@ export function CommentForm() {
<button
className="reviews__submit form__submit button"
type="submit"
disabled
>
Submit
</button>
Expand Down
3 changes: 2 additions & 1 deletion src/components/map/map.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import {useEffect, useRef} from 'react';
import {useMap} from '../../hooks/use-map.ts';
import {Nullable} from 'vitest';
import {City} from '../../types/city.ts';
import {OfferDetails} from '../../types/offer-details.ts';

type MapProps = {
city: City;
activeOffer: Nullable<Offer>;
activeOffer: Nullable<OfferDetails>;
offers: Offer[];
className: string;
};
Expand Down
4 changes: 2 additions & 2 deletions src/components/reviews/review-item.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {Review} from '../../types/review.ts';
import {Comment} from '../../types/comment.ts';

type ReviewItemProps = {
review: Review;
review: Comment;
}

export function ReviewItem({review}: ReviewItemProps) {
Expand Down
4 changes: 2 additions & 2 deletions src/components/reviews/reviews-list.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {Review} from '../../types/review.ts';
import {Comment} from '../../types/comment.ts';
import {ReviewItem} from './review-item.tsx';

type ReviewsListProps = {
reviews: Review[];
reviews: Comment[];
}

export function ReviewsList({reviews}: ReviewsListProps) {
Expand Down
6 changes: 5 additions & 1 deletion src/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ export enum AppRoute {
Main = '/',
Login = '/login',
Favorites = '/favorites',
Offer = '/offer/:id'
Offer = '/offer/:id',
NotFound = '/not-found'
}

export enum AuthorizationStatus {
Expand All @@ -29,7 +30,10 @@ export const TIMEOUT_SHOW_ERROR = 2000;

export enum APIRoute {
Offers = '/offers',
NearbyOffers = '/offers/:id/nearby',
Favorite = '/favorite',
Login = '/login',
Logout = '/logout',
OfferDetails = '/offers/:id',
OfferComments = '/comments/:id',
}
48 changes: 0 additions & 48 deletions src/mocks/reviews.ts

This file was deleted.

53 changes: 37 additions & 16 deletions src/pages/offer-screen/offer-screen.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,46 @@
import {CommentForm} from '../../components/comment-form/comment-form.tsx';
import {useParams} from 'react-router-dom';
import {OFFERS_DETAILS} from '../../mocks/offers-details.ts';
import {ReviewsList} from '../../components/reviews/reviews-list.tsx';
import {REVIEWS} from '../../mocks/reviews.ts';
import {Map} from '../../components/map/map.tsx';
import {Header} from '../../components/header/header.tsx';
import {NearPlaceCardList} from '../../components/place-card/place-card-list.tsx';
import {useAppSelector} from '../../hooks';
import {useAppDispatch, useAppSelector} from '../../hooks';
import {useEffect} from 'react';
import {fetchOfferDetailsAction} from '../../store/api-actions.ts';
import {AuthorizationStatus} from '../../consts.ts';


const reviews = REVIEWS;

export function OfferScreen() {

const offers = useAppSelector((state) => state.offers);

const id = useParams().id;
const offerDetails = OFFERS_DETAILS.find((details) => details.id === id);

const dispatch = useAppDispatch();

const authorizationStatus = useAppSelector((state) => state.authorizationStatus);
const offerDetails = useAppSelector((state) => state.currentOfferDetails);
const comments = useAppSelector((state) => state.comments);
let nearbyOffers = useAppSelector((state) => state.nearbyOffers);

if (offerDetails) {
const offer = {
...offerDetails,
previewImage: offerDetails.images[0]
};

nearbyOffers = nearbyOffers.concat(offer);
}

useEffect(() => {
if (id) {
dispatch(fetchOfferDetailsAction(id));
}
}, [dispatch, id]);

if (!offerDetails) {
return;
}

const activeOffer = offers.find((offer) => offer.id === id);

const city = offerDetails.city;
const nearbyOffers = offers.filter((details) => details.id !== id);

return (

Expand Down Expand Up @@ -141,21 +156,27 @@ export function OfferScreen() {

<section className="offer__reviews reviews">
<h2 className="reviews__title">
Reviews · <span className="reviews__amount">{reviews.length}</span>
Reviews · <span className="reviews__amount">{comments.length}</span>
</h2>

<ReviewsList
reviews={reviews}
reviews={comments}
/>
<CommentForm/>
{
authorizationStatus === AuthorizationStatus.Auth
&&
<CommentForm
offerId={id ?? ''}
/>
}
</section>
</div>
</div>

<Map
city={city}
activeOffer={activeOffer}
offers={offers}
activeOffer={offerDetails}
offers={nearbyOffers}
className="offer__map map"
/>

Expand Down
9 changes: 9 additions & 0 deletions src/store/action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import {createAction} from '@reduxjs/toolkit';
import {Offer, Offers} from '../types/offer.ts';
import {AppRoute, AuthorizationStatus, Sorting} from '../consts.ts';
import {UserData} from '../types/user-data.ts';
import {Comment, Comments} from '../types/comment.ts';
import {OfferDetails} from '../types/offer-details.ts';

export const selectCity = createAction<{ city: string }>('selectCity');

Expand All @@ -23,3 +25,10 @@ export const setError = createAction<string | null>('app/setError');

export const redirectToRoute = createAction<AppRoute>('app/redirectToRoute');

export const loadOfferComments = createAction<Comments>('data/loadOfferComments');

export const loadNearbyOffers = createAction<Offers>('data/loadNearbyOffers');

export const loadOfferDetails = createAction<OfferDetails>('data/loadOfferDetails');

export const sendComment = createAction<Comment>('data/sendComment');
64 changes: 64 additions & 0 deletions src/store/api-actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,13 @@ import {APIRoute, AppRoute, AuthorizationStatus, TIMEOUT_SHOW_ERROR} from '../co
import {Offers} from '../types/offer.ts';
import {
loadFavoriteOffers,
loadNearbyOffers,
loadOfferComments,
loadOfferDetails,
loadOffers,
redirectToRoute,
requireAuthorization,
sendComment,
setError,
setOffersDataLoadingStatus,
updateUserData
Expand All @@ -16,6 +20,8 @@ import {AuthData} from '../types/auth-data.ts';
import {UserData} from '../types/user-data.ts';
import {dropToken, saveToken} from '../api/token.ts';
import {store} from './index.ts';
import {Comment, Comments} from '../types/comment.ts';
import {OfferDetails} from '../types/offer-details.ts';


export const clearErrorAction = createAsyncThunk(
Expand Down Expand Up @@ -104,4 +110,62 @@ export const logoutAction = createAsyncThunk<void, undefined, {
},
);

export const fetchOfferCommentsAction = createAsyncThunk<void, string, {
dispatch: AppDispatch;
state: State;
extra: AxiosInstance;
}>(
'data/loadOfferComments',
async (id, {dispatch, extra: api}) => {
const url = APIRoute.OfferComments.replace(':id', id);
const {data} = await api.get<Comments>(url);
dispatch(loadOfferComments(data));
},
);


export const fetchNearbyOffersAction = createAsyncThunk<void, string, {
dispatch: AppDispatch;
state: State;
extra: AxiosInstance;
}>(
'data/loadNearbyOffers',
async (id, {dispatch, extra: api}) => {
const url = APIRoute.NearbyOffers.replace(':id', id);
const {data} = await api.get<Offers>(url);
dispatch(loadNearbyOffers(data));
},
);

export const fetchOfferDetailsAction = createAsyncThunk<void, string, {
dispatch: AppDispatch;
state: State;
extra: AxiosInstance;
}>(
'data/loadOfferDetails',
async (id, {dispatch, extra: api}) => {
const url = APIRoute.OfferDetails.replace(':id', id);

try {
const {data} = await api.get<OfferDetails>(url);
dispatch(loadOfferDetails(data));
dispatch(fetchOfferCommentsAction(id));
dispatch(fetchNearbyOffersAction(id));
} catch (e) {
dispatch(redirectToRoute(AppRoute.NotFound));
}
},
);

export const sendCommentAction = createAsyncThunk<void, { offerId: string; comment: string; rating: number }, {
dispatch: AppDispatch;
state: State;
extra: AxiosInstance;
}>(
'data/loadNearbyOffers',
async ({offerId, comment, rating}, {dispatch, extra: api}) => {
const url = APIRoute.OfferComments.replace(':id', offerId);
const commentData = (await api.post<Comment>(url, {comment: comment, rating: Number(rating)})).data;
dispatch(sendComment(commentData));
}
);
Loading

0 comments on commit 0db5fd6

Please sign in to comment.