From 3d5829726ad4ed95bb890c40ab79a1b74af839b2 Mon Sep 17 00:00:00 2001 From: yadroRus <37119397+yadroRus@users.noreply.github.com> Date: Mon, 4 Aug 2025 16:40:17 +0300 Subject: [PATCH 1/3] =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B5=D1=85=D0=BE=D0=B4?= =?UTF-8?q?=20=D0=BD=D0=B0=20redux=20toolkit=20query?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../restaurant-comment-item-container.jsx | 24 +++++----- .../restaurant-comments.jsx | 13 ++++-- .../restaurant-tab-container.jsx | 13 ++---- src/data/redux/store.js | 6 ++- src/data/services/api/api.js | 45 +++++++++++++++++++ .../restaurant-page-layout-container.jsx | 22 ++------- src/layouts/restaurant-page-layout.jsx | 23 +++++----- src/pages/dish-page/dish-page-container.jsx | 9 ++-- .../restaurant-home-page-container.jsx | 12 ++--- .../restaurant-home-page.jsx | 10 +++-- .../restaurant-reviews-page-container.jsx | 17 ++++--- .../restaurant-reviews-page.jsx | 4 +- .../restaurants-page-container.jsx | 14 +++--- .../restaurants-page/restaurants-page.jsx | 13 ++++-- 14 files changed, 132 insertions(+), 93 deletions(-) create mode 100644 src/data/services/api/api.js diff --git a/src/components/restaurant-comment-item/restaurant-comment-item-container.jsx b/src/components/restaurant-comment-item/restaurant-comment-item-container.jsx index fb712a3..5717910 100644 --- a/src/components/restaurant-comment-item/restaurant-comment-item-container.jsx +++ b/src/components/restaurant-comment-item/restaurant-comment-item-container.jsx @@ -1,16 +1,14 @@ import RestaurantCommentItem from "./restaurant-comment-item.jsx"; -import { useSelector } from "react-redux"; -import { selectReviewById } from "../../data/entities/reviews/slice.js"; -import { selectUserById } from "../../data/entities/users/slice.js"; +import { useGetUsersQuery } from "../../data/services/api/api.js"; +import { FULFILLED } from "../../data/entities/request/sliсe.js"; -export const RestaurantCommentItemContainer = ({ commentId }) => { - const comment = useSelector((state) => selectReviewById(state, commentId)); - const user = useSelector((state) => selectUserById(state, comment.userId)); - return ( - - ); +export const RestaurantCommentItemContainer = ({ text, rating, userId }) => { + // const comment = useSelector((state) => selectReviewById(state, commentId)); + // const user = useSelector((state) => selectUserById(state, userId)); + + const { data: users, status } = useGetUsersQuery(); + const user = users?.find((u) => u.id === userId); + return status === FULFILLED ? ( + + ) : null; }; diff --git a/src/components/restaurant-comments/restaurant-comments.jsx b/src/components/restaurant-comments/restaurant-comments.jsx index 37ecadc..6948297 100644 --- a/src/components/restaurant-comments/restaurant-comments.jsx +++ b/src/components/restaurant-comments/restaurant-comments.jsx @@ -1,14 +1,19 @@ import { RestaurantCommentItemContainer } from "../restaurant-comment-item/restaurant-comment-item-container.jsx"; -export default function RestaurantComments({ commentsIds }) { - if (!commentsIds) { +export default function RestaurantComments({ reviews }) { + if (!reviews) { return null; } return ( ); diff --git a/src/components/restaurant-tab-container/restaurant-tab-container.jsx b/src/components/restaurant-tab-container/restaurant-tab-container.jsx index 47d69cc..d6e0bca 100644 --- a/src/components/restaurant-tab-container/restaurant-tab-container.jsx +++ b/src/components/restaurant-tab-container/restaurant-tab-container.jsx @@ -1,21 +1,16 @@ -import { selectRestaurantById } from "../../data/entities/restaurants/slice.js"; -import { useSelector } from "react-redux"; import { Link } from "../link/link.jsx"; import styles from "../tab/tabs.module.css"; import { MENU_PAGE, RESTAURANT_PAGE } from "../../pages/links-paths.js"; -export const RestaurantTabContainer = ({ restaurantId }) => { - const restaurant = useSelector((state) => - selectRestaurantById(state, restaurantId), - ); +export const RestaurantTabContainer = ({ restaurantId, restaurantName }) => { return ( - {restaurant.name} + {restaurantName} ); }; diff --git a/src/data/redux/store.js b/src/data/redux/store.js index 963c368..c8a1ed6 100644 --- a/src/data/redux/store.js +++ b/src/data/redux/store.js @@ -5,6 +5,7 @@ import { reviewsSlice } from "../entities/reviews/slice.js"; import { usersSlice } from "../entities/users/slice.js"; import { cartSlice } from "../entities/cart/slice.js"; import { requestSlice } from "../entities/request/sliсe.js"; +import { api } from "../services/api/api.js"; const loggerMiddleware = (store) => (next) => (action) => { console.log(action); @@ -18,8 +19,9 @@ export const store = configureStore({ [reviewsSlice.name]: reviewsSlice.reducer, [usersSlice.name]: usersSlice.reducer, [cartSlice.name]: cartSlice.reducer, - [requestSlice.name]: requestSlice.reducer + [requestSlice.name]: requestSlice.reducer, + [api.reducerPath]: api.reducer }, middleware: (getDefaultMiddlewares) => - getDefaultMiddlewares().concat(loggerMiddleware) + getDefaultMiddlewares().concat( api.middleware) }); \ No newline at end of file diff --git a/src/data/services/api/api.js b/src/data/services/api/api.js new file mode 100644 index 0000000..d37ef6f --- /dev/null +++ b/src/data/services/api/api.js @@ -0,0 +1,45 @@ +import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; + +export const api = createApi({ + reducerPath: "api", + // pollingInterval: 5000, + baseQuery: fetchBaseQuery({ + baseUrl: "http://localhost:3001/api" + }), + endpoints: (builder) => ({ + getRestaurants: builder.query({ + query: () => "/restaurants", + keepUnusedDataFor: 20 + }), + getRestaurantById: builder.query({ + query: (id) => `/restaurant/${id}`, + keepUnusedDataFor: 20 + }), + getDishes: builder.query({ + query: (restaurantId) => `/dishes?restaurantId=${restaurantId}`, + keepUnusedDataFor: 20 + }), + getDishById: builder.query({ + query: (id) => `/dish/${id}`, + keepUnusedDataFor: 20 + }), + getReviews: builder.query({ + query: (restaurantId) => `/reviews?restaurantId=${restaurantId}`, + keepUnusedDataFor: 20 + }), + getUsers: builder.query({ + query: () => `/users`, + keepUnusedDataFor: 20 + }), + }) +}); + +export const { + useGetRestaurantsQuery, + useLazyGetRestaurantsQuery, + useGetRestaurantByIdQuery, + useGetDishesQuery, + useGetDishByIdQuery, + useGetReviewsQuery, + useGetUsersQuery, +} = api; \ No newline at end of file diff --git a/src/layouts/restaurant-page-layout-container.jsx b/src/layouts/restaurant-page-layout-container.jsx index b3b7938..7c10fbc 100644 --- a/src/layouts/restaurant-page-layout-container.jsx +++ b/src/layouts/restaurant-page-layout-container.jsx @@ -1,23 +1,9 @@ -import { useSelector } from "react-redux"; -import { selectRestaurantById, selectRestaurantsIds } from "../data/entities/restaurants/slice.js"; import { RestaurantPageLayout } from "./restaurant-page-layout.jsx"; -import { useParams } from "react-router"; -import { getRestaurants } from "../data/entities/restaurants/get-restaurants.js"; -import { useRequest } from "../data/hooks/use-request.js"; -import { getRestaurant } from "../data/entities/restaurants/get-restaurant.js"; +import { useGetRestaurantsQuery } from "../data/services/api/api.js"; export const RestaurantPageLayoutContainer = () => { - const requestStatus = useRequest(getRestaurants); - const { restaurantId } = useParams(); - const restaurantRequestStatus = useRequest(getRestaurant, restaurantId); - const restaurant = useSelector((state) => - selectRestaurantById(state, restaurantId) - ); + const { data: restaurants, status: requestStatus } = useGetRestaurantsQuery(); - const restaurantsIds = useSelector(selectRestaurantsIds); - - return ; + return ; }; \ No newline at end of file diff --git a/src/layouts/restaurant-page-layout.jsx b/src/layouts/restaurant-page-layout.jsx index d6c7aa2..ad66e7b 100644 --- a/src/layouts/restaurant-page-layout.jsx +++ b/src/layouts/restaurant-page-layout.jsx @@ -1,4 +1,4 @@ -import { Outlet } from "react-router"; +import { Outlet, useParams } from "react-router"; import styles from "../components/restaurant-tabs/restaurant-tabs.module.css"; import { RestaurantTabContainer } from "../components/restaurant-tab-container/restaurant-tab-container.jsx"; import { Breadcrumbs } from "../components/breadcrumbs/breadcrumbs.jsx"; @@ -7,18 +7,20 @@ import { FULFILLED } from "../data/entities/request/sliсe.js"; import { requestText } from "../data/hooks/use-request.js"; export const RestaurantPageLayout = ({ - restaurantsIds, - restaurant, - requestStatus, - restaurantRequestStatus + restaurants, + requestStatus }) => { + const { restaurantId } = useParams(); + + const currentRestaurant = restaurants?.find((restaurant) => restaurant.id === restaurantId); + const breadcrumbs = [ { text: "Рестораны", path: RESTAURANT_PAGE }, { - text: restaurant?.name || "..." + text: currentRestaurant?.name || "..." } ]; @@ -31,14 +33,15 @@ export const RestaurantPageLayout = ({ ( <>
- {restaurantsIds.map((id) => ( + {restaurants?.map((restaurant) => ( ))}
- + )} diff --git a/src/pages/dish-page/dish-page-container.jsx b/src/pages/dish-page/dish-page-container.jsx index 542ef91..094371f 100644 --- a/src/pages/dish-page/dish-page-container.jsx +++ b/src/pages/dish-page/dish-page-container.jsx @@ -4,15 +4,14 @@ import { selectDishById } from "../../data/entities/dishes/slice.js"; import { DishPage } from "./dish-page.jsx"; import { useRequest } from "../../data/hooks/use-request.js"; import { getDish } from "../../data/entities/dishes/get-dish.js"; +import { useGetDishByIdQuery } from "../../data/services/api/api.js"; export const DishPageContainer = () => { const { dishId } = useParams(); - const requestStatus = useRequest(getDish, dishId); - const dish = useSelector((state) => selectDishById(state, dishId)); + // const requestStatus = useRequest(getDish, dishId); + // const dish = useSelector((state) => selectDishById(state, dishId)); - if (!dish) { - return null; - } + const { data: dish, status: requestStatus } = useGetDishByIdQuery(dishId); return { - const { restaurant, restaurantRequestStatus } = useOutletContext(); + + const { restaurantId } = useParams(); + + const { data: restaurant, status: restaurantRequestStatus } = useGetRestaurantByIdQuery(restaurantId); return ( ); diff --git a/src/pages/restaurant-home-page/restaurant-home-page.jsx b/src/pages/restaurant-home-page/restaurant-home-page.jsx index b05c8f0..1d0085b 100644 --- a/src/pages/restaurant-home-page/restaurant-home-page.jsx +++ b/src/pages/restaurant-home-page/restaurant-home-page.jsx @@ -1,17 +1,19 @@ import styles from "./restaurant-home-page.module.css"; import { Link } from "../../components/link/link.jsx"; -import { Outlet } from "react-router"; +import { Outlet, useOutletContext } from "react-router"; import buttonStyles from "../../components/button/button.module.css"; import { MENU_PAGE, REVIEWS_PAGE } from "../links-paths.js"; import { FULFILLED } from "../../data/entities/request/sliсe.js"; import { requestText } from "../../data/hooks/use-request.js"; export const RestaurantHomePage = ({ restaurant, restaurantRequestStatus }) => { - const { name, img } = restaurant; + + const {currentRestaurant} = useOutletContext(); + return (
- name -

{name}

+ name +

{currentRestaurant?.name}

{restaurantRequestStatus !== FULFILLED ? requestText(restaurantRequestStatus) : ( diff --git a/src/pages/restaurant-reviews-page/restaurant-reviews-page-container.jsx b/src/pages/restaurant-reviews-page/restaurant-reviews-page-container.jsx index 7ffc3ab..82620b4 100644 --- a/src/pages/restaurant-reviews-page/restaurant-reviews-page-container.jsx +++ b/src/pages/restaurant-reviews-page/restaurant-reviews-page-container.jsx @@ -1,21 +1,20 @@ import { useLoginContext } from "../../components/login-context/hooks.js"; import { RestaurantReviewsPage } from "./restaurant-reviews-page.jsx"; import { useOutletContext } from "react-router"; -import { useRequest } from "../../data/hooks/use-request.js"; -import { getReviews } from "../../data/entities/reviews/get-reviews.js"; -import { getUsers } from "../../data/entities/users/get-users.js"; -import { FULFILLED, PENDING } from "../../data/entities/request/sliсe.js"; +import { useGetReviewsQuery } from "../../data/services/api/api.js"; export const RestaurantReviewsPageContainer = () => { const { restaurant } = useOutletContext(); const { user } = useLoginContext(); - const requestStatusUser = useRequest(getUsers); - const requestStatusReviews = useRequest(getReviews, restaurant.id); - const requestStatus = requestStatusUser === FULFILLED && requestStatusReviews === FULFILLED ? - FULFILLED : PENDING; + // const requestStatusUser = useRequest(getUsers); + // const requestStatusReviews = useRequest(getReviews, restaurant.id); + // const requestStatus = requestStatusUser === FULFILLED && requestStatusReviews === FULFILLED ? + // FULFILLED : PENDING; + + const { data: restaurantReviews, status: requestStatus } = useGetReviewsQuery(restaurant.id); return ; }; \ No newline at end of file diff --git a/src/pages/restaurant-reviews-page/restaurant-reviews-page.jsx b/src/pages/restaurant-reviews-page/restaurant-reviews-page.jsx index d2e20d6..754339d 100644 --- a/src/pages/restaurant-reviews-page/restaurant-reviews-page.jsx +++ b/src/pages/restaurant-reviews-page/restaurant-reviews-page.jsx @@ -3,11 +3,11 @@ import { ReviewForm } from "../../components/review-form/review-form.jsx"; import { FULFILLED } from "../../data/entities/request/sliсe.js"; import { requestText } from "../../data/hooks/use-request.js"; -export const RestaurantReviewsPage = ({ user, reviewsIds, restaurantId, requestStatus }) => { +export const RestaurantReviewsPage = ({ user, reviews, restaurantId, requestStatus }) => { return requestStatus !== FULFILLED ? requestText(requestStatus) : ( <> - + {user.name && } ); diff --git a/src/pages/restaurants-page/restaurants-page-container.jsx b/src/pages/restaurants-page/restaurants-page-container.jsx index 39c3912..fa901fb 100644 --- a/src/pages/restaurants-page/restaurants-page-container.jsx +++ b/src/pages/restaurants-page/restaurants-page-container.jsx @@ -1,11 +1,11 @@ -import { useSelector } from "react-redux"; -import { selectRestaurantsIds } from "../../data/entities/restaurants/slice.js"; -import { getRestaurants } from "../../data/entities/restaurants/get-restaurants.js"; -import { useRequest } from "../../data/hooks/use-request.js"; import { RestaurantsPage } from "./restaurants-page.jsx"; +import { useGetRestaurantsQuery } from "../../data/services/api/api.js"; export const RestaurantsPageContainer = () => { - const requestStatus = useRequest(getRestaurants); - const restaurantsIds = useSelector(selectRestaurantsIds); - return ; + // const requestStatus = useRequest(getRestaurants); + // const restaurantsIds = useSelector(selectRestaurantsIds); + + const { data: restaurants, status: requestStatus } = useGetRestaurantsQuery(); + + return ; }; \ No newline at end of file diff --git a/src/pages/restaurants-page/restaurants-page.jsx b/src/pages/restaurants-page/restaurants-page.jsx index 329fdcd..01b049a 100644 --- a/src/pages/restaurants-page/restaurants-page.jsx +++ b/src/pages/restaurants-page/restaurants-page.jsx @@ -1,10 +1,10 @@ import styles from "../../components/restaurant-tabs/restaurant-tabs.module.css"; -import { RestaurantTileContainer } from "../../components/restaurant-tile/restaurant-tile-container.jsx"; import { Breadcrumbs } from "../../components/breadcrumbs/breadcrumbs.jsx"; import { requestText } from "../../data/hooks/use-request.js"; import { FULFILLED } from "../../data/entities/request/sliсe.js"; +import RestaurantTile from "../../components/restaurant-tile/restaurant-tile.jsx"; -export const RestaurantsPage = ({ requestStatus, restaurantsIds }) => { +export const RestaurantsPage = ({ requestStatus, restaurants }) => { const breadcrumbs = [ { text: "Рестораны" @@ -18,8 +18,13 @@ export const RestaurantsPage = ({ requestStatus, restaurantsIds }) => { {requestStatus !== FULFILLED ? requestText(requestStatus) : (
- {restaurantsIds.map((id) => ( - + {restaurants.map((restaurant) => ( + ))}
) } From b553a5c33ea8ef82cb73b619f59dcc161dce5fcd Mon Sep 17 00:00:00 2001 From: yadroRus <37119397+yadroRus@users.noreply.github.com> Date: Mon, 4 Aug 2025 17:38:01 +0300 Subject: [PATCH 2/3] =?UTF-8?q?=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=BE=D1=82=D0=B7=D1=8B=D0=B2=D0=B0=20?= =?UTF-8?q?=D0=BE=20=D1=80=D0=B5=D1=81=D1=82=D0=BE=D1=80=D0=B0=D0=BD=D0=B5?= =?UTF-8?q?=20=D0=BD=D0=B0=20=D1=81=D0=B5=D1=80=D0=B2=D0=B0=D0=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- materials/simple_api/package.json | 1 + materials/simple_api/server.js | 7 +++++-- materials/simple_api/yarn.lock | 15 +++++++++++++- src/components/review-form/review-form.jsx | 9 ++++----- src/data/services/api/api.js | 13 +++++++++++- .../restaurant-reviews-page-container.jsx | 20 +++++++++++++++++-- .../restaurant-reviews-page.jsx | 12 ++++++++--- 7 files changed, 63 insertions(+), 14 deletions(-) diff --git a/materials/simple_api/package.json b/materials/simple_api/package.json index a2cfc54..0395ea5 100644 --- a/materials/simple_api/package.json +++ b/materials/simple_api/package.json @@ -7,6 +7,7 @@ }, "dependencies": { "body-parser": "^1.19.0", + "cors": "^2.8.5", "express": "^4.17.1", "nanoid": "^3.3.6" } diff --git a/materials/simple_api/server.js b/materials/simple_api/server.js index d7688d5..762cd6e 100644 --- a/materials/simple_api/server.js +++ b/materials/simple_api/server.js @@ -2,10 +2,12 @@ const express = require("express"); const api = require("./api"); const bodyParser = require("body-parser"); const port = 3001; +const cors = require("cors"); const app = express(); +app.use(cors({origin:true,credentials: true})); -app.use(function (req, res, next) { +app.use(function(req, res, next) { res.header("Access-Control-Allow-Origin", "*"); res.header("Access-Control-Allow-Methods", "*"); res.header( @@ -17,7 +19,8 @@ app.use(function (req, res, next) { app.use(bodyParser.json()); app.use("/api", api); -app.listen(port, "localhost", function (err) { + +app.listen(port, "localhost", function(err) { if (err) { console.log(err); return; diff --git a/materials/simple_api/yarn.lock b/materials/simple_api/yarn.lock index 6e8a00f..75e3d14 100644 --- a/materials/simple_api/yarn.lock +++ b/materials/simple_api/yarn.lock @@ -58,6 +58,14 @@ cookie@0.4.1: resolved "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz" integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA== +cors@^2.8.5: + version "2.8.5" + resolved "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz" + integrity sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g== + dependencies: + object-assign "^4" + vary "^1" + debug@2.6.9: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" @@ -234,6 +242,11 @@ negotiator@0.6.2: resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== +object-assign@^4: + version "4.1.1" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + on-finished@~2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz" @@ -351,7 +364,7 @@ utils-merge@1.0.1: resolved "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz" integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA== -vary@~1.1.2: +vary@^1, vary@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== diff --git a/src/components/review-form/review-form.jsx b/src/components/review-form/review-form.jsx index 7df0fe3..3b3a946 100644 --- a/src/components/review-form/review-form.jsx +++ b/src/components/review-form/review-form.jsx @@ -8,7 +8,7 @@ const isFormClear = (form) => { return !Object.values(form).find((value) => !!value); }; -export const ReviewForm = memo(({ restaurantId }) => { +export const ReviewForm = memo(({ restaurantId, onSubmit }) => { const { form, setName, @@ -16,7 +16,6 @@ export const ReviewForm = memo(({ restaurantId }) => { incrementRating, decrementRating, clear, - submit, } = useForm({ restaurantId }); const { name, comment, rating } = form; @@ -61,7 +60,7 @@ export const ReviewForm = memo(({ restaurantId }) => { diff --git a/src/data/services/api/api.js b/src/data/services/api/api.js index d37ef6f..77e7c3f 100644 --- a/src/data/services/api/api.js +++ b/src/data/services/api/api.js @@ -6,6 +6,7 @@ export const api = createApi({ baseQuery: fetchBaseQuery({ baseUrl: "http://localhost:3001/api" }), + tagTypes: ["review"], endpoints: (builder) => ({ getRestaurants: builder.query({ query: () => "/restaurants", @@ -25,12 +26,21 @@ export const api = createApi({ }), getReviews: builder.query({ query: (restaurantId) => `/reviews?restaurantId=${restaurantId}`, + providesTags: (_, __, id) => [{ type: "review", id }], keepUnusedDataFor: 20 }), + addReview: builder.mutation({ + query: ({ restaurantId, review }) => ({ + url: `/review/${restaurantId}`, + method: "POST", + body: review + }), + invalidatesTags: (_, __, { id }) => [{ type: "review", id }] + }), getUsers: builder.query({ query: () => `/users`, keepUnusedDataFor: 20 - }), + }) }) }); @@ -42,4 +52,5 @@ export const { useGetDishByIdQuery, useGetReviewsQuery, useGetUsersQuery, + useAddReviewMutation } = api; \ No newline at end of file diff --git a/src/pages/restaurant-reviews-page/restaurant-reviews-page-container.jsx b/src/pages/restaurant-reviews-page/restaurant-reviews-page-container.jsx index 82620b4..28a1f84 100644 --- a/src/pages/restaurant-reviews-page/restaurant-reviews-page-container.jsx +++ b/src/pages/restaurant-reviews-page/restaurant-reviews-page-container.jsx @@ -1,7 +1,7 @@ import { useLoginContext } from "../../components/login-context/hooks.js"; import { RestaurantReviewsPage } from "./restaurant-reviews-page.jsx"; import { useOutletContext } from "react-router"; -import { useGetReviewsQuery } from "../../data/services/api/api.js"; +import { useAddReviewMutation, useGetReviewsQuery } from "../../data/services/api/api.js"; export const RestaurantReviewsPageContainer = () => { const { restaurant } = useOutletContext(); @@ -13,8 +13,24 @@ export const RestaurantReviewsPageContainer = () => { const { data: restaurantReviews, status: requestStatus } = useGetReviewsQuery(restaurant.id); + + const [addReview, isAddReviewLoading] = useAddReviewMutation(); + + const handelOnReview = (form) => { + addReview({ + restaurantId: restaurant.id, + review: { + text: form.comment, + rating: form.rating, + userId: user.userId + } + }); + }; + return ; + requestStatus={requestStatus} + onReviewSubmit={handelOnReview} + />; }; \ No newline at end of file diff --git a/src/pages/restaurant-reviews-page/restaurant-reviews-page.jsx b/src/pages/restaurant-reviews-page/restaurant-reviews-page.jsx index 754339d..4451d5d 100644 --- a/src/pages/restaurant-reviews-page/restaurant-reviews-page.jsx +++ b/src/pages/restaurant-reviews-page/restaurant-reviews-page.jsx @@ -3,12 +3,18 @@ import { ReviewForm } from "../../components/review-form/review-form.jsx"; import { FULFILLED } from "../../data/entities/request/sliсe.js"; import { requestText } from "../../data/hooks/use-request.js"; -export const RestaurantReviewsPage = ({ user, reviews, restaurantId, requestStatus }) => { - return requestStatus !== FULFILLED ? +export const RestaurantReviewsPage = ({ + user, + reviews, + restaurantId, + requestStatus, + onReviewSubmit + }) => { + return requestStatus !== FULFILLED && !reviews ? requestText(requestStatus) : ( <> - {user.name && } + {user.name && } ); }; \ No newline at end of file From cc9052664c2ed288657c05fd6fae16e2ef02cf95 Mon Sep 17 00:00:00 2001 From: yadroRus <37119397+yadroRus@users.noreply.github.com> Date: Mon, 4 Aug 2025 18:39:11 +0300 Subject: [PATCH 3/3] =?UTF-8?q?=D0=BF=D1=80=D0=B0=D0=B2=D0=BA=D0=B0=20?= =?UTF-8?q?=D1=83=D0=B6=D0=B5=20=D0=B4=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=D0=BD=D0=BE=D0=B3=D0=BE=20=D0=BA=D0=BE=D0=BC=D0=BC=D0=B5?= =?UTF-8?q?=D0=BD=D1=82=D0=B0=D1=80=D0=B8=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- materials/simple_api/server.js | 2 +- .../restaurant-comment-item/hooks.js | 28 +++++++++++++++ .../restaurant-comment-item-container.jsx | 18 ++++++++-- .../restaurant-comment-item.jsx | 34 +++++++++++++++++-- .../restaurant-comments.jsx | 4 ++- src/data/services/api/api.js | 11 +++++- .../restaurant-reviews-page.jsx | 2 +- 7 files changed, 91 insertions(+), 8 deletions(-) create mode 100644 src/components/restaurant-comment-item/hooks.js diff --git a/materials/simple_api/server.js b/materials/simple_api/server.js index 762cd6e..0996787 100644 --- a/materials/simple_api/server.js +++ b/materials/simple_api/server.js @@ -5,7 +5,7 @@ const port = 3001; const cors = require("cors"); const app = express(); -app.use(cors({origin:true,credentials: true})); +app.use(cors({ origin: true, credentials: true })); app.use(function(req, res, next) { res.header("Access-Control-Allow-Origin", "*"); diff --git a/src/components/restaurant-comment-item/hooks.js b/src/components/restaurant-comment-item/hooks.js new file mode 100644 index 0000000..635273d --- /dev/null +++ b/src/components/restaurant-comment-item/hooks.js @@ -0,0 +1,28 @@ +import { useState } from "react"; +import { useUpdateReviewMutation } from "../../data/services/api/api.js"; + +export const useCommentEditor = () => { + const [editMode, setEditMode] = useState(false); + const [correctedText, setCorrectedText] = useState(""); + const [correctedRating, setCorrectedRating] = useState(""); + + const [updateReview] = useUpdateReviewMutation(); + + const editCommentHandler = ({ reviewId, text, userId, rating }) => { + setEditMode(!editMode); + if (editMode) { + setCorrectedText(text); + setCorrectedRating(rating); + updateReview({ + reviewId, + review: { + text, + userId, + rating + } + }); + } + }; + + return { editMode, editCommentHandler, correctedText, correctedRating }; +}; \ No newline at end of file diff --git a/src/components/restaurant-comment-item/restaurant-comment-item-container.jsx b/src/components/restaurant-comment-item/restaurant-comment-item-container.jsx index 5717910..1a4fdd6 100644 --- a/src/components/restaurant-comment-item/restaurant-comment-item-container.jsx +++ b/src/components/restaurant-comment-item/restaurant-comment-item-container.jsx @@ -1,14 +1,28 @@ import RestaurantCommentItem from "./restaurant-comment-item.jsx"; import { useGetUsersQuery } from "../../data/services/api/api.js"; import { FULFILLED } from "../../data/entities/request/sliсe.js"; +import { useCommentEditor } from "./hooks.js"; -export const RestaurantCommentItemContainer = ({ text, rating, userId }) => { +export const RestaurantCommentItemContainer = ({ text, rating, userId, reviewId, currentUserId }) => { // const comment = useSelector((state) => selectReviewById(state, commentId)); // const user = useSelector((state) => selectUserById(state, userId)); + const { correctedComment, correctedRating,editMode, editCommentHandler } = useCommentEditor(); + const { data: users, status } = useGetUsersQuery(); + const user = users?.find((u) => u.id === userId); + + const showEditButton = currentUserId === userId; + return status === FULFILLED ? ( - + ) : null; }; diff --git a/src/components/restaurant-comment-item/restaurant-comment-item.jsx b/src/components/restaurant-comment-item/restaurant-comment-item.jsx index de06d3a..69fb8f4 100644 --- a/src/components/restaurant-comment-item/restaurant-comment-item.jsx +++ b/src/components/restaurant-comment-item/restaurant-comment-item.jsx @@ -1,11 +1,41 @@ import styles from "./restaurant-comment-item.module.css"; import { StarsRating } from "../stars-rating/stars-rating.jsx"; +import { Button } from "../button/button.jsx"; +import { useRef } from "react"; + +function RestaurantCommentItem({ + user, + text, + rating, + showEditButton, + editMode, + reviewId, + editCommentHandler + }) { + + const refText = useRef(null); + const refRating = useRef(null); -function RestaurantCommentItem({ user, text, rating }) { return (
  • - {user}: {text} + {user.name}: + {editMode ? ( + <> + + + + ) : ( + {text} + )} + {showEditButton ? ( +
  • diff --git a/src/components/restaurant-comments/restaurant-comments.jsx b/src/components/restaurant-comments/restaurant-comments.jsx index 6948297..a71e016 100644 --- a/src/components/restaurant-comments/restaurant-comments.jsx +++ b/src/components/restaurant-comments/restaurant-comments.jsx @@ -1,6 +1,6 @@ import { RestaurantCommentItemContainer } from "../restaurant-comment-item/restaurant-comment-item-container.jsx"; -export default function RestaurantComments({ reviews }) { +export default function RestaurantComments({ reviews, userId }) { if (!reviews) { return null; } @@ -10,9 +10,11 @@ export default function RestaurantComments({ reviews }) { {reviews.map((review) => ( ))} diff --git a/src/data/services/api/api.js b/src/data/services/api/api.js index 77e7c3f..a4e2634 100644 --- a/src/data/services/api/api.js +++ b/src/data/services/api/api.js @@ -37,6 +37,14 @@ export const api = createApi({ }), invalidatesTags: (_, __, { id }) => [{ type: "review", id }] }), + updateReview: builder.mutation({ + query: ({ reviewId, review }) => ({ + url: `/review/${reviewId}`, + method: "PATCH", + body: review + }), + invalidatesTags: (_, __, { id }) => [{ type: "review", id }] + }), getUsers: builder.query({ query: () => `/users`, keepUnusedDataFor: 20 @@ -52,5 +60,6 @@ export const { useGetDishByIdQuery, useGetReviewsQuery, useGetUsersQuery, - useAddReviewMutation + useAddReviewMutation, + useUpdateReviewMutation, } = api; \ No newline at end of file diff --git a/src/pages/restaurant-reviews-page/restaurant-reviews-page.jsx b/src/pages/restaurant-reviews-page/restaurant-reviews-page.jsx index 4451d5d..1662cd2 100644 --- a/src/pages/restaurant-reviews-page/restaurant-reviews-page.jsx +++ b/src/pages/restaurant-reviews-page/restaurant-reviews-page.jsx @@ -13,7 +13,7 @@ export const RestaurantReviewsPage = ({ return requestStatus !== FULFILLED && !reviews ? requestText(requestStatus) : ( <> - + {user.name && } );