Skip to content

Commit

Permalink
Merge pull request #47 from gunganghaljido/feature/정성혜
Browse files Browse the repository at this point in the history
  • Loading branch information
eqypo9 authored Dec 2, 2024
2 parents 3a4597b + 16b1427 commit 84ba654
Show file tree
Hide file tree
Showing 9 changed files with 623 additions and 43 deletions.
482 changes: 463 additions & 19 deletions package-lock.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@
"lint": "next lint"
},
"dependencies": {
"@emotion/styled": "^11.13.5",
"@tanstack/react-query": "^5.59.20",
"axios": "^1.7.7",
"classnames": "^2.5.1",
"lodash": "^4.17.21",
"next": "15.0.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-icons": "^5.3.0",
"recoil": "^0.7.7",
"sass": "^1.80.6",
"scss": "^0.2.4",
Expand Down
67 changes: 67 additions & 0 deletions src/components/CourseDetails/RatingStar/StarInput/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import styled from '@emotion/styled';
import { css } from '@emotion/react';
import { FaStar, FaStarHalf } from 'react-icons/fa';
import React from 'react';

interface StarInputProps {
onClickRating: (value: number) => void;
value: number;
isHalf: boolean;
}

const Input = styled.input`
display: none;
`;

const Label = styled.label<{ isHalf: boolean }>`
cursor: pointer;
font-size: 24px;
color: #f1f2f4;
${({ isHalf }) =>
isHalf &&
css`
position: absolute;
width: 12px;
overflow: hidden;
&:nth-of-type(10) {
transform: translate(-108px);
}
&:nth-of-type(8) {
transform: translate(-84px);
}
&:nth-of-type(6) {
transform: translate(-60px);
}
&:nth-of-type(4) {
transform: translate(-36px);
}
&:nth-of-type(2) {
transform: translate(-12px);
}
`}
`;

export default function StarInput({
onClickRating,
value,
isHalf,
}: StarInputProps) {
const handleClickRatingInput = () => {
onClickRating(value);
};

return (
<>
<Input type="radio" name="rating" id={`star${value}`} value={value} />
<Label
onClick={() => handleClickRatingInput()}
isHalf={isHalf}
htmlFor={`star${value}`}
>
{isHalf ? <FaStarHalf /> : <FaStar />}
</Label>
</>
);
}
50 changes: 50 additions & 0 deletions src/components/CourseDetails/RatingStar/StarRating/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import styled from '@emotion/styled';
import StarInput from '../StarInput';

interface StarRatingProps {
currentRating: number;
onRatingChange: (value: number) => void;
isNormal: boolean;
}

const Base = styled.section<{ isNormal: boolean }>`
display: flex;
align-items: center;
gap: 8px;
`;

const RatingField = styled.fieldset<{ isNormal: boolean }>`
position: relative;
display: flex;
align-items: center;
flex-direction: row-reverse;
border: none;
transform: translateY(2px);
input:checked ~ label,
label:hover,
label:hover ~ label {
transition: 0.2s;
color: ${({ isNormal }) => (isNormal ? '#75abff' : '#76c663')};
}
`;

export default function StarRating({
onRatingChange,
isNormal,
}: StarRatingProps) {
return (
<Base isNormal={isNormal}>
<RatingField isNormal={isNormal}>
{[5, 4.5, 4, 3.5, 3, 2.5, 2, 1.5, 1, 0.5].map(value => (
<StarInput
key={value}
onClickRating={onRatingChange}
value={value}
isHalf={value % 1 !== 0}
/>
))}
</RatingField>
</Base>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
.card {
display: flex;
flex-direction: column;
gap: 16px;
gap: 28px;
}

.reviewItem {
Expand Down
49 changes: 31 additions & 18 deletions src/components/CourseDetails/ReviewCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ export default function ReviewCard({
serialNumber,
averageScore,
reviews,
}: ReviewCardProps) {
isNormal,
}: ReviewCardProps & { isNormal: boolean }) {
const [profile, setProfile] = useState<ProfileResponse>();
const [dropdownOpen, setDropdownOpen] = useState<string | null>(null);
const dropdownRef = useRef<HTMLDivElement>(null);
Expand Down Expand Up @@ -70,7 +71,7 @@ export default function ReviewCard({
setDropdownOpen(prev => (prev === reviewId ? null : reviewId));
};

useOutsideClick(dropdownRef, () => toggleDropdown(''));
useOutsideClick(dropdownRef, () => setDropdownOpen(null));

return (
<div className={styles.reviewWrapper}>
Expand All @@ -79,7 +80,7 @@ export default function ReviewCard({
<span className={styles.reviewTitle}>시설 후기</span>
<div className={styles.ratingSummary}>
<IconComponent
name={serialNumber ? 'starFull' : 'starFullSP'}
name={isNormal ? 'starFull' : 'starFullSP'}
width={14}
height={14}
/>
Expand All @@ -90,9 +91,7 @@ export default function ReviewCard({
{!hasReviewed && (
<button
className={
serialNumber
? styles.writeReviewButton
: styles.writeReviewButtonSP
isNormal ? styles.writeReviewButton : styles.writeReviewButtonSP
}
onClick={handleOpenReviewWrite}
>
Expand All @@ -117,22 +116,36 @@ export default function ReviewCard({
{hideNickname(review.nickname)}
</span>
<div className={styles.rating}>
{Array.from({ length: review.score }, (_, index) => (
{Array.from(
{ length: Math.floor(review.score) },
(_, index) => (
<IconComponent
key={`filled-${review.id}-${index}`}
name={isNormal ? 'starFull' : 'starFullSP'}
width={14}
height={14}
/>
)
)}
{review.score % 1 !== 0 && (
<IconComponent
key={`filled-${review.id}-${index}`}
name={serialNumber ? 'starFull' : 'starFullSP'}
key={`half-${review.id}`}
name={isNormal ? 'starHalf' : 'starHalfSP'}
width={14}
height={14}
/>
))}
{Array.from({ length: 5 - review.score }, (_, index) => (
<IconComponent
key={`empty-${review.id}-${index}`}
name="starEmpty"
width={14}
height={14}
/>
))}
)}
{Array.from(
{ length: 5 - Math.ceil(review.score) },
(_, index) => (
<IconComponent
key={`empty-${review.id}-${index}`}
name="starEmpty"
width={14}
height={14}
/>
)
)}
</div>
<span className={styles.date}>
{formattedDate(review.createdAt)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@
border-radius: 12px;
padding: 12px 16px;
margin-top: 16px;
display: flex;
align-items: center;
gap: 8px;
}

.btnContainer {
Expand Down
10 changes: 5 additions & 5 deletions src/components/CourseDetails/ReviewWrite/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import styles from './ReviewWrite.module.scss';
import { getProfile, ProfileResponse } from '@/apis/get/getProfile';
import { formattedDate } from '@/utils/formatDate';
import IconComponent from '@/components/Asset/Icon';
import Rating from './Rating';
import StarRating from '../RatingStar/StarRating';
import CustomButton from '@/components/Button/CustomButton';
import { usePopup } from '@/utils/popupUtils';
import { postNormalReview, postSpecialReview } from '@/apis/post/postReview';
Expand All @@ -19,7 +19,7 @@ export default function ReviewWrite({
}) {
const [profile, setProfile] = useState<ProfileResponse>();
const [text, setText] = useState<string>('');
const [rating, setRating] = useState<number>(1);
const [rating, setRating] = useState<number>(0);
const { openPopup } = usePopup();

useEffect(() => {
Expand Down Expand Up @@ -76,7 +76,7 @@ export default function ReviewWrite({
content: '후기 작성을 완료했어요.',
});
setText('');
setRating(1);
setRating(0);
router.back();
} else {
console.log(response.message);
Expand Down Expand Up @@ -117,9 +117,9 @@ export default function ReviewWrite({
</span>
</div>
<div className={styles.ratingContainer}>
<Rating
onRatingChange={rating => setRating(rating)}
<StarRating
currentRating={rating}
onRatingChange={(newRating: number) => setRating(newRating)}
isNormal={serialNumber ? true : false}
/>
</div>
Expand Down
1 change: 1 addition & 0 deletions src/components/CourseDetails/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ export default function CourseDetails({
serialNumber={serialNumber}
averageScore={facility.averageScore}
reviews={facility.reviews}
isNormal={serialNumber ? true : false}
/>
</div>
);
Expand Down

0 comments on commit 84ba654

Please sign in to comment.