Integrate with get recent locations ratings in home page
This commit is contained in:
parent
f01bf17fcf
commit
1ecefbf60a
@ -10,7 +10,8 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"axios": "^1.5.0",
|
"axios": "^1.5.0",
|
||||||
"preact": "^10.16.0"
|
"preact": "^10.16.0",
|
||||||
|
"react-router-dom": "^6.16.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@preact/preset-vite": "^2.5.0",
|
"@preact/preset-vite": "^2.5.0",
|
||||||
|
23
src/app.tsx
23
src/app.tsx
@ -1,11 +1,26 @@
|
|||||||
|
import { Route, Routes } from 'react-router-dom'
|
||||||
|
import { BrowserRouter as Router } from 'react-router-dom'
|
||||||
import './app.css'
|
import './app.css'
|
||||||
import { Home } from './pages'
|
import { DefaultLayout } from './layouts'
|
||||||
|
import routes from './routes'
|
||||||
export function App() {
|
export function App() {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Home />
|
<Router>
|
||||||
|
<Routes>
|
||||||
|
<Route element={<DefaultLayout />}>
|
||||||
|
{routes.map(({ path, name, element}) => (
|
||||||
|
<>
|
||||||
|
<Route
|
||||||
|
path={path}
|
||||||
|
id={name}
|
||||||
|
element={element}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
))}
|
||||||
|
</Route>
|
||||||
|
</Routes>
|
||||||
|
</Router>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -114,9 +114,4 @@ label:before {
|
|||||||
/* display: 'inline-block';
|
/* display: 'inline-block';
|
||||||
max-width: '100%';
|
max-width: '100%';
|
||||||
text-align: 'center'; */
|
text-align: 'center'; */
|
||||||
}
|
|
||||||
|
|
||||||
.navLink:hover{
|
|
||||||
border-bottom-width: 2px;
|
|
||||||
margin-bottom: -2px;
|
|
||||||
}
|
}
|
16
src/constants/api.ts
Normal file
16
src/constants/api.ts
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
const BASE_URL = "http://localhost:8888"
|
||||||
|
|
||||||
|
const SIGNUP_URI = `${BASE_URL}/user/signup`
|
||||||
|
|
||||||
|
|
||||||
|
const GET_LIST_LOCATIONS_URI = `${BASE_URL}/locations`;
|
||||||
|
const GET_LIST_RECENT_LOCATIONS_RATING_URI = `${BASE_URL}/recent-locations/ratings`
|
||||||
|
const GET_LOCATION_URI = `${BASE_URL}/location`;
|
||||||
|
|
||||||
|
export {
|
||||||
|
BASE_URL,
|
||||||
|
GET_LIST_RECENT_LOCATIONS_RATING_URI,
|
||||||
|
GET_LIST_LOCATIONS_URI,
|
||||||
|
GET_LOCATION_URI,
|
||||||
|
SIGNUP_URI
|
||||||
|
}
|
@ -1,16 +1,13 @@
|
|||||||
import { ComponentChildren } from "preact";
|
import { ComponentChildren } from "preact";
|
||||||
import { Footer, Header } from "../../components";
|
import { Footer, Header } from "../../components";
|
||||||
|
import { Outlet } from "react-router-dom";
|
||||||
|
|
||||||
type ChildrenProps = {
|
function DefaultLayout() {
|
||||||
children: ComponentChildren
|
|
||||||
}
|
|
||||||
|
|
||||||
function DefaultLayout({ children }: ChildrenProps) {
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Header />
|
<Header />
|
||||||
<main style={{ overflow: 'hidden' }}>
|
<main style={{ overflow: 'hidden' }}>
|
||||||
{children}
|
<Outlet />
|
||||||
</main>
|
</main>
|
||||||
<Footer />
|
<Footer />
|
||||||
</>
|
</>
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
import { DefaultLayout } from '../../layouts/';
|
|
||||||
import { SeparatorWithAnchor } from '../../components';
|
import { SeparatorWithAnchor } from '../../components';
|
||||||
import data from '../../datas/home.json';
|
import data from '../../datas/home.json';
|
||||||
import news from '../../datas/recent_news_event.json';
|
import news from '../../datas/recent_news_event.json';
|
||||||
@ -6,16 +5,18 @@ import popular from '../../datas/popular.json';
|
|||||||
import critics_users_pick from '../../datas/critics_users_best_pick.json';
|
import critics_users_pick from '../../datas/critics_users_best_pick.json';
|
||||||
import popular_user_review from '../../datas/popular_user_reviews.json';
|
import popular_user_review from '../../datas/popular_user_reviews.json';
|
||||||
import './style.css';
|
import './style.css';
|
||||||
|
import { useEffect, useState } from 'preact/hooks';
|
||||||
|
import { getListLocations, getListRecentLocationsRatings } from '../../services';
|
||||||
|
|
||||||
type NewPlaces = {
|
type NewPlaces = {
|
||||||
id: Number,
|
id: Number,
|
||||||
name: string,
|
name: string,
|
||||||
thumbnail: string,
|
thumbnail: NullValueRes<'String', string>,
|
||||||
location: string,
|
regency_name: NullValueRes<'String', string>,
|
||||||
critic_rating: Number,
|
critic_score: Number,
|
||||||
critic_voters: Number,
|
critic_count: Number,
|
||||||
user_rating: Number,
|
user_score: Number,
|
||||||
user_voters: Number
|
user_count: Number
|
||||||
}
|
}
|
||||||
|
|
||||||
type News = {
|
type News = {
|
||||||
@ -27,40 +28,58 @@ type News = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function Home() {
|
function Home() {
|
||||||
|
const [recentLocations, setRecentLocations] = useState([])
|
||||||
|
|
||||||
|
async function getRecentLocations() {
|
||||||
|
try {
|
||||||
|
const locations = await getListRecentLocationsRatings(12)
|
||||||
|
setRecentLocations(locations.data)
|
||||||
|
} catch(error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
getRecentLocations()
|
||||||
|
},[])
|
||||||
return (
|
return (
|
||||||
<DefaultLayout>
|
<>
|
||||||
<div className="content main-content mt-3">
|
<div className="content main-content mt-3">
|
||||||
|
|
||||||
{/* RECENTLY ADDED SECTION */}
|
{/* RECENTLY ADDED SECTION */}
|
||||||
<section about={"Recently added places"} className={'mt-3'}>
|
<section about={"Recently added places"} className={'mt-3'}>
|
||||||
<SeparatorWithAnchor pageLink='#' pageName='recently added' secondLink='#' />
|
<SeparatorWithAnchor pageLink='#' pageName='recently added' secondLink='#' />
|
||||||
{data.new_places.map((x: NewPlaces) => (
|
{recentLocations.map((x: NewPlaces) => (
|
||||||
<div className={"recently-added-section-card"}>
|
<div className={"recently-added-section-card"}>
|
||||||
<div className={'border-secondary recently-img-container'}>
|
<div className={'border-secondary recently-img-container'}>
|
||||||
<img alt={x.name} src={x.thumbnail} loading="eager" style={{ width: '100%', height: '100%' }} />
|
<img alt={x.name} src={x.thumbnail.String.toString()} loading="eager" style={{ width: '100%', height: '100%' }} />
|
||||||
</div>
|
</div>
|
||||||
<div className={"border-primary pb-2 location-container text-sm mb-2 mt-2"}>
|
<div className={"border-primary pb-2 location-container text-sm mb-2 mt-2"}>
|
||||||
<p className={'location-title'}>{x.name}</p>
|
<p className={'location-title'}>{x.name}</p>
|
||||||
<p className={'text-xs mt-1'}>{x.location}</p>
|
<p className={'text-xs mt-1'}>{x.regency_name.String}</p>
|
||||||
</div>
|
</div>
|
||||||
<div className={"flex flex-row items-center mb-3"}>
|
{ x.critic_score !== -1 &&
|
||||||
<div className={'mr-3 users-score-bar'}>
|
<div className={"flex flex-row items-center mb-3"}>
|
||||||
<p className={'text-sm text-center'}>{x.critic_rating}</p>
|
<div className={'mr-3 users-score-bar'}>
|
||||||
<div style={{ height: 4, width: 30, backgroundColor: "#72767d"}}>
|
<p className={'text-sm text-center'}>{x.critic_score === -1 ? "NR" : x.critic_score}</p>
|
||||||
<div style={{ height: 4, width: `${x.critic_rating}%`, backgroundColor: 'green' }} />
|
<div style={{ height: 4, width: 30, backgroundColor: "#72767d"}}>
|
||||||
|
<div style={{ height: 4, width: `${x.critic_score === -1 ? 0 : x.critic_score}%`, backgroundColor: 'green' }} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<p className={"users-score"}>critic score ({x.critic_count})</p>
|
||||||
</div>
|
</div>
|
||||||
<p className={"users-score"}>critic score ({x.critic_voters})</p>
|
}
|
||||||
</div>
|
{ x.user_score !== -1 &&
|
||||||
<div className={"flex flex-row items-center"}>
|
<div className={"flex flex-row items-center"}>
|
||||||
<div className={'mr-3 users-score-bar'}>
|
<div className={'mr-3 users-score-bar'}>
|
||||||
<p className={'text-sm text-center'}>{x.user_rating}</p>
|
<p className={'text-sm text-center'}>{x.user_score === -1 ? "NR" : x.user_score}</p>
|
||||||
<div style={{ height: 4, width: 30, backgroundColor: "#72767d" }}>
|
<div style={{ height: 4, width: 30, backgroundColor: "#72767d" }}>
|
||||||
<div style={{ height: 4, width: ` ${x.user_rating}%`, backgroundColor: 'green' }} />
|
<div style={{ height: 4, width: ` ${x.user_score === -1 ? 0 : x.user_score}%`, backgroundColor: 'green' }} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<p className={'users-score'}>user score ({x.user_count})</p>
|
||||||
</div>
|
</div>
|
||||||
<p className={'users-score'}>user score ({x.user_voters})</p>
|
}
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</section>
|
</section>
|
||||||
@ -187,7 +206,7 @@ function Home() {
|
|||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
</div>
|
</div>
|
||||||
</DefaultLayout>
|
</>
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
13
src/routes/index.tsx
Normal file
13
src/routes/index.tsx
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
import {
|
||||||
|
Home
|
||||||
|
} from '../pages';
|
||||||
|
|
||||||
|
const routes = [
|
||||||
|
{
|
||||||
|
path: "/",
|
||||||
|
name: "Home",
|
||||||
|
element: <Home />
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
export default routes;
|
19
src/services/config.ts
Normal file
19
src/services/config.ts
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import axios, { AxiosPromise, AxiosRequestConfig } from "axios";
|
||||||
|
import {BASE_URL} from '../constants/api'
|
||||||
|
|
||||||
|
export const client = (props: AxiosRequestConfig): AxiosPromise => axios({
|
||||||
|
method: props.method,
|
||||||
|
baseURL: `${BASE_URL}`,
|
||||||
|
url: props.url,
|
||||||
|
headers: props.headers,
|
||||||
|
data: props.data
|
||||||
|
})
|
||||||
|
|
||||||
|
// export const authClient = (props: AxiosRequestConfig) => axios({
|
||||||
|
// method: props.method,
|
||||||
|
// baseURL: `${BASE_URL}`,
|
||||||
|
// url: props.url,
|
||||||
|
// headers: {
|
||||||
|
// 'Authorization':
|
||||||
|
// }
|
||||||
|
// })
|
6
src/services/index.ts
Normal file
6
src/services/index.ts
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
import { getListLocations, getListRecentLocationsRatings } from "./locations";
|
||||||
|
|
||||||
|
export {
|
||||||
|
getListLocations,
|
||||||
|
getListRecentLocationsRatings
|
||||||
|
}
|
54
src/services/locations.ts
Normal file
54
src/services/locations.ts
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
import { GET_LIST_LOCATIONS_URI, GET_LIST_RECENT_LOCATIONS_RATING_URI } from "../constants/api";
|
||||||
|
import { client } from "./config";
|
||||||
|
import statusCode from "./status-code";
|
||||||
|
|
||||||
|
const initialState: any = {
|
||||||
|
data: null,
|
||||||
|
error: null
|
||||||
|
}
|
||||||
|
|
||||||
|
type getListLocationsArg = {
|
||||||
|
page: number,
|
||||||
|
page_size: number
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getListLocations ({ page, page_size}: getListLocationsArg) {
|
||||||
|
const newState = {...initialState};
|
||||||
|
const url = `${GET_LIST_LOCATIONS_URI}?page=${page}&page_size=${page_size}`
|
||||||
|
try {
|
||||||
|
const response = await client({method: 'GET', url: url})
|
||||||
|
switch (response.request.status) {
|
||||||
|
case statusCode.OK:
|
||||||
|
newState.data = response.data;
|
||||||
|
return newState;
|
||||||
|
default:
|
||||||
|
newState.error = response.data;
|
||||||
|
return newState
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getListRecentLocationsRatings (page_size: Number) {
|
||||||
|
const newState = {...initialState};
|
||||||
|
const url = `${GET_LIST_RECENT_LOCATIONS_RATING_URI}?page_size=${page_size}`
|
||||||
|
try {
|
||||||
|
const response = await client({method: 'GET', url: url})
|
||||||
|
switch (response.request.status) {
|
||||||
|
case statusCode.OK:
|
||||||
|
newState.data = response.data;
|
||||||
|
return newState;
|
||||||
|
default:
|
||||||
|
newState.error = response.data;
|
||||||
|
return newState
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
getListLocations,
|
||||||
|
getListRecentLocationsRatings
|
||||||
|
}
|
10
src/services/status-code.ts
Normal file
10
src/services/status-code.ts
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
export default {
|
||||||
|
OK: 200,
|
||||||
|
CREATED: 201,
|
||||||
|
ACCEPTED: 202,
|
||||||
|
BAD_REQUEST: 400,
|
||||||
|
UNAUTHORIZED: 401,
|
||||||
|
NOT_ALLOWED: 405,
|
||||||
|
NOT_FOUND: 404,
|
||||||
|
SERVER_ERROR: 500,
|
||||||
|
};
|
3
src/types/common.ts
Normal file
3
src/types/common.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
type BaseNullValueRes = { valid: boolean };
|
||||||
|
type NullValueRes<Key extends string, Type> = BaseNullValueRes & Record<Key, string | number>
|
||||||
|
|
20
yarn.lock
20
yarn.lock
@ -434,6 +434,11 @@
|
|||||||
"@prefresh/utils" "^1.2.0"
|
"@prefresh/utils" "^1.2.0"
|
||||||
"@rollup/pluginutils" "^4.2.1"
|
"@rollup/pluginutils" "^4.2.1"
|
||||||
|
|
||||||
|
"@remix-run/router@1.9.0":
|
||||||
|
version "1.9.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.9.0.tgz#9033238b41c4cbe1e961eccb3f79e2c588328cf6"
|
||||||
|
integrity sha512-bV63itrKBC0zdT27qYm6SDZHlkXwFL1xMBuhkn+X7l0+IIhNaH5wuuvZKp6eKhCD4KFhujhfhCT1YxXW6esUIA==
|
||||||
|
|
||||||
"@rollup/pluginutils@^4.1.1", "@rollup/pluginutils@^4.2.1":
|
"@rollup/pluginutils@^4.1.1", "@rollup/pluginutils@^4.2.1":
|
||||||
version "4.2.1"
|
version "4.2.1"
|
||||||
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d"
|
resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d"
|
||||||
@ -1050,6 +1055,21 @@ queue-microtask@^1.2.2:
|
|||||||
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
||||||
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
||||||
|
|
||||||
|
react-router-dom@^6.16.0:
|
||||||
|
version "6.16.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-router-dom/-/react-router-dom-6.16.0.tgz#86f24658da35eb66727e75ecbb1a029e33ee39d9"
|
||||||
|
integrity sha512-aTfBLv3mk/gaKLxgRDUPbPw+s4Y/O+ma3rEN1u8EgEpLpPe6gNjIsWt9rxushMHHMb7mSwxRGdGlGdvmFsyPIg==
|
||||||
|
dependencies:
|
||||||
|
"@remix-run/router" "1.9.0"
|
||||||
|
react-router "6.16.0"
|
||||||
|
|
||||||
|
react-router@6.16.0:
|
||||||
|
version "6.16.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-router/-/react-router-6.16.0.tgz#abbf3d5bdc9c108c9b822a18be10ee004096fb81"
|
||||||
|
integrity sha512-VT4Mmc4jj5YyjpOi5jOf0I+TYzGpvzERy4ckNSvSh2RArv8LLoCxlsZ2D+tc7zgjxcY34oTz2hZaeX5RVprKqA==
|
||||||
|
dependencies:
|
||||||
|
"@remix-run/router" "1.9.0"
|
||||||
|
|
||||||
read-cache@^1.0.0:
|
read-cache@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"
|
resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"
|
||||||
|
Loading…
Reference in New Issue
Block a user