94 lines
2.5 KiB
TypeScript
94 lines
2.5 KiB
TypeScript
import { useState } from 'react'
|
||
|
||
import { useSendRate, useUserRating } from '../hooks/api'
|
||
import { gotError, gotResponse } from '../hooks/useFetch'
|
||
|
||
import styles from '../styles/StarRating.module.css'
|
||
|
||
type StarProps = {
|
||
filled: boolean,
|
||
selected: boolean,
|
||
selectRate?: () => void,
|
||
sendMyRate?: () => void,
|
||
disabled: boolean
|
||
}
|
||
|
||
function Star({ filled, selected, selectRate, disabled }: StarProps) {
|
||
return (
|
||
<button
|
||
className={`${styles.star} ${filled ? styles.starFilled : ''} ${selected ? styles.starSelected : ''}`}
|
||
onMouseEnter={selectRate}
|
||
onFocus={selectRate}
|
||
disabled={disabled}
|
||
>★</button> // star
|
||
)
|
||
}
|
||
|
||
type StarRatingProps = {
|
||
userId: number,
|
||
dynamic?: boolean,
|
||
}
|
||
|
||
function StarRating({ userId, dynamic = false }: StarRatingProps) {
|
||
const rating = useUserRating(userId)
|
||
|
||
const [selectedRate, setSelectedRate] = useState(0)
|
||
const [myRate, setMyRate] = useState(0)
|
||
const rated = myRate > 0
|
||
|
||
const { doSendRate } = useSendRate()
|
||
|
||
async function sendMyRate() {
|
||
const res = await doSendRate(selectedRate, userId)
|
||
|
||
if (res) {
|
||
rating.refetch()
|
||
setMyRate(selectedRate)
|
||
}
|
||
}
|
||
|
||
if (!gotResponse(rating)) {
|
||
return (
|
||
<span>Загрузка...</span>
|
||
)
|
||
}
|
||
|
||
if (gotError(rating)) {
|
||
return (
|
||
<span className='text-danger'>{rating.error}</span>
|
||
)
|
||
}
|
||
|
||
return (
|
||
<span
|
||
className={styles.starContainer}
|
||
|
||
onClick={() => dynamic && !rated && void sendMyRate()}
|
||
|
||
onMouseEnter={() => rated && setSelectedRate(myRate)}
|
||
onMouseLeave={() => setSelectedRate(0)}
|
||
|
||
onFocus={() => rated && setSelectedRate(myRate)}
|
||
onBlur={() => setSelectedRate(0)}
|
||
|
||
onTouchStart={() => rated && setSelectedRate(myRate)}
|
||
onTouchEnd={() => setSelectedRate(0)}
|
||
|
||
title={`Пользователи: ${Math.round(rating.data)}\nВы: ${myRate}`}
|
||
tabIndex={0}
|
||
>
|
||
{...Array(5).fill(5).map((_, i) => (
|
||
<Star
|
||
key={i}
|
||
filled={i < Math.round(rating.data)}
|
||
selected={i < selectedRate}
|
||
selectRate={() => dynamic && !rated && setSelectedRate(i + 1)}
|
||
disabled={!dynamic || rated}
|
||
/>
|
||
))}
|
||
</span >
|
||
)
|
||
}
|
||
|
||
export default StarRating
|