84 lines
3.1 KiB
TypeScript
84 lines
3.1 KiB
TypeScript
import { CleanlinessIcon } from '../../Icons/CleanlinessIcon';
|
|
import { FacilityIcon } from '../../Icons/FacilityIcon';
|
|
import { AccessIcon } from '../../Icons/AccessIcon';
|
|
import { ServiceIcon } from '../../Icons/ServiceIcon';
|
|
|
|
interface RatingData {
|
|
score: number;
|
|
count: number;
|
|
}
|
|
|
|
interface DetailRatings {
|
|
environment: number;
|
|
cleanliness: number;
|
|
price: number;
|
|
facility: number;
|
|
}
|
|
|
|
interface UserLocationDetailRatingsCardProps<T> {
|
|
data: T;
|
|
getCriticData: (data: T) => RatingData;
|
|
getUserData: (data: T) => RatingData;
|
|
getCriticDetails?: (data: T) => DetailRatings;
|
|
getUserDetails?: (data: T) => DetailRatings;
|
|
}
|
|
|
|
const UserLocationDetailRatingsCard = <T,>({
|
|
data,
|
|
getUserData,
|
|
getUserDetails
|
|
}: UserLocationDetailRatingsCardProps<T>) => {
|
|
const userData = getUserData(data);
|
|
const userDetails = getUserDetails?.(data);
|
|
|
|
const formatCount = (count: number): string | number => {
|
|
return count >= 1000
|
|
? `${(count / 1000).toFixed(1).replace(/\.0$/, '')}k`
|
|
: count;
|
|
};
|
|
|
|
const calculateScore = (score: number, count: number): string | number => {
|
|
return count !== 0 ? Math.floor(score / count) : "NR";
|
|
};
|
|
|
|
const detailItems = userDetails ? [
|
|
{ label: 'Akses', value: userDetails.environment, icon: <AccessIcon className="w-7 h-7" strokeWidth={1.1} /> },
|
|
{ label: 'Pelayanan', value: userDetails.price, icon: <ServiceIcon className="w-7 h-7" strokeWidth={1.1} /> },
|
|
{ label: 'Kebersihan', value: userDetails.cleanliness, icon: <CleanlinessIcon className="w-7 h-7" strokeWidth={1.1} /> },
|
|
{ label: 'Fasilitas', value: userDetails.facility, icon: <FacilityIcon className="w-7 h-7" strokeWidth={1.1} /> },
|
|
] : [];
|
|
|
|
return (
|
|
<div className="w-full justify-center mt-2 flex flex-row gap-2 overflow-x-auto [&::-webkit-scrollbar]:hidden">
|
|
|
|
{/* USER SCORE card */}
|
|
<div className="bg-secondary rounded-xl px-4 py-3 flex items-center gap-4 flex-shrink-0 min-w-[240px]">
|
|
<div>
|
|
<div className="text-base font-bold tracking-wide">USER SCORE</div>
|
|
{userData.count !== 0 && (
|
|
<div className="text-tertiary mt-0.5 text-sm">Based on {formatCount(userData.count)} reviews</div>
|
|
)}
|
|
</div>
|
|
<div className="w-11 h-11 rounded-full ml-7 bg-primary flex items-center justify-center text-lg font-bold flex-shrink-0">
|
|
{calculateScore(userData.score, userData.count)}
|
|
</div>
|
|
</div>
|
|
|
|
{/* Detail rating cards — all in one row */}
|
|
{detailItems.map((item) => (
|
|
<div key={item.label} className="border border-gray-600 rounded-xl px-4 py-3 flex items-center gap-3 flex-shrink-0 min-w-[240px]">
|
|
<div className="text-tertiary flex-shrink-0">{item.icon}</div>
|
|
<div>
|
|
<div className="text-tertiary text-sm">{item.label}</div>
|
|
<div className="text-2xl font-bold leading-none my-0.5">{item.value}</div>
|
|
<div className="text-tertiary text-sm">Based on {formatCount(userData.count)} reviews</div>
|
|
</div>
|
|
</div>
|
|
))}
|
|
|
|
</div>
|
|
);
|
|
};
|
|
|
|
export default UserLocationDetailRatingsCard;
|