-

-
{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 && }
>
);