Skip to content

Commit

Permalink
Merge pull request #1 from 3V2T/van1
Browse files Browse the repository at this point in the history
Van1
  • Loading branch information
aycact authored Oct 5, 2024
2 parents 88a81d1 + da1f976 commit 7fef3d5
Show file tree
Hide file tree
Showing 35 changed files with 929 additions and 277 deletions.
2 changes: 2 additions & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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"
},
Expand Down
19 changes: 15 additions & 4 deletions client/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ import {
Cart,
Order,
UserInfo,
Manager
Manager,
SingleOrder
} from './pages/main'
import VerifyEmail from './pages/VerifyEmail'
import { ProtectedRoute, Error } from './pages'
Expand All @@ -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: {
Expand All @@ -50,6 +52,11 @@ const router = createBrowserRouter([
element: <Library />,
loader: libraryLoader(queryClient),
},
{
path: 'library/:id',
element: <SingleBook />,
loader: singleBookLoader(queryClient),
},
{
path: 'cart',
element: <Cart />,
Expand All @@ -71,9 +78,13 @@ const router = createBrowserRouter([
),
},
{
path: 'library/:id',
element: <SingleBook />,
loader: singleBookLoader(queryClient),
path: 'order/:id',
element: (
<ProtectedRoute>
<SingleOrder />
</ProtectedRoute>
),
loader: singleUserOrder(queryClient),
},
{
path: 'author/:id',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
boldTextColor,
} from '../../assets/js/variables'

const CartTotals = () => {
const OrderSummary = () => {
const { cartTotal, shipping, tax, orderTotal } = useSelector(
(store) => store.cart
)
Expand Down Expand Up @@ -41,7 +41,7 @@ const CartTotals = () => {
</Wrapper>
)
}
export default CartTotals
export default OrderSummary

const Wrapper = styled.section`
margin-bottom: 1rem;
Expand Down
260 changes: 260 additions & 0 deletions client/src/components/CommentSection.jsx
Original file line number Diff line number Diff line change
@@ -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 <Loading/>
return (
<Wrapper style={{ backgroundColor: `${quaternaryBgColor}` }}>
<MDBContainer className="mt-2 " style={{ maxWidth: '100vw' }}>
<MDBRow className="justify-content-center">
<MDBCol md="12" lg="10">
<MDBCard className="text-dark comment-container">
<MDBCardBody className="p-4">
{userReview && user ? (
<div>
<MDBTypography tag="h4" className="mb-4">
Đánh giá của bạn
</MDBTypography>
<div className="d-flex flex-start">
<div
style={{ width: '12rem' }}
className="d-flex flex-column align-items-center"
>
<MDBCardImage
className="rounded-circle shadow-1-strong me-3"
src={userReview?.user?.user_img || defaultAvatar}
alt="avatar"
width="60"
height="60"
/>
<MDBTypography tag="h6" className="fw-bold mb-1">
{userReview?.user?.name}
</MDBTypography>
<p className="mb-0">
{formatVNTimeZoneDate(userReview?.created_at)}
</p>
</div>
<div style={{ width: '70vw', marginLeft: '1rem' }}>
<div className="d-flex align-items-center justify-content-start mb-3">
<span
className="badge bg-success"
style={{ fontSize: '1rem', color: '#FFBF00' }}
>
{userReview?.rating}
<FaStar className="pb-1 ms-1" />
</span>
<h5 className="mb-0 ms-2">
{ratingTitle(userReview?.rating)}
</h5>
</div>
<div className="mb-0">{userReview?.comment}</div>
</div>
</div>
</div>
) : (
<div className="d-flex flex-column">
<label htmlFor="description">
<h5 className="mb-0">Viết đánh giá của bạn</h5>
</label>
<div className="d-flex">
<StarRatings
changeRating={handleRatingChange}
rating={values.rating}
starRatedColor="rgb(230, 67, 47)"
numberOfStars={5}
name="rating"
starDimension="22px"
/>
<h5 className="mb-0 mt-2 ms-3">{title}</h5>
</div>
<textarea
id="description"
name="comment"
rows="5"
cols="115"
className="description-area mt-2"
value={values.comment}
onChange={handleChange}
/>
<div className="btn-container">
<button
disabled={!user}
type="button"
onClick={handleSubmit}
className="btn"
>
Gửi đánh giá
</button>
</div>
</div>
)}
</MDBCardBody>

<hr className="my-0" />
<div className="ms-4 mt-4">
<MDBTypography tag="h4" className="mb-0">
Những đánh giá gần đây
</MDBTypography>
<p className="fw-light pb-2">
Đánh giá mới nhất bởi người dùng
</p>
</div>
{reviews?.length === 0 && (
<h5 className="ms-4">Chưa có đánh giá nào...</h5>
)}
{reviews?.map((review) => {
return (
user?.userId !== review?.user_id && (
<MDBCardBody className="p-4" key={review?.id}>
<div className="d-flex flex-start">
<div
style={{ width: '12rem' }}
className="d-flex flex-column align-items-center"
>
<MDBCardImage
className="rounded-circle shadow-1-strong me-3"
src={review?.user?.user_img || defaultAvatar}
alt="avatar"
width="60"
height="60"
/>
<div>
<MDBTypography tag="h6" className="fw-bold mb-1">
{review?.user?.name}
</MDBTypography>
</div>
<p className="mb-0">
{formatVNTimeZoneDate(review?.created_at)}
</p>
</div>
<div style={{ width: '70vw', marginLeft: '3rem' }}>
<div className="d-flex align-items-center justify-content-start mb-3">
<span
className="badge bg-success"
style={{ fontSize: '1rem', color: '#FFBF00' }}
>
{review?.rating}
<FaStar className="pb-1 ms-1" />
</span>
<h5 className="mb-0 ms-2">
{ratingTitle(review?.rating)}
</h5>
</div>
<div className="mb-0">{review?.comment}</div>
</div>
</div>
</MDBCardBody>
)
)
})}
</MDBCard>
</MDBCol>
</MDBRow>
</MDBContainer>
</Wrapper>
)
}

const Wrapper = styled.section`
.comment-container {
margin-bottom: 2rem;
padding-bottom: 1rem;
background-color: ${quaternaryBgColorLight};
}
.description-area {
background-color: ${quaternaryBgColorLight};
border-radius: 1rem;
}
.btn-container {
margin-top: 1rem;
}
.btn {
background-color: ${quaternaryBgColor};
float: right;
}
`
2 changes: 1 addition & 1 deletion client/src/components/Home/FeaturedBook.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const FeaturedBook = ({ newBooks, title, maxWidthItems, gap }) => {
lg={maxWidthItems}
className={`${gap} g-5 justify-content-start`}
>
{newBooks.map((book) => {
{newBooks?.map((book) => {
return <BookItem book={book} key={book.id} />
})}
</Row>
Expand Down
4 changes: 2 additions & 2 deletions client/src/components/MyNavbar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,11 +58,11 @@ const MyNavbar = () => {
{(user === null || user?.role === 'user') && (
<Nav.Link href="/cart">Giỏ hàng</Nav.Link>
)}
{user && user.role === 'user' && (
{user && user?.role === 'user' && (
<Nav.Link href="/checkout">Thanh toán</Nav.Link>
)}
{user && <Nav.Link href="/order">Đơn hàng</Nav.Link>}
{user && user.role === 'admin' && (
{user && user?.role === 'admin' && (
<Nav.Link href="/manager">Quản lý</Nav.Link>
)}
</Nav>
Expand Down
6 changes: 6 additions & 0 deletions client/src/components/Order/CustomerContactInfo.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
const CustomerContactInfo = () => {
return (
<div>CustomerContactInfo</div>
)
}
export default CustomerContactInfo
Loading

0 comments on commit 7fef3d5

Please sign in to comment.