Skip to content

Commit

Permalink
Feat: Star Half
Browse files Browse the repository at this point in the history
  • Loading branch information
eqypo9 committed Dec 2, 2024
1 parent 4038572 commit e316b2f
Show file tree
Hide file tree
Showing 8 changed files with 666 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>
</>
);
}
49 changes: 49 additions & 0 deletions src/components/CourseDetails/RatingStar/StarRating/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import styled from '@emotion/styled';
import StarInput from '../StarInput';

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

const Base = styled.section`
display: flex;
align-items: center;
gap: 8px;
`;

const RatingField = styled.fieldset`
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: #75abff;
}
`;

export default function StarRating({
currentRating,
onRatingChange,
}: StarRatingProps) {
return (
<Base>
<RatingField>
{[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>
);
}
58 changes: 51 additions & 7 deletions src/components/CourseDetails/ReviewCard/ReviewCard.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -54,22 +54,66 @@
padding: 24px 20px;
background: $white;
border-radius: 12px;
}

.card {
display: flex;
flex-direction: column;
gap: 16px;
gap: 28px;
}

.reviewItem {
border-bottom: 1px solid $gray20;
padding-bottom: 12px;

&:last-child {
border-bottom: none;
.header {
display: flex;
justify-content: space-between;
align-items: center;

.profile {
display: flex;
gap: 8px;
align-items: center;

.nameDate {
display: flex;
align-items: center;
gap: 8px;
}

.name {
@include B14M;
color: $gray90;
}

.date {
@include C12M;
color: $gray60;
}
}
}

.rating {
display: flex;
gap: 4px;
margin: 8px 0;
}

.content {
@include B14R;
color: $gray80;
margin: 0 8px 0 40px;
}
}
.reviewContainer {
padding: 24px 20px;
background: $white;
border-radius: 12px;
display: flex;
flex-direction: column;
gap: 28px;
}

.reviewItem {
padding-bottom: 12px;

.header {
display: flex;
justify-content: space-between;
Expand Down
38 changes: 26 additions & 12 deletions src/components/CourseDetails/ReviewCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,22 +72,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="starFull"
width={14}
height={14}
/>
)
)}
{review.score % 1 !== 0 && (
<IconComponent
key={`filled-${review.id}-${index}`}
name="starFull"
key={`half-${review.id}`}
name="starHalf"
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 @@ -74,6 +74,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 } 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 @@ -71,7 +71,7 @@ export default function ReviewWrite({

if (response.success) {
setText('');
setRating(1);
setRating(0);
router.back();
} else {
console.log(response.message);
Expand Down Expand Up @@ -106,9 +106,9 @@ export default function ReviewWrite({
</span>
</div>
<div className={styles.ratingContainer}>
<Rating
onRatingChange={rating => setRating(rating)}
<StarRating
currentRating={rating}
onRatingChange={(newRating: number) => setRating(newRating)}
/>
</div>
<div className={styles.btnContainer}>
Expand Down

0 comments on commit e316b2f

Please sign in to comment.