hilingriviw/src/pages/BestLocations/index.tsx
2025-04-11 06:46:12 +07:00

204 lines
9.0 KiB
TypeScript
Executable File

import { TargetedEvent } from "preact/compat";
import { useEffect, useState } from "preact/hooks";
import { getListTopLocationsService } from "../../services";
import { DefaultSeparator } from "../../components";
import './style.css';
import { useClick, useFloating, useInteractions } from "@floating-ui/react";
import { Link } from "react-router-dom";
interface TopLocation {
row_number: Number,
id: Number,
name: String,
thumbnail: string | null,
address: String,
google_maps_link: string,
regency_name: string,
critic_score: Number,
critic_count: Number,
user_score: Number,
user_count: Number,
critic_bayes: Number,
user_bayes: Number,
avg_bayes: Number,
}
const REGIONS = [
'All',
'Sumatera',
'Jawa',
'Kalimantan',
'Nusa Tenggara',
'Maluku',
'Papua',
'Sulawesi',
];
const REVIEWERS_TYPE = [
'All',
'Critics',
'Users'
]
const MIN_REVIEWS = [
2,
5,
7,
11
]
function BestLocation() {
const [page, _setPage] = useState<number>(1);
const [topLocations, setTopLocations] = useState<Array<TopLocation>>([])
const [pageState, setPageState] = useState({
filterScoreType: 'all',
filterScoreTypeidx: 1,
filterRegionTypeName: 'All',
filterRegionType: 0,
})
async function getTopLocations() {
try {
const res = await getListTopLocationsService({
page: page, page_size: 20,
order_by: pageState.filterScoreTypeidx,
region_type: pageState.filterRegionType
})
setTopLocations(res.data)
} catch (err) {
console.log(err)
}
}
function onChangeReviewType(e: TargetedEvent<HTMLAnchorElement>, reviewer_type: string, i: number) {
e.preventDefault()
setPageState({ ...pageState, filterScoreType: reviewer_type, filterScoreTypeidx: i })
}
function onChangeRegionType(e: TargetedEvent<HTMLAnchorElement>, region_name: string, type: number) {
e.preventDefault();
setPageState({ ...pageState, filterRegionTypeName: region_name, filterRegionType: type })
}
useEffect(() => {
getTopLocations()
}, [pageState])
return (
<div className={'content main-content mt-3'}>
<section name={"Top locations header"}>
<h1 className={'text-3xl mb-5 font-bold'}>Top Locations</h1>
<div className={'regions-dropdown text-xs pr-3 inline-block'}>
<p className={'inline-block'}>Regions</p>
<a style={{ cursor: 'pointer' }}>
<p className={'ml-2 inline-block'}>{pageState.filterRegionTypeName}</p>
<svg style={{ display: 'inline-block' }} fill='white' xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M480-345 240-585l56-56 184 184 184-184 56 56-240 240Z" /></svg>
</a>
<div className={'dropdown-content text-sm'}>
{REGIONS.map((x, index) => (
<a onClick={(e) => onChangeRegionType(e, x, index)} className={'block pt-1'}>{x}</a>
))}
</div>
</div>
<div className={'regions-dropdown text-xs pr-3 inline-block'}>
<p className={'inline-block'}>Min. Reviews</p>
<a style={{ cursor: 'pointer' }}>
<p className={'ml-2 inline-block'}>All</p>
<svg style={{ display: 'inline-block' }} fill='white' xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M480-345 240-585l56-56 184 184 184-184 56 56-240 240Z" /></svg>
</a>
<div className={'dropdown-content-min-reviews text-sm'}>
{MIN_REVIEWS.map(x => (
<a className={'block pt-1'}>{x}</a>
))}
</div>
</div>
<div className={'regions-dropdown text-xs pr-3 inline-block'}>
<p className={'inline-block'}>Tags</p>
<a style={{ cursor: 'pointer' }}>
<p className={'ml-2 inline-block'}>All</p>
<svg style={{ display: 'inline-block' }} fill='white' xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M480-345 240-585l56-56 184 184 184-184 56 56-240 240Z" /></svg>
</a>
<div className={'dropdown-content text-sm'}>
{/* {REGIONS.map(x => (
<a className={'block pt-1'}>{x}</a>
))} */}
</div>
</div>
<DefaultSeparator />
</section>
<section name={'Main content'}>
<div className={'flex flex-row pt-10 pb-10'}>
<div className={'mr-5'} style={{ flex: 1 }}>
{topLocations.map(x => (
<>
{/* UNCOMMENT....IF THERES A PURPOSE FOR RIGHT THREE DOTS */}
{/* <div style={{ float: 'right', cursor: 'pointer' }}>
<a className={'text-xl'}>
...
</a>
</div> */}
<div className={'mb-2 best-locations-title'}>
<Link className={'text-xl'} to={`/location/${x.id}`}>{x.row_number}.{x.name}</Link>
</div>
<div style={{ maxWidth: 200, maxHeight: 200, margin: '0 30px 30px 10px', float: 'left' }}>
<Link to={`/location/${x.id}`} >
<img src={x.thumbnail ? x.thumbnail : ""} loading={'lazy'} style={{ width: '100%', objectFit: 'cover', height: '100%', aspectRatio: '1/1' }} />
</Link>
</div>
<div className={'text-md font-bold'}>{x.regency_name}</div>
<div className={'text-xs mb-2'}>{x.address}</div>
<div>$$$ (IDR 1000-12000)</div>
<a href={x.google_maps_link} target={'_'}><div className={'text-sm mt-2 items-center'}><svg style={{ display: 'inline-block', marginBottom: 3 }} xmlns="http://www.w3.org/2000/svg" height="12" fill={'white'} viewBox="0 -960 960 960" width="12 "><path d="M480-480q33 0 56.5-23.5T560-560q0-33-23.5-56.5T480-640q-33 0-56.5 23.5T400-560q0 33 23.5 56.5T480-480Zm0 294q122-112 181-203.5T720-552q0-109-69.5-178.5T480-800q-101 0-170.5 69.5T240-552q0 71 59 162.5T480-186Zm0 106Q319-217 239.5-334.5T160-552q0-150 96.5-239T480-880q127 0 223.5 89T800-552q0 100-79.5 217.5T480-80Zm0-480Z" /></svg>Maps Location</div></a>
<div className={'mt-4'}>
<div className={'text-xs bg-secondary'} style={{ width: 160, display: 'inline-block', borderRadius: 5 }}>
<div className={'text-center p-1 bg-tertiary text-primary'} style={{ borderTopRightRadius: 5, borderTopLeftRadius: 5 }}>CRITICS SCORE</div>
<div className={"flex flex-row items-center p-2"}>
<div className={'mr-3 users-score-bar'}>
<p className={`text-xl text-center ${x.critic_score !== 0 ? 'font-bold' : ''}`}>{x.critic_score !== 0 ? Number(x.critic_score) / Number(x.critic_count) * 10 : "N/A"}</p>
<div className={"mt-1"} style={{ height: 4, width: 40, backgroundColor: "#72767d" }}>
<div style={{ height: 4, width: ` ${x.critic_count !== 0 ? Number(x.critic_score) / Number(x.critic_count) * 10 : 0}%`, backgroundColor: 'green' }} />
</div>
</div>
<p className={'text-xs users-score'}>{x.critic_count} reviews</p>
</div>
</div>
<div className={'text-xs bg-secondary ml-3'} style={{ width: 160, display: 'inline-block', borderRadius: 5 }}>
<div className={'text-center p-1 bg-tertiary text-primary'} style={{ borderTopLeftRadius: 5, borderTopRightRadius: 5 }}>USERS SCORE</div>
<div className={"flex flex-row items-center p-2"}>
<div className={'mr-3 users-score-bar'}>
<p className={`text-xl text-center ${x.user_score !== 0 ? 'font-bold' : ''}`}>{x.user_score !== 0 ? x.user_score : "N/A"}</p>
<div className={"mt-1"} style={{ height: 4, width: 40, backgroundColor: "#72767d" }}>
<div style={{ height: 4, width: ` ${x.user_score !== 0 ? x.user_score : 0}%`, backgroundColor: 'green' }} />
</div>
</div>
<p className={'text-xs users-score'}>{x.user_count} reviews</p>
</div>
</div>
</div>
<div style={{ clear: 'both' }} />
</>
))}
</div>
<div className={'p-4 bg-secondary'} style={{ minWidth: 300 }}>
<div className={'h-30 bg-primary p-4 right-filter'}>
{REVIEWERS_TYPE.map((x, idx) => (
<a
onClick={(e) => onChangeReviewType(e, x.toLowerCase(), idx + 1)}
href={'#'}
style={pageState.filterScoreType == x.toLowerCase() ? { pointerEvents: 'none' } : ''}
>
<div className={`pt-1 pb-1 ${pageState.filterScoreType == x.toLowerCase() ? 'pl-1 bg-tertiary selected-reviewer-filter' : ''}`}>{x} Score</div>
</a>
))}
</div>
</div>
</div>
</section>
</div>
)
}
export default BestLocation;