Compare commits
No commits in common. "7e152c1532abcebb04ba2e8d067dfbf99565ca26" and "946bed296abb7b918eea94dd43d31eee77ab8945" have entirely different histories.
7e152c1532
...
946bed296a
4
TODO
4
TODO
@ -1,4 +0,0 @@
|
|||||||
SITE DESIGN:
|
|
||||||
|
|
||||||
- Discover / Cards
|
|
||||||
https://www.looria.com/category/backpack
|
|
@ -16,10 +16,11 @@
|
|||||||
"interweave": "^13.1.0",
|
"interweave": "^13.1.0",
|
||||||
"interweave-autolink": "^5.1.0",
|
"interweave-autolink": "^5.1.0",
|
||||||
"interweave-emoji": "^7.0.0",
|
"interweave-emoji": "^7.0.0",
|
||||||
|
"moment": "^2.29.4",
|
||||||
"preact": "^10.16.0",
|
"preact": "^10.16.0",
|
||||||
|
"react": "^18.2.0",
|
||||||
"react-redux": "^8.1.2",
|
"react-redux": "^8.1.2",
|
||||||
"react-router-dom": "^6.16.0",
|
"react-router-dom": "^6.16.0",
|
||||||
"react-select": "^5.8.0",
|
|
||||||
"react-textarea-autosize": "^8.5.3",
|
"react-textarea-autosize": "^8.5.3",
|
||||||
"redux-persist": "^6.0.0",
|
"redux-persist": "^6.0.0",
|
||||||
"redux-thunk": "^2.4.2",
|
"redux-thunk": "^2.4.2",
|
||||||
|
2273
pnpm-lock.yaml
2273
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
@ -3,7 +3,7 @@ import { BrowserRouter as Router } from 'react-router-dom'
|
|||||||
import './app.css'
|
import './app.css'
|
||||||
import { DefaultLayout } from './layouts'
|
import { DefaultLayout } from './layouts'
|
||||||
import "yet-another-react-lightbox/styles.css";
|
import "yet-another-react-lightbox/styles.css";
|
||||||
import { Login, NotFound } from './pages'
|
import { Login, NotFound, Submissions } from './pages'
|
||||||
import { Provider } from 'react-redux'
|
import { Provider } from 'react-redux'
|
||||||
import { persistore, store } from './store/config'
|
import { persistore, store } from './store/config'
|
||||||
import { PersistGate } from 'redux-persist/integration/react'
|
import { PersistGate } from 'redux-persist/integration/react'
|
||||||
|
@ -35,13 +35,13 @@ export default function CustomInterweave({
|
|||||||
instagram,
|
instagram,
|
||||||
...props
|
...props
|
||||||
}: Props) {
|
}: Props) {
|
||||||
// let hashtagUrl = '';
|
let hashtagUrl = '';
|
||||||
|
|
||||||
// if (twitter) {
|
if (twitter) {
|
||||||
// hashtagUrl = 'https://twitter.com/hashtag/{{hashtag}}';
|
hashtagUrl = 'https://twitter.com/hashtag/{{hashtag}}';
|
||||||
// } else if (instagram) {
|
} else if (instagram) {
|
||||||
// hashtagUrl = 'https://instagram.com/explore/tags/{{hashtag}}';
|
hashtagUrl = 'https://instagram.com/explore/tags/{{hashtag}}';
|
||||||
// }
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Interweave
|
<Interweave
|
||||||
|
@ -3,10 +3,8 @@ import { useState } from "preact/hooks";
|
|||||||
import { useSelector, useDispatch } from "react-redux";
|
import { useSelector, useDispatch } from "react-redux";
|
||||||
import { UserRootState } from "../../store/type";
|
import { UserRootState } from "../../store/type";
|
||||||
import { logout } from '../../actions';
|
import { logout } from '../../actions';
|
||||||
import AsyncSelect from 'react-select/async';
|
|
||||||
import './style.css';
|
import './style.css';
|
||||||
import { logoutService } from "../../services";
|
import { logoutService } from "../../services";
|
||||||
import { getSearchLocationService } from "../../services/locations";
|
|
||||||
|
|
||||||
|
|
||||||
function Header() {
|
function Header() {
|
||||||
@ -19,9 +17,9 @@ function Header() {
|
|||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const user = useSelector((state: UserRootState) => state.auth)
|
const user = useSelector((state: UserRootState) => state.auth)
|
||||||
|
|
||||||
const onInput = (val: string): void => {
|
const onInput = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||||
// const val = e.target as HTMLInputElement;
|
const val = e.target as HTMLInputElement;
|
||||||
setSearchVal(val.toLowerCase())
|
setSearchVal(val.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
const handleLogout = async (): Promise<void> => {
|
const handleLogout = async (): Promise<void> => {
|
||||||
@ -38,29 +36,6 @@ function Header() {
|
|||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
}
|
}
|
||||||
|
|
||||||
const onSelectedSearchOption = (val) => {
|
|
||||||
console.log(val)
|
|
||||||
}
|
|
||||||
|
|
||||||
const onLoadSelectOptions = async (inputValue: string) => {
|
|
||||||
try {
|
|
||||||
const results = await getSearchLocationService({
|
|
||||||
name: inputValue,
|
|
||||||
page: 1,
|
|
||||||
page_size: 7
|
|
||||||
})
|
|
||||||
const resultData = results.data.map((x: any) => {
|
|
||||||
return {
|
|
||||||
value: x.id,
|
|
||||||
label: x.name
|
|
||||||
}
|
|
||||||
})
|
|
||||||
return resultData
|
|
||||||
} catch (err) {
|
|
||||||
alert(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const onDropdown = (): void => {
|
const onDropdown = (): void => {
|
||||||
document.body.style.overflow = "hidden"
|
document.body.style.overflow = "hidden"
|
||||||
|
|
||||||
@ -98,57 +73,15 @@ function Header() {
|
|||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<form onSubmit={onSearchSubmit} className={`header-search-input ${dropdown ? "search-input-dropdown" : ""}`}>
|
<form onSubmit={onSearchSubmit} className={`header-search-input ${dropdown ? "search-input-dropdown" : ""}`}>
|
||||||
<AsyncSelect
|
<label>
|
||||||
onInputChange={onInput}
|
<input
|
||||||
inputValue={searchVal}
|
type="text"
|
||||||
isSearchable
|
value={searchVal}
|
||||||
placeholder={"Candi Borobudur, Tunjungan Plaza, ...."}
|
onInput={onInput}
|
||||||
|
placeholder="Yogyakarta, Pantai Cidaun ..."
|
||||||
components={{
|
class="text-input-search"
|
||||||
DropdownIndicator: () => null,
|
|
||||||
NoOptionsMessage: () => null,
|
|
||||||
IndicatorSeparator: () => null
|
|
||||||
}}
|
|
||||||
loadOptions={onLoadSelectOptions}
|
|
||||||
cacheOptions
|
|
||||||
classNames={{
|
|
||||||
control: () => "bg-secondary text-input-search",
|
|
||||||
menuList: () => "bg-secondary text-sm text-left",
|
|
||||||
}}
|
|
||||||
styles={{
|
|
||||||
singleValue: (base, _props) => ({
|
|
||||||
color: '#797979',
|
|
||||||
textTransform: 'capitalize',
|
|
||||||
...base,
|
|
||||||
}),
|
|
||||||
input: (base, _props) => ({
|
|
||||||
...base,
|
|
||||||
width: 325,
|
|
||||||
color: 'white',
|
|
||||||
padding: 0,
|
|
||||||
}),
|
|
||||||
control: (base, _props) => ({
|
|
||||||
...base,
|
|
||||||
backgroundColor: '#red',
|
|
||||||
color: 'white',
|
|
||||||
border: 0,
|
|
||||||
padding: 0,
|
|
||||||
boxShadow: 'none',
|
|
||||||
textAlign: 'left',
|
|
||||||
minHeight: 45
|
|
||||||
}),
|
|
||||||
option: (base, {isFocused}) => ({
|
|
||||||
...base,
|
|
||||||
backgroundColor: isFocused ? '#202225' : 'none',
|
|
||||||
}),
|
|
||||||
// container: (base, props) => ({
|
|
||||||
// ...base,
|
|
||||||
// border: 0,
|
|
||||||
// color: "white"
|
|
||||||
// })
|
|
||||||
}}
|
|
||||||
onChange={onSelectedSearchOption}
|
|
||||||
/>
|
/>
|
||||||
|
</label>
|
||||||
</form>
|
</form>
|
||||||
<button onClick={onDropdown} className={`dropdown-menu bg-secondary ${dropdown ? 'ml-auto' : ''}`} style={{ padding: 5, borderRadius: 10 }}>
|
<button onClick={onDropdown} className={`dropdown-menu bg-secondary ${dropdown ? 'ml-auto' : ''}`} style={{ padding: 5, borderRadius: 10 }}>
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" height="30" fill="white" viewBox="0 -960 960 960" width="30"><path d="M120-240v-80h720v80H120Zm0-200v-80h720v80H120Zm0-200v-80h720v80H120Z" /></svg>
|
<svg xmlns="http://www.w3.org/2000/svg" height="30" fill="white" viewBox="0 -960 960 960" width="30"><path d="M120-240v-80h720v80H120Zm0-200v-80h720v80H120Zm0-200v-80h720v80H120Z" /></svg>
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
const BASE_URL = "http://localhost:8888";
|
const BASE_URL = "http://localhost:8888"
|
||||||
|
|
||||||
const SIGNUP_URI = `${BASE_URL}/user/signup`;
|
const SIGNUP_URI = `${BASE_URL}/user/signup`
|
||||||
const LOGIN_URI = `${BASE_URL}/user/login`;
|
const LOGIN_URI = `${BASE_URL}/user/login`
|
||||||
const LOGOUT_URI = `${BASE_URL}/user/logout`;
|
const LOGOUT_URI = `${BASE_URL}/user/logout`
|
||||||
|
|
||||||
const GET_REGIONS = `${BASE_URL}/regions`;
|
const GET_REGIONS = `${BASE_URL}/regions`;
|
||||||
const GET_REGENCIES = `${BASE_URL}/region/regencies`;
|
const GET_REGENCIES = `${BASE_URL}/region/regencies`;
|
||||||
@ -11,23 +11,22 @@ const GET_PROVINCES = `${BASE_URL}/region/provinces`;
|
|||||||
const GET_CURRENT_USER_STATS = `${BASE_URL}/user/profile`;
|
const GET_CURRENT_USER_STATS = `${BASE_URL}/user/profile`;
|
||||||
const PATCH_USER_AVATAR = `${BASE_URL}/user/avatar`;
|
const PATCH_USER_AVATAR = `${BASE_URL}/user/avatar`;
|
||||||
const PATCH_USER_INFO = `${BASE_URL}/user`;
|
const PATCH_USER_INFO = `${BASE_URL}/user`;
|
||||||
const DELETE_USER_AVATAR = `${BASE_URL}/user/avatar`;
|
const DELETE_USER_AVATAR = `${BASE_URL}/user/avatar`
|
||||||
|
|
||||||
const GET_NEWS_EVENTS_URI = `${BASE_URL}/news-events`;
|
const GET_NEWS_EVENTS_URI = `${BASE_URL}/news-events`;
|
||||||
const POST_NEWS_EVENTS_URI = GET_NEWS_EVENTS_URI;
|
const POST_NEWS_EVENTS_URI = GET_NEWS_EVENTS_URI
|
||||||
|
|
||||||
const GET_LIST_LOCATIONS_URI = `${BASE_URL}/locations`;
|
const GET_LIST_LOCATIONS_URI = `${BASE_URL}/locations`;
|
||||||
const GET_SEARCH_LOCATIONS_URI = `${BASE_URL}/locations/search`;
|
const GET_LIST_TOP_LOCATIONS = `${BASE_URL}/locations/top-ratings`
|
||||||
const GET_LIST_TOP_LOCATIONS = `${BASE_URL}/locations/top-ratings`;
|
const GET_LIST_RECENT_LOCATIONS_RATING_URI = `${BASE_URL}/locations/recent`
|
||||||
const GET_LIST_RECENT_LOCATIONS_RATING_URI = `${BASE_URL}/locations/recent`;
|
|
||||||
const GET_LOCATION_URI = `${BASE_URL}/location`;
|
const GET_LOCATION_URI = `${BASE_URL}/location`;
|
||||||
const GET_LOCATION_TAGS_URI = `${BASE_URL}/location/tags`;
|
const GET_LOCATION_TAGS_URI = `${BASE_URL}/location/tags`
|
||||||
const POST_CREATE_LOCATION = GET_LIST_LOCATIONS_URI;
|
const POST_CREATE_LOCATION = GET_LIST_LOCATIONS_URI;
|
||||||
|
|
||||||
const GET_IMAGES_BY_LOCATION_URI = `${BASE_URL}/images/location`;
|
const GET_IMAGES_BY_LOCATION_URI = `${BASE_URL}/images/location`
|
||||||
|
|
||||||
const POST_REVIEW_LOCATION_URI = `${BASE_URL}/review/location`;
|
const POST_REVIEW_LOCATION_URI = `${BASE_URL}/review/location`
|
||||||
const GET_CURRENT_USER_REVIEW_LOCATION_URI = `${BASE_URL}/user/review/location`;
|
const GET_CURRENT_USER_REVIEW_LOCATION_URI = `${BASE_URL}/user/review/location`
|
||||||
|
|
||||||
export {
|
export {
|
||||||
BASE_URL,
|
BASE_URL,
|
||||||
@ -44,7 +43,6 @@ export {
|
|||||||
GET_LIST_TOP_LOCATIONS,
|
GET_LIST_TOP_LOCATIONS,
|
||||||
GET_LIST_LOCATIONS_URI,
|
GET_LIST_LOCATIONS_URI,
|
||||||
GET_LOCATION_URI,
|
GET_LOCATION_URI,
|
||||||
GET_SEARCH_LOCATIONS_URI,
|
|
||||||
GET_LOCATION_TAGS_URI,
|
GET_LOCATION_TAGS_URI,
|
||||||
GET_IMAGES_BY_LOCATION_URI,
|
GET_IMAGES_BY_LOCATION_URI,
|
||||||
GET_CURRENT_USER_REVIEW_LOCATION_URI,
|
GET_CURRENT_USER_REVIEW_LOCATION_URI,
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
|
import { NullValueRes } from '../types/common';
|
||||||
|
|
||||||
export type LocationInfo = {
|
export type LocationInfo = {
|
||||||
id: Number,
|
id: Number,
|
||||||
name: string,
|
name: string,
|
||||||
thumbnail: string | null,
|
thumbnail: NullValueRes<'String', string>,
|
||||||
regency_name: String,
|
regency_name: String,
|
||||||
province_name: String,
|
province_name: String,
|
||||||
critic_score: Number,
|
critic_score: Number,
|
||||||
|
@ -227,7 +227,7 @@ function AddLocation() {
|
|||||||
<a href={'#'} title={x.name}>
|
<a href={'#'} title={x.name}>
|
||||||
<img
|
<img
|
||||||
loading={'lazy'}
|
loading={'lazy'}
|
||||||
src={x.thumbnail ? x.thumbnail : ""}
|
src={x.thumbnail.String.toString()}
|
||||||
alt={x.name}
|
alt={x.name}
|
||||||
style={{ aspectRatio: '1/1' }}
|
style={{ aspectRatio: '1/1' }}
|
||||||
/>
|
/>
|
||||||
|
@ -9,7 +9,7 @@ interface TopLocation {
|
|||||||
row_number: Number,
|
row_number: Number,
|
||||||
id: Number,
|
id: Number,
|
||||||
name: String,
|
name: String,
|
||||||
thumbnail: string | null,
|
thumbnail: NullValueRes<"String", String>,
|
||||||
address: String,
|
address: String,
|
||||||
google_maps_link: string,
|
google_maps_link: string,
|
||||||
regency_name: string,
|
regency_name: string,
|
||||||
@ -145,7 +145,7 @@ function BestLocation() {
|
|||||||
</div>
|
</div>
|
||||||
<div style={{ maxWidth: 200, maxHeight: 200, margin: '0 30px 30px 10px', float: 'left' }}>
|
<div style={{ maxWidth: 200, maxHeight: 200, margin: '0 30px 30px 10px', float: 'left' }}>
|
||||||
<a href={`/location/${x.id}`} >
|
<a href={`/location/${x.id}`} >
|
||||||
<img src={x.thumbnail ? x.thumbnail : ""} loading={'lazy'} style={{ width: '100%', objectFit: 'cover', height: '100%', aspectRatio: '1/1' }} />
|
<img src={x.thumbnail.String.toString()} loading={'lazy'} style={{ width: '100%', objectFit: 'cover', height: '100%', aspectRatio: '1/1' }} />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div className={'text-md font-bold'}>{x.regency_name}</div>
|
<div className={'text-md font-bold'}>{x.regency_name}</div>
|
||||||
|
@ -53,8 +53,16 @@ function Home() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function onNavigateToDetail(id: Number,) {
|
function onNavigateToDetail(
|
||||||
navigate(`/location/${id}`)
|
id: Number,
|
||||||
|
critic_count: Number,
|
||||||
|
critic_score: Number,
|
||||||
|
user_count: Number,
|
||||||
|
user_score: Number,
|
||||||
|
) {
|
||||||
|
|
||||||
|
navigate(`/location/${id}`, { state: { user_score: user_score, user_count: user_count, critic_score: critic_score, critic_count: critic_count } })
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -71,9 +79,9 @@ function Home() {
|
|||||||
<SeparatorWithAnchor pageLink='#' pageName='recently added' secondLink='#' />
|
<SeparatorWithAnchor pageLink='#' pageName='recently added' secondLink='#' />
|
||||||
{recentLocations.map((x) => (
|
{recentLocations.map((x) => (
|
||||||
<div className={"recently-added-section-card"}>
|
<div className={"recently-added-section-card"}>
|
||||||
<a onClick={() => onNavigateToDetail(x.id)}>
|
<a onClick={() => onNavigateToDetail(x.id, x.critic_count, x.critic_score, x.user_count, x.user_score)}>
|
||||||
<div className={'border-secondary recently-img-container'}>
|
<div className={'border-secondary recently-img-container'}>
|
||||||
<img alt={x.name} src={x.thumbnail ? x.thumbnail : ''} loading="lazy" style={{ width: '100%', height: '100%' }} />
|
<img alt={x.name} src={x.thumbnail.String.toString()} loading="lazy" style={{ width: '100%', height: '100%' }} />
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
<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"}>
|
||||||
@ -191,7 +199,7 @@ function Home() {
|
|||||||
<div className={"pt-2 text-sm top-location-container"}>
|
<div className={"pt-2 text-sm top-location-container"}>
|
||||||
<div className={'mr-2 critics-users-image'}>
|
<div className={'mr-2 critics-users-image'}>
|
||||||
<img
|
<img
|
||||||
src={x.thumbnail ? x.thumbnail : 'https://i.ytimg.com/vi/0DY1WSk8B9o/maxresdefault.jpg'}
|
src={x.thumbnail.Valid ? x.thumbnail.String.toString() : 'https://i.ytimg.com/vi/0DY1WSk8B9o/maxresdefault.jpg'}
|
||||||
loading={'lazy'}
|
loading={'lazy'}
|
||||||
style={{ height: '100%', width: '100%', borderRadius: 3}}
|
style={{ height: '100%', width: '100%', borderRadius: 3}}
|
||||||
/>
|
/>
|
||||||
@ -215,7 +223,7 @@ function Home() {
|
|||||||
<div className={"pt-2 text-sm top-location-container"}>
|
<div className={"pt-2 text-sm top-location-container"}>
|
||||||
<div className={'mr-2 critics-users-image'}>
|
<div className={'mr-2 critics-users-image'}>
|
||||||
<img
|
<img
|
||||||
src={x.thumbnail ? x.thumbnail : 'https://i.ytimg.com/vi/0DY1WSk8B9o/maxresdefault.jpg'}
|
src={x.thumbnail.Valid ? x.thumbnail.String.toString() : 'https://i.ytimg.com/vi/0DY1WSk8B9o/maxresdefault.jpg'}
|
||||||
style={{ height: '100%', width: '100%', borderRadius: 3}}
|
style={{ height: '100%', width: '100%', borderRadius: 3}}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
@ -61,9 +61,7 @@ function LocationDetail() {
|
|||||||
try {
|
try {
|
||||||
const res = await getLocationService(Number(id))
|
const res = await getLocationService(Number(id))
|
||||||
setLocationDetail(res.data, (val) => {
|
setLocationDetail(res.data, (val) => {
|
||||||
if(val.detail.thumbnail) {
|
getImage(val.detail.thumbnail.String.toString())
|
||||||
getImage(val.detail.thumbnail)
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
let err = error as AxiosError;
|
let err = error as AxiosError;
|
||||||
@ -225,7 +223,7 @@ function LocationDetail() {
|
|||||||
style={{ display: 'grid', position: 'relative', gridTemplateColumns: 'repeat(12,1fr)', cursor: 'zoom-in' }}
|
style={{ display: 'grid', position: 'relative', gridTemplateColumns: 'repeat(12,1fr)', cursor: 'zoom-in' }}
|
||||||
>{Number(locationImages?.total_image) > 0 &&
|
>{Number(locationImages?.total_image) > 0 &&
|
||||||
<div class="image-stack__item image-stack__item--top">
|
<div class="image-stack__item image-stack__item--top">
|
||||||
<img src={locationDetail.detail.thumbnail ? locationDetail.detail.thumbnail : ""} alt="" style={{ aspectRatio: '1/1' }} />
|
<img src={locationDetail.detail.thumbnail.String.toString()} alt="" style={{ aspectRatio: '1/1' }} />
|
||||||
{locationImages?.images.length > 1 &&
|
{locationImages?.images.length > 1 &&
|
||||||
<div className={'text-xs p-2 bg-primary'} style={{ position: 'absolute', bottom: 0, right: 0 }}>
|
<div className={'text-xs p-2 bg-primary'} style={{ position: 'absolute', bottom: 0, right: 0 }}>
|
||||||
Total images ({locationImages?.images.length})
|
Total images ({locationImages?.images.length})
|
||||||
@ -239,7 +237,7 @@ function LocationDetail() {
|
|||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
<div class="image-stack__item image-stack__item--bottom" style={Number(locationImages?.total_image) > 1 ? {} : { gridColumn: '13/1' }}>
|
<div class="image-stack__item image-stack__item--bottom" style={Number(locationImages?.total_image) > 1 ? {} : { gridColumn: '13/1' }}>
|
||||||
<img src={Number(locationImages?.total_image) > 1 ? locationImages?.images[1].src.toString() : locationDetail.detail.thumbnail!} alt="" style={{ aspectRatio: '1/1' }} />
|
<img src={Number(locationImages?.total_image) > 1 ? locationImages?.images[1].src.toString() : locationDetail.detail.thumbnail.String.toString()} alt="" style={{ aspectRatio: '1/1' }} />
|
||||||
</div>
|
</div>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -435,7 +433,7 @@ function LocationDetail() {
|
|||||||
<img
|
<img
|
||||||
loading={'lazy'}
|
loading={'lazy'}
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
src={x.user_avatar ? x.user_avatar : 'https://cdn.discordapp.com/attachments/743422487882104837/1153985664849805392/421-4212617_person-placeholder-image-transparent-hd-png-download.png'}
|
src={x.user_avatar.Valid ? x.user_avatar.String.toString() : 'https://cdn.discordapp.com/attachments/743422487882104837/1153985664849805392/421-4212617_person-placeholder-image-transparent-hd-png-download.png'}
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -488,7 +486,7 @@ function LocationDetail() {
|
|||||||
<img
|
<img
|
||||||
loading={'lazy'}
|
loading={'lazy'}
|
||||||
style={{ width: '100%' }}
|
style={{ width: '100%' }}
|
||||||
src={x.user_avatar ? x.user_avatar : 'https://cdn.discordapp.com/attachments/743422487882104837/1153985664849805392/421-4212617_person-placeholder-image-transparent-hd-png-download.png'}
|
src={x.user_avatar.Valid ? x.user_avatar.String.toString() : 'https://cdn.discordapp.com/attachments/743422487882104837/1153985664849805392/421-4212617_person-placeholder-image-transparent-hd-png-download.png'}
|
||||||
/>
|
/>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
@ -9,7 +9,7 @@ export interface ILocationDetail {
|
|||||||
province_name: String,
|
province_name: String,
|
||||||
region_name: String,
|
region_name: String,
|
||||||
google_maps_link: String,
|
google_maps_link: String,
|
||||||
thumbnail: string | null,
|
thumbnail: NullValueRes<"String", String>,
|
||||||
submitted_by: Number,
|
submitted_by: Number,
|
||||||
critic_score: Number,
|
critic_score: Number,
|
||||||
critic_count: Number,
|
critic_count: Number,
|
||||||
@ -22,7 +22,7 @@ export function emptyLocationDetail(): ILocationDetail {
|
|||||||
id: 0,
|
id: 0,
|
||||||
address: '',
|
address: '',
|
||||||
google_maps_link: '',
|
google_maps_link: '',
|
||||||
thumbnail: "",
|
thumbnail: { String: '', Valid: false },
|
||||||
name: '',
|
name: '',
|
||||||
province_name: '',
|
province_name: '',
|
||||||
regency_name: '',
|
regency_name: '',
|
||||||
@ -41,7 +41,7 @@ export interface LocationReviewsResponse {
|
|||||||
comments: string,
|
comments: string,
|
||||||
user_id: number,
|
user_id: number,
|
||||||
username: string,
|
username: string,
|
||||||
user_avatar: string | null,
|
user_avatar: NullValueRes<"String", string>,
|
||||||
created_at: string,
|
created_at: string,
|
||||||
updated_at: string
|
updated_at: string
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import { IHttpResponse } from "../../../src/types/common";
|
|||||||
import { useSelector } from "react-redux";
|
import { useSelector } from "react-redux";
|
||||||
import { UserRootState } from "src/store/type";
|
import { UserRootState } from "src/store/type";
|
||||||
import "./style.css"
|
import "./style.css"
|
||||||
|
import useCallbackState from "../../../src/types/state-callback";
|
||||||
|
|
||||||
function NewsEvent() {
|
function NewsEvent() {
|
||||||
const [news, setNews] = useState<Array<News>>([]);
|
const [news, setNews] = useState<Array<News>>([]);
|
||||||
|
@ -3,7 +3,7 @@ import { DefaultButton, TitleSeparator, WarningButton } from "../../components";
|
|||||||
import { UserRootState } from "../../store/type";
|
import { UserRootState } from "../../store/type";
|
||||||
import { DEFAULT_AVATAR_IMG } from "../../constants/default";
|
import { DEFAULT_AVATAR_IMG } from "../../constants/default";
|
||||||
import { ChangeEvent, TargetedEvent, useRef } from "preact/compat";
|
import { ChangeEvent, TargetedEvent, useRef } from "preact/compat";
|
||||||
import { useState } from "preact/compat";
|
import { useState } from "react";
|
||||||
import { enumKeys, useAutosizeTextArea } from "../../utils";
|
import { enumKeys, useAutosizeTextArea } from "../../utils";
|
||||||
import { SocialMediaEnum } from "../../types/common";
|
import { SocialMediaEnum } from "../../types/common";
|
||||||
import { SocialMedia, UserInfo } from "../../../src/domains/User";
|
import { SocialMedia, UserInfo } from "../../../src/domains/User";
|
||||||
|
@ -5,7 +5,6 @@ import {
|
|||||||
GET_LIST_TOP_LOCATIONS,
|
GET_LIST_TOP_LOCATIONS,
|
||||||
GET_LOCATION_TAGS_URI,
|
GET_LOCATION_TAGS_URI,
|
||||||
GET_LOCATION_URI,
|
GET_LOCATION_URI,
|
||||||
GET_SEARCH_LOCATIONS_URI,
|
|
||||||
POST_CREATE_LOCATION
|
POST_CREATE_LOCATION
|
||||||
} from "../constants/api";
|
} from "../constants/api";
|
||||||
import { client } from "./config";
|
import { client } from "./config";
|
||||||
@ -22,10 +21,6 @@ interface GetListLocationsArg extends GetRequestPagination {
|
|||||||
region_type?: number
|
region_type?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
interface GetSearchLocations extends GetRequestPagination {
|
|
||||||
name: string
|
|
||||||
}
|
|
||||||
|
|
||||||
async function getListLocationsService({ page, page_size }: GetListLocationsArg) {
|
async function getListLocationsService({ page, page_size }: GetListLocationsArg) {
|
||||||
const newState = { ...initialState };
|
const newState = { ...initialState };
|
||||||
const url = `${GET_LIST_LOCATIONS_URI}?page=${page}&page_size=${page_size}`
|
const url = `${GET_LIST_LOCATIONS_URI}?page=${page}&page_size=${page_size}`
|
||||||
@ -131,29 +126,8 @@ async function createLocationService(data: FormData): Promise<IHttpResponse> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function getSearchLocationService(arg: GetSearchLocations): Promise<IHttpResponse> {
|
|
||||||
const newState: IHttpResponse = { data: null, error: null};
|
|
||||||
|
|
||||||
try {
|
|
||||||
const response = await client({
|
|
||||||
method: 'GET',
|
|
||||||
url: `${GET_SEARCH_LOCATIONS_URI}?name=${arg.name}&limit=${arg.page_size}&offset=${arg.page}`
|
|
||||||
})
|
|
||||||
|
|
||||||
newState.data = response.data;
|
|
||||||
newState.status = response.status;
|
|
||||||
return newState;
|
|
||||||
} catch(error) {
|
|
||||||
const err = error as AxiosError;
|
|
||||||
newState.error = err;
|
|
||||||
newState.status = err.status;
|
|
||||||
return newState;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
getListLocationsService,
|
getListLocationsService,
|
||||||
getSearchLocationService,
|
|
||||||
getListRecentLocationsRatingsService,
|
getListRecentLocationsRatingsService,
|
||||||
getListTopLocationsService,
|
getListTopLocationsService,
|
||||||
getLocationTagsService,
|
getLocationTagsService,
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import { AxiosError } from "axios"
|
import { AxiosError } from "axios"
|
||||||
import { client } from "./config";
|
import { client } from "./config";
|
||||||
import { GET_CURRENT_USER_REVIEW_LOCATION_URI, POST_REVIEW_LOCATION_URI } from "../constants/api";
|
import { GET_CURRENT_USER_REVIEW_LOCATION_URI, POST_REVIEW_LOCATION_URI } from "../constants/api";
|
||||||
import { IHttpResponse } from "src/types/common";
|
|
||||||
|
|
||||||
const initialState: IHttpResponse = {
|
const initialState: IHttpResponse = {
|
||||||
data: null,
|
data: null,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// https://medium.com/geekculture/usecallbackstate-the-hook-that-let-you-run-code-after-a-setstate-operation-finished-25f40db56661
|
// https://medium.com/geekculture/usecallbackstate-the-hook-that-let-you-run-code-after-a-setstate-operation-finished-25f40db56661
|
||||||
import { useEffect, useRef, useState } from "preact/compat";
|
import { useEffect, useRef, useState } from "react";
|
||||||
|
|
||||||
type CallBackType<T> = (updatedValue: T) => void;
|
type CallBackType<T> = (updatedValue: T) => void;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { useEffect } from "preact/compat";
|
import { useEffect } from "react";
|
||||||
|
|
||||||
// Updates the height of a <textarea> when the value changes.
|
// Updates the height of a <textarea> when the value changes.
|
||||||
const useAutosizeTextArea = (
|
const useAutosizeTextArea = (
|
||||||
|
Loading…
Reference in New Issue
Block a user