diff --git a/client/package.json b/client/package.json index 6e50047..d865193 100644 --- a/client/package.json +++ b/client/package.json @@ -23,6 +23,7 @@ "bootstrap-icons": "^1.11.3", "dayjs": "^1.11.13", "dotenv": "^16.4.5", + "mdb-react-ui-kit": "^9.0.0", "lightningcss": "^1.27.0", "polished": "^4.3.1", "react": "^18.3.1", @@ -31,6 +32,7 @@ "react-icons": "^5.2.1", "react-redux": "^9.1.2", "react-router-dom": "^6.24.0", + "react-star-ratings": "^2.3.0", "react-toastify": "^10.0.5", "styled-components": "^6.1.12" }, diff --git a/client/src/App.jsx b/client/src/App.jsx index 939618a..2dee735 100644 --- a/client/src/App.jsx +++ b/client/src/App.jsx @@ -11,7 +11,8 @@ import { Cart, Order, UserInfo, - Manager + Manager, + SingleOrder } from './pages/main' import VerifyEmail from './pages/VerifyEmail' import { ProtectedRoute, Error } from './pages' @@ -24,6 +25,7 @@ import { loader as verifyEmailLoader } from './pages/VerifyEmail' import { loader as singleBookLoader } from './pages/main/SingleBook' import { loader as singleAuthorLoader } from './pages/main/SingleAuthor' import { loader as newBookLoader} from './pages/main/Home' +import { loader as singleUserOrder } from './pages/main/SingleOrder' const queryClient = new QueryClient({ defaultOptions: { @@ -50,6 +52,11 @@ const router = createBrowserRouter([ element: , loader: libraryLoader(queryClient), }, + { + path: 'library/:id', + element: , + loader: singleBookLoader(queryClient), + }, { path: 'cart', element: , @@ -71,9 +78,13 @@ const router = createBrowserRouter([ ), }, { - path: 'library/:id', - element: , - loader: singleBookLoader(queryClient), + path: 'order/:id', + element: ( + + + + ), + loader: singleUserOrder(queryClient), }, { path: 'author/:id', diff --git a/client/src/components/Cart/CartTotals.jsx b/client/src/components/Cart/OrderSummary.jsx similarity index 96% rename from client/src/components/Cart/CartTotals.jsx rename to client/src/components/Cart/OrderSummary.jsx index e93a8bf..69a1a6f 100644 --- a/client/src/components/Cart/CartTotals.jsx +++ b/client/src/components/Cart/OrderSummary.jsx @@ -10,7 +10,7 @@ import { boldTextColor, } from '../../assets/js/variables' -const CartTotals = () => { +const OrderSummary = () => { const { cartTotal, shipping, tax, orderTotal } = useSelector( (store) => store.cart ) @@ -41,7 +41,7 @@ const CartTotals = () => { ) } -export default CartTotals +export default OrderSummary const Wrapper = styled.section` margin-bottom: 1rem; diff --git a/client/src/components/CommentSection.jsx b/client/src/components/CommentSection.jsx new file mode 100644 index 0000000..2d234d7 --- /dev/null +++ b/client/src/components/CommentSection.jsx @@ -0,0 +1,260 @@ +import React, { useEffect, useState } from 'react' +import { + MDBCard, + MDBCardBody, + MDBCardImage, + MDBCol, + MDBContainer, + MDBRow, + MDBTypography, +} from 'mdb-react-ui-kit' +import { + quaternaryBgColor, + quaternaryBgColorLight, +} from '../assets/js/variables' +import styled from 'styled-components' +import { defaultAvatar } from '../assets/images' +import { formatVNTimeZoneDate, ratingTitle } from '../utils' +import { FaStar } from 'react-icons/fa' +import { useSelector } from 'react-redux' +import { customFetch } from '../utils/axios' +import StarRatings from 'react-star-ratings' +import { toast } from 'react-toastify' +import Loading from './Loading' + +export default function CommentSection({ book_id, reviews }) { + const [loading, setLoading] = useState(false) + const [values, setValues] = useState({ + rating: 5, + comment: '', + }) + const [title, setTitle] = useState(ratingTitle(values.rating)) + const { user, isLoading } = useSelector((store) => store.user) + const [userReview, setUserReview] = useState(null) + + const handleRatingChange = (e) => { + setValues({ ...values, rating: e }) + } + const handleChange = (e) => { + const name = e.target.name + const value = e.target.value + setValues({ ...values, [name]: value }) + } + + const handleSubmit = async (e) => { + e.preventDefault() + try { + setLoading(true) + const review = { + rating: values.rating, + comment: values.comment, + book_id, + } + + await customFetch.post('/reviews', review) + setValues({ + rating: 5, + comment: '', + }) + toast.success('Đánh giá đã được gửi') + } catch (error) { + console.log(error) + toast.warn(error?.response?.data?.msg) + } finally { + setLoading(false) + } + } + + useEffect(() => { + const fetchUserReview = async () => { + if (user) { + try { + const response = await customFetch( + `/reviews/getCurrentUserReviewSingleBook/${book_id}` + ) + setUserReview(response.data.review) + } catch (error) { + console.error('Error fetching user review:', error) + } + } + } + + fetchUserReview() + }, [book_id, loading, user]) + + useEffect(() => { + setTitle(ratingTitle(values.rating)) + }, [values.rating]) + + if(loading) + return + return ( + + + + + + + {userReview && user ? ( +
+ + Đánh giá của bạn + +
+
+ + + {userReview?.user?.name} + +

+ {formatVNTimeZoneDate(userReview?.created_at)} +

+
+
+
+ + {userReview?.rating} + + +
+ {ratingTitle(userReview?.rating)} +
+
+
{userReview?.comment}
+
+
+
+ ) : ( +
+ +
+ +
{title}
+
+