Compare commits
No commits in common. "00c8831dc92b8215decee2863bcc2ad16c2ac277" and "0295d18574c47152b3883bc739248f31c741fd12" have entirely different histories.
00c8831dc9
...
0295d18574
package.jsontailwind.config.jsyarn.lock
src
actions
app.tsxcomponents
constants
features
index.csspages
reducers
routes
services
store
types
utils
11
package.json
11
package.json
@ -9,20 +9,9 @@
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"dependencies": {
|
||||
"@reduxjs/toolkit": "^1.9.5",
|
||||
"@types/react-redux": "^7.1.26",
|
||||
"axios": "^1.5.0",
|
||||
"emojibase": "^15.0.0",
|
||||
"interweave": "^13.1.0",
|
||||
"interweave-autolink": "^5.1.0",
|
||||
"interweave-emoji": "^7.0.0",
|
||||
"moment": "^2.29.4",
|
||||
"preact": "^10.16.0",
|
||||
"react": "^18.2.0",
|
||||
"react-redux": "^8.1.2",
|
||||
"react-router-dom": "^6.16.0",
|
||||
"redux-persist": "^6.0.0",
|
||||
"redux-thunk": "^2.4.2",
|
||||
"yet-another-react-lightbox": "^3.12.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -1,5 +0,0 @@
|
||||
import { LOGOUT } from "../constants/actions";
|
||||
|
||||
export const logout = () => ({
|
||||
type: LOGOUT
|
||||
});
|
@ -1 +0,0 @@
|
||||
export * from "./LogoutAction";
|
12
src/app.tsx
12
src/app.tsx
@ -4,22 +4,15 @@ import './app.css'
|
||||
import { DefaultLayout } from './layouts'
|
||||
import routes from './routes'
|
||||
import "yet-another-react-lightbox/styles.css";
|
||||
import { Login, NotFound } from './pages'
|
||||
import { Provider } from 'react-redux'
|
||||
import { persistore, store } from './store/config'
|
||||
import { PersistGate } from 'redux-persist/integration/react'
|
||||
|
||||
|
||||
export function App() {
|
||||
return (
|
||||
<>
|
||||
<Provider store={store}>
|
||||
<PersistGate persistor={persistore}>
|
||||
<Router>
|
||||
<Routes>
|
||||
<Route path='/login' element={<Login />} />
|
||||
<Route element={<DefaultLayout />}>
|
||||
{routes.map(({ path, name, element }) => (
|
||||
{routes.map(({ path, name, element}) => (
|
||||
<>
|
||||
<Route
|
||||
path={path}
|
||||
@ -29,11 +22,8 @@ export function App() {
|
||||
</>
|
||||
))}
|
||||
</Route>
|
||||
<Route path="*" element={<NotFound />} />
|
||||
</Routes>
|
||||
</Router>
|
||||
</PersistGate>
|
||||
</Provider>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
@ -1,64 +0,0 @@
|
||||
import { stripHexcode } from 'emojibase';
|
||||
import { InterweaveProps, FilterInterface, MatcherInterface, Interweave } from 'interweave';
|
||||
import { IpMatcher, UrlMatcher, EmailMatcher, HashtagMatcher } from 'interweave-autolink';
|
||||
import { EmojiMatcher, PathConfig } from 'interweave-emoji';
|
||||
|
||||
const globalFilters: FilterInterface[] = [];
|
||||
|
||||
const globalMatchers: MatcherInterface[] = [
|
||||
new EmailMatcher('email'),
|
||||
new IpMatcher('ip'),
|
||||
new UrlMatcher('url'),
|
||||
new HashtagMatcher('hashtag'),
|
||||
new EmojiMatcher('emoji', {
|
||||
convertEmoticon: true,
|
||||
convertShortcode: true,
|
||||
convertUnicode: true,
|
||||
}),
|
||||
];
|
||||
|
||||
function getEmojiPath(hexcode: string, { enlarged }: PathConfig): string {
|
||||
return `//cdn.jsdelivr.net/emojione/assets/3.1/png/${enlarged ? 64 : 32}/${stripHexcode(
|
||||
hexcode,
|
||||
).toLowerCase()}.png`;
|
||||
}
|
||||
|
||||
interface Props extends InterweaveProps {
|
||||
instagram?: boolean;
|
||||
twitter?: boolean;
|
||||
}
|
||||
|
||||
export default function CustomInterweave({
|
||||
filters = [],
|
||||
matchers = [],
|
||||
twitter,
|
||||
instagram,
|
||||
...props
|
||||
}: Props) {
|
||||
let hashtagUrl = '';
|
||||
|
||||
if (twitter) {
|
||||
hashtagUrl = 'https://twitter.com/hashtag/{{hashtag}}';
|
||||
} else if (instagram) {
|
||||
hashtagUrl = 'https://instagram.com/explore/tags/{{hashtag}}';
|
||||
}
|
||||
|
||||
return (
|
||||
<Interweave
|
||||
filters={[...globalFilters, ...filters]}
|
||||
matchers={[...globalMatchers, ...matchers]}
|
||||
// hashtagUrl={hashtagUrl}
|
||||
emojiSource={getEmojiPath}
|
||||
// newWindow
|
||||
{...props}
|
||||
/>
|
||||
// <BaseInterweave
|
||||
// filters={[...globalFilters, ...filters]}
|
||||
// matchers={[...globalMatchers, ...matchers]}
|
||||
// hashtagUrl={hashtagUrl}
|
||||
// emojiPath={getEmojiPath}
|
||||
// newWindow
|
||||
// {...props}
|
||||
// />
|
||||
);
|
||||
}
|
@ -1,37 +1,18 @@
|
||||
import React, { TargetedEvent } from "preact/compat";
|
||||
import React from "preact/compat";
|
||||
import { useState } from "preact/hooks";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { UserRootState } from "../../store/type";
|
||||
import { logout } from '../../actions';
|
||||
import './style.css';
|
||||
import { logoutService } from "../../services";
|
||||
|
||||
|
||||
function Header() {
|
||||
|
||||
const [searchVal, setSearchVal] = useState('');
|
||||
const [dropdown, setDropdown] = useState(false);
|
||||
const [pageState, setPageState] = useState({
|
||||
profileMenu: false
|
||||
})
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const user = useSelector((state: UserRootState) => state.auth)
|
||||
|
||||
const onInput = (e: React.ChangeEvent<HTMLInputElement>): void => {
|
||||
const val = e.target as HTMLInputElement;
|
||||
setSearchVal(val.value)
|
||||
}
|
||||
|
||||
const handleLogout = async (): Promise<void> => {
|
||||
try {
|
||||
await logoutService()
|
||||
dispatch(logout())
|
||||
location.reload()
|
||||
} catch (error) {
|
||||
alert(error)
|
||||
}
|
||||
}
|
||||
|
||||
const onSearchSubmit = (e: React.TargetedEvent<HTMLFormElement>): void => {
|
||||
e.preventDefault();
|
||||
}
|
||||
@ -39,7 +20,7 @@ function Header() {
|
||||
const onDropdown = (): void => {
|
||||
document.body.style.overflow = "hidden"
|
||||
|
||||
if (dropdown) {
|
||||
if(dropdown) {
|
||||
document.body.style.overflowX = "hidden";
|
||||
document.body.style.overflowY = "scroll";
|
||||
}
|
||||
@ -52,25 +33,6 @@ function Header() {
|
||||
<a href={"/"}>
|
||||
<h1 className={`title ${dropdown ? 'title-dropdown' : ""}`}>Hilingin</h1>
|
||||
</a>
|
||||
<div className={'user-img self-center mr-5'} style={dropdown ? { display: 'none' } : ''}>
|
||||
<a href={user.username ? '#' : '/login'} onClick={() => user.username ? setPageState({ ...pageState, profileMenu: !pageState.profileMenu }) : ''}>
|
||||
<img
|
||||
loading={'lazy'}
|
||||
style={{ width: 40, borderRadius: 15 }}
|
||||
src={'https://cdn.discordapp.com/attachments/743422487882104837/1153985664849805392/421-4212617_person-placeholder-image-transparent-hd-png-download.png'}
|
||||
/>
|
||||
</a>
|
||||
{user.username &&
|
||||
<div className={'profile-dropdown-img bg-secondary text-left'} style={pageState.profileMenu ? { display: 'block'} : { display: 'none'}}>
|
||||
<a href={'#'}><div className={'p-2'}>Profile</div></a>
|
||||
<a href={'#'}><div className={'p-2'}>Feed</div></a>
|
||||
<a href={'#'}><div className={'p-2'}>Add location</div></a>
|
||||
<a href={'#'} onClick={handleLogout}><div className={'p-2'}>Logout</div></a>
|
||||
{/* <div className={'p-2'}><a href={'#'}>Halo</a></div> */}
|
||||
{/* <div className={'p-2'}><a href={'#'}>Halo</a></div> */}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<form onSubmit={onSearchSubmit} className={`search-input ${dropdown ? "search-input-dropdown" : ""}`}>
|
||||
<label>
|
||||
<input
|
||||
@ -82,7 +44,7 @@ function Header() {
|
||||
/>
|
||||
</label>
|
||||
</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" style={{ padding: 5, margin: 'auto 0', borderRadius: 10, marginLeft: 'auto' }}>
|
||||
<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>
|
||||
</button>
|
||||
</div>
|
||||
@ -92,22 +54,11 @@ function Header() {
|
||||
}
|
||||
<a href="/best-places" className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>Top Places</a>
|
||||
<a href="/discover" className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>Discover</a>
|
||||
<a href="#" className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>Trending Places</a>
|
||||
<a href="/stories" className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>Stories</a>
|
||||
<a href="/news-events" className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>News / Events</a>
|
||||
<a href="#" className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>Forum</a>
|
||||
<div className={'profile-container'}>
|
||||
<a href={user.username ? '#' : '/login'} onClick={() => user.username ? setPageState({ ...pageState, profileMenu: !pageState.profileMenu }) : ''} className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>{user.username ? user.username : 'Sign in'}</a>
|
||||
{user && screen.width > 600 &&
|
||||
<div className={'profile-dropdown bg-secondary ml-6'} style={pageState.profileMenu ? { display: 'block' } : {display: 'none'}}>
|
||||
<a href={'#'}><div className={'p-1'}>Profile</div></a>
|
||||
<a href={'#'}><div className={'p-1'}>Feed</div></a>
|
||||
<a href={'#'}><div className={'p-1'}>Add location</div></a>
|
||||
<a href={'#'} onClick={handleLogout}><div className={'p-1'}>Logout</div></a>
|
||||
{/* <div className={'p-2'}><a href={'#'}>Halo</a></div> */}
|
||||
{/* <div className={'p-2'}><a href={'#'}>Halo</a></div> */}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<a href="#" className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>Sign in</a>
|
||||
</div>
|
||||
</header>
|
||||
)
|
||||
|
@ -1,7 +1,74 @@
|
||||
@media screen and (max-width: 768px) {
|
||||
a.navLink {
|
||||
font-size: 12px;
|
||||
padding: 0px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 488px) {
|
||||
a.navLink{
|
||||
/* display: none; */
|
||||
margin-top: 10px;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
border-bottom: 1px solid white;
|
||||
padding: 10px 0
|
||||
}
|
||||
|
||||
div.nav-container {
|
||||
padding: 0 20px;
|
||||
height: 100vh;
|
||||
/* align-items: start; */
|
||||
justify-content: start;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
div.nav-container-disabled {
|
||||
padding: 4px;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
a.navLink-disabled {
|
||||
display: none;
|
||||
}
|
||||
|
||||
form.search-input {
|
||||
display: none;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
button.dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.search-input-dropdown {
|
||||
margin-right: 10px;
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
h1.title-dropdown {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a.navLink:hover{
|
||||
border-bottom-width: 1px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 390px){
|
||||
input.text-input-search {
|
||||
width: 230px;
|
||||
}
|
||||
}
|
||||
|
||||
.dropdown-menu {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.search-input {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
label {
|
||||
position: relative;
|
||||
@ -35,33 +102,6 @@ label:before {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.profile-dropdown {
|
||||
display: block;
|
||||
position: absolute;
|
||||
padding: 5px;
|
||||
width: 135px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.profile-dropdown a div:hover {
|
||||
background-color: #a8adb3;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.profile-dropdown-img {
|
||||
position: absolute;
|
||||
font-size: 13px;
|
||||
padding: 5px;
|
||||
margin-top: 5px;
|
||||
right: 70px;
|
||||
width: 130px;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.profile-dropdown-img a div:hover {
|
||||
background-color: #a8adb3;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.nav-container {
|
||||
background-color: #2f3136;
|
||||
@ -75,90 +115,3 @@ label:before {
|
||||
max-width: '100%';
|
||||
text-align: 'center'; */
|
||||
}
|
||||
|
||||
.search-input {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.user-img {
|
||||
display: none;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@media screen and (max-width: 768px) {
|
||||
a.navLink {
|
||||
font-size: 12px;
|
||||
padding: 0px 20px;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 488px) {
|
||||
a.navLink{
|
||||
/* display: none; */
|
||||
margin-top: 10px;
|
||||
width: 100%;
|
||||
padding: 0;
|
||||
border-bottom: 1px solid white;
|
||||
padding: 10px 0
|
||||
}
|
||||
|
||||
.profile-container {
|
||||
display: none;
|
||||
}
|
||||
|
||||
div.nav-container {
|
||||
padding: 0 20px;
|
||||
height: 100vh;
|
||||
/* align-items: start; */
|
||||
justify-content: start;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
div.nav-container-disabled {
|
||||
padding: 4px;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
a.navLink-disabled {
|
||||
display: none;
|
||||
}
|
||||
|
||||
form.search-input {
|
||||
display: none;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
div.user-img {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
button.dropdown-menu {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.search-input-dropdown {
|
||||
margin-right: 10px;
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
h1.title-dropdown {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a.navLink:hover{
|
||||
border-bottom-width: 1px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.user-img .profile-dropdown-img {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
|
||||
@media screen and (max-width: 390px){
|
||||
input.text-input-search {
|
||||
width: 230px;
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +0,0 @@
|
||||
import './style.css'
|
||||
export default function SpinnerLoading() {
|
||||
return (
|
||||
<div className={'spinner'} style={{ display: 'inline-block'}}></div>
|
||||
)
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
@keyframes spinner {
|
||||
to {transform: rotate(360deg);}
|
||||
}
|
||||
|
||||
.spinner:before {
|
||||
content: '';
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border-radius: 50%;
|
||||
border: 2px solid #ccc;
|
||||
border-top-color: #000;
|
||||
animation: spinner .7s linear infinite;
|
||||
}
|
@ -2,16 +2,10 @@ import Header from "./Header";
|
||||
import SeparatorWithAnchor from "./Separator/WithAnchor";
|
||||
import DefaultSeparator from "./Separator/Default";
|
||||
import Footer from './Footer/';
|
||||
import CustomInterweave from "./CustomInterweave";
|
||||
|
||||
import SpinnerLoading from "./Loading/Spinner";
|
||||
|
||||
export {
|
||||
Header,
|
||||
SeparatorWithAnchor,
|
||||
DefaultSeparator,
|
||||
Footer,
|
||||
CustomInterweave,
|
||||
|
||||
SpinnerLoading,
|
||||
Footer
|
||||
}
|
@ -1 +0,0 @@
|
||||
export const LOGOUT = 'LOGOUT';
|
@ -1,8 +1,7 @@
|
||||
const BASE_URL = "http://localhost:8888"
|
||||
|
||||
const SIGNUP_URI = `${BASE_URL}/user/signup`
|
||||
const LOGIN_URI = `${BASE_URL}/user/login`
|
||||
const LOGOUT_URI = `${BASE_URL}/user/logout`
|
||||
|
||||
|
||||
const GET_LIST_LOCATIONS_URI = `${BASE_URL}/locations`;
|
||||
const GET_LIST_TOP_LOCATIONS = `${BASE_URL}/locations/top-ratings`
|
||||
@ -12,18 +11,13 @@ const GET_LOCATION_TAGS_URI = `${BASE_URL}/location/tags`
|
||||
|
||||
const GET_IMAGES_BY_LOCATION_URI = `${BASE_URL}/images/location`
|
||||
|
||||
const POST_REVIEW_LOCATION_URI = `${BASE_URL}/review/location`
|
||||
|
||||
export {
|
||||
BASE_URL,
|
||||
SIGNUP_URI,
|
||||
LOGIN_URI,
|
||||
LOGOUT_URI,
|
||||
GET_LIST_RECENT_LOCATIONS_RATING_URI,
|
||||
GET_LIST_TOP_LOCATIONS,
|
||||
GET_LIST_LOCATIONS_URI,
|
||||
GET_LOCATION_URI,
|
||||
GET_LOCATION_TAGS_URI,
|
||||
GET_IMAGES_BY_LOCATION_URI,
|
||||
POST_REVIEW_LOCATION_URI
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
export const DEFAULT_AVATAR_IMG = 'https://cdn.discordapp.com/attachments/743422487882104837/1153985664849805392/421-4212617_person-placeholder-image-transparent-hd-png-download.png';
|
||||
|
@ -1,20 +0,0 @@
|
||||
import { createSlice } from "@reduxjs/toolkit";
|
||||
|
||||
const initialState = {}
|
||||
|
||||
const authSlice = createSlice({
|
||||
name: 'auth',
|
||||
initialState,
|
||||
reducers: {
|
||||
authAdded(state, action) {
|
||||
const current_user = action.payload;
|
||||
let newState = { ...state }
|
||||
newState = current_user
|
||||
return newState
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export const { authAdded } = authSlice.actions;
|
||||
|
||||
export default authSlice.reducer;
|
@ -1,14 +0,0 @@
|
||||
export interface IUser {
|
||||
id: Number,
|
||||
email: String,
|
||||
username: String,
|
||||
avatar_picture: String,
|
||||
banned_at: NullValueRes<"Time", String>,
|
||||
banned_until: NullValueRes<"Time", String>,
|
||||
ban_reason: String,
|
||||
is_permaban: boolean,
|
||||
is_admin: boolean,
|
||||
is_critics: boolean,
|
||||
is_verfied: boolean,
|
||||
social_media: NullValueRes<"RawMessage", any>
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
import authSlice from "./auth/authSlice/authSlice";
|
||||
|
||||
export {
|
||||
authSlice
|
||||
}
|
@ -18,13 +18,6 @@
|
||||
-webkit-text-size-adjust: 100%;
|
||||
}
|
||||
|
||||
input:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
cursor: pointer;
|
||||
}
|
||||
/* a {
|
||||
font-weight: 500;
|
||||
color: #646cff;
|
||||
|
@ -3,6 +3,8 @@ import { getListTopLocationsService } from "../../services";
|
||||
import { DefaultSeparator } from "../../components";
|
||||
import { TargetedEvent } from "preact/compat";
|
||||
import './style.css';
|
||||
import { useNavigate } from "react-router-dom";
|
||||
|
||||
|
||||
interface TopLocation {
|
||||
row_number: Number,
|
||||
@ -55,6 +57,8 @@ function BestLocation() {
|
||||
filterRegionType: 0,
|
||||
})
|
||||
|
||||
const navigate = useNavigate()
|
||||
|
||||
async function getTopLocations() {
|
||||
try {
|
||||
const res = await getListTopLocationsService({ page: page, page_size: 20, order_by: pageState.filterScoreTypeidx, region_type: pageState.filterRegionType })
|
||||
@ -75,6 +79,18 @@ function BestLocation() {
|
||||
setPageState({ ...pageState, filterRegionTypeName: region_name, filterRegionType: type})
|
||||
}
|
||||
|
||||
function onNavigateToDetail(
|
||||
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(() => {
|
||||
getTopLocations()
|
||||
}, [pageState])
|
||||
@ -136,10 +152,10 @@ function BestLocation() {
|
||||
</a>
|
||||
</div> */}
|
||||
<div className={'mb-2 best-locations-title'}>
|
||||
<a className={'text-xl'} href={`/location/${x.id}`}>{x.row_number}.{x.name}</a>
|
||||
<a className={'text-xl'} href={`/location/${x.id}`} onClick={() => onNavigateToDetail(x.id, x.critic_count, x.critic_score, x.user_count, x.user_score)}>{x.row_number}.{x.name}</a>
|
||||
</div>
|
||||
<div style={{ maxWidth: 200, maxHeight: 200, margin: '0 30px 30px 10px', float: 'left' }}>
|
||||
<a href={`/location/${x.id}`} >
|
||||
<a href={`/location/${x.id}`} onClick={() => onNavigateToDetail(x.id, x.critic_count, x.critic_score, x.user_count, x.user_score)}>
|
||||
<img src={x.thumbnail.String.toString()} loading={'lazy'} style={{ width: '100%', objectFit: 'cover', height: '100%', aspectRatio: '1/1' }} />
|
||||
</a>
|
||||
</div>
|
||||
|
@ -67,11 +67,6 @@ img {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.text-area-button {
|
||||
background-color: gray;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
|
||||
.criticSortFilter {
|
||||
float: right;
|
||||
}
|
||||
|
@ -1,43 +1,22 @@
|
||||
import { useNavigate, useParams } from 'react-router-dom';
|
||||
import { useLocation, useParams } from 'react-router-dom';
|
||||
import { ChangeEvent, TargetedEvent } from 'preact/compat';
|
||||
import { useEffect, useRef, useState } from 'preact/hooks';
|
||||
import './index.css';
|
||||
import Lightbox from 'yet-another-react-lightbox';
|
||||
import useCallbackState from '../../types/state-callback';
|
||||
import {
|
||||
EmptyLocationDetailResponse,
|
||||
LocationDetailResponse,
|
||||
LocationResponse,
|
||||
emptyLocationResponse,
|
||||
CurrentUserLocationReviews,
|
||||
} from './types';
|
||||
import { handleAxiosError, useAutosizeTextArea } from '../../utils';
|
||||
import { getImagesByLocationService, getLocationService, postReviewLocation } from "../../services";
|
||||
import { DefaultSeparator, SeparatorWithAnchor, CustomInterweave, SpinnerLoading } from '../../components';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { UserRootState } from '../../store/type';
|
||||
import { DEFAULT_AVATAR_IMG } from '../../constants/default';
|
||||
import './index.css';
|
||||
import { AxiosError } from 'axios';
|
||||
|
||||
const SORT_TYPE = [
|
||||
'highest rated',
|
||||
'lowest rated',
|
||||
'newest',
|
||||
'oldest'
|
||||
]
|
||||
import { EmptyLocationDetailResponse, LocationDetailResponse, LocationResponse, emptyLocationResponse } from './types';
|
||||
import { useAutosizeTextArea } from '../../utils';
|
||||
import { getImagesByLocationService, getLocationService } from "../../services";
|
||||
import { DefaultSeparator, SeparatorWithAnchor } from '../../components';
|
||||
|
||||
function LocationDetail() {
|
||||
const [locationDetail, setLocationDetail] = useCallbackState<LocationDetailResponse>(EmptyLocationDetailResponse)
|
||||
const [locationImages, setLocationImages] = useState<LocationResponse>(emptyLocationResponse())
|
||||
const [currentUserReview, setCurrentUserReview] = useState<CurrentUserLocationReviews>()
|
||||
const [lightboxOpen, setLightboxOpen] = useState<boolean>(false)
|
||||
const [pageState, setPageState] = useState({
|
||||
critic_filter_name: 'highest rated',
|
||||
critic_filter_type: 0,
|
||||
show_sort: false,
|
||||
enable_post: true,
|
||||
on_submit_loading: false,
|
||||
is_score_rating_panic_msg: '',
|
||||
show_sort: false
|
||||
})
|
||||
const [reviewValue, setReviewValue] = useState({
|
||||
review_textArea: '',
|
||||
@ -45,27 +24,28 @@ function LocationDetail() {
|
||||
})
|
||||
const [isLoading, setIsLoading] = useState<boolean>(true)
|
||||
|
||||
const navigate = useNavigate();
|
||||
const user = useSelector((state: UserRootState) => state.auth)
|
||||
|
||||
|
||||
const textAreaRef = useRef<HTMLTextAreaElement>(null);
|
||||
useAutosizeTextArea(textAreaRef.current, reviewValue.review_textArea);
|
||||
|
||||
const { state } = useLocation();
|
||||
const { id } = useParams()
|
||||
|
||||
const SORT_TYPE = [
|
||||
'highest rated',
|
||||
'lowest rated',
|
||||
'newest',
|
||||
'oldest'
|
||||
]
|
||||
|
||||
async function getLocationDetail(): Promise<void> {
|
||||
try {
|
||||
const res = await getLocationService(Number(id))
|
||||
setLocationDetail(res.data, (val) => {
|
||||
getImage(val.detail.thumbnail.String.toString())
|
||||
})
|
||||
} catch (error) {
|
||||
let err = error as AxiosError;
|
||||
if (err.response?.status == 404) {
|
||||
navigate("/")
|
||||
}
|
||||
alert(error)
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
@ -96,75 +76,11 @@ function LocationDetail() {
|
||||
...reviewValue,
|
||||
score_input: val.value
|
||||
})
|
||||
|
||||
setPageState({
|
||||
...pageState,
|
||||
is_score_rating_panic_msg: ''
|
||||
})
|
||||
}
|
||||
|
||||
function onChangeCriticsSort(e: TargetedEvent<HTMLAnchorElement>, sort_name: string, sort_type: number): void {
|
||||
e.preventDefault()
|
||||
setPageState({ ...pageState, show_sort: false, critic_filter_name: sort_name, critic_filter_type: sort_type })
|
||||
}
|
||||
|
||||
async function handleSubmitReview(e: TargetedEvent<HTMLAnchorElement>) {
|
||||
e.preventDefault();
|
||||
setPageState({ ...pageState, on_submit_loading: true })
|
||||
|
||||
if (isNaN(Number(reviewValue.score_input))) {
|
||||
setPageState({ ...pageState, is_score_rating_panic_msg: "SCORE MUST BE A NUMBER" })
|
||||
return
|
||||
}
|
||||
|
||||
if (Number(reviewValue.score_input) > 100) {
|
||||
setPageState({ ...pageState, is_score_rating_panic_msg: "SCORE MUST BE LESS OR EQUAL THAN 100" })
|
||||
return
|
||||
}
|
||||
|
||||
if (reviewValue.score_input === '') {
|
||||
setPageState({ ...pageState, is_score_rating_panic_msg: "SCORE MUSTN'T BE EMPTY" })
|
||||
return
|
||||
}
|
||||
|
||||
try {
|
||||
const { data } = await postReviewLocation({
|
||||
is_hided: false,
|
||||
location_id: Number(id),
|
||||
score: Number(reviewValue.score_input),
|
||||
submitted_by: Number(user.id),
|
||||
is_from_critic: user.is_critics,
|
||||
comments: reviewValue.review_textArea,
|
||||
})
|
||||
|
||||
setPageState({ ...pageState, enable_post: false, on_submit_loading: false })
|
||||
setReviewValue({ review_textArea: '', score_input: '' })
|
||||
setCurrentUserReview({
|
||||
id: data.id,
|
||||
comments: data.comments,
|
||||
is_from_critic: data.is_from_critic,
|
||||
is_hided: data.is_hided,
|
||||
location_id: data.location_id,
|
||||
score: data.score,
|
||||
submitted_by: data.submitted_by,
|
||||
created_at: data.created_at,
|
||||
updated_at: data.updated_at
|
||||
})
|
||||
} catch (error) {
|
||||
let err = error as AxiosError;
|
||||
console.log(err)
|
||||
const str = handleAxiosError(err)
|
||||
alert(str)
|
||||
setPageState({ ...pageState, on_submit_loading: false })
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function handleSignInNavigation(e: TargetedEvent<HTMLAnchorElement>) {
|
||||
e.preventDefault();
|
||||
|
||||
|
||||
navigate('/login', { state: { from: `/location/${id}` } })
|
||||
setPageState({ show_sort: false, critic_filter_name: sort_name, critic_filter_type: sort_type })
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@ -221,36 +137,36 @@ function LocationDetail() {
|
||||
<div className={'p-4 bg-secondary mt-3'} style={{ width: '100%', height: 120, borderTopLeftRadius: 10, borderTopRightRadius: 10 }}>
|
||||
<div className={'font-bold ml-1 text-xs'}>CRITICS SCORE</div>
|
||||
<div className={'text-4xl text-center mt-2 mr-4'} style={{ width: 95, float: 'left' }}>
|
||||
{locationDetail.detail.critic_count !== 0 ? Math.floor(Number(locationDetail.detail.critic_score) / Number(locationDetail.detail.critic_count)) : "NR"}
|
||||
{state.critic_count !== 0 ? state.critic_score : "NR"}
|
||||
<div className={"items-center p-2"}>
|
||||
<div className={'mr-3 users-score-bar'}>
|
||||
<div className={"mt-1"} style={{ height: 4, width: 80, backgroundColor: "#72767d" }}>
|
||||
<div style={{ height: 4, width: ` ${locationDetail.detail.critic_count !== 0 ? Number(locationDetail.detail.critic_score) : 0}%`, backgroundColor: 'green' }} />
|
||||
<div style={{ height: 4, width: ` ${state.critic_count !== 0 ? Number(state.critic_score) / Number(state.critic_count) * 10 : 0}%`, backgroundColor: 'green' }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{locationDetail.detail.critic_count !== 0 &&
|
||||
{state.critic_count !== 0 &&
|
||||
<div className={'ml-14 text-sm'}>
|
||||
Based on {locationDetail.detail.critic_count} reviews
|
||||
Based on {state.critic_count} reviews
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div className={'p-4 bg-secondary mt-1 inline-block'} style={{ width: '100%', height: 120, borderBottomLeftRadius: 10, borderBottomRightRadius: 10 }}>
|
||||
<div className={'font-bold ml-2 text-xs'}>USERS SCORE</div>
|
||||
<div className={'text-4xl text-center mt-2 mr-4'} style={{ width: 95, float: 'left' }}>
|
||||
{locationDetail.detail.user_count !== 0 ? Math.floor(Number(locationDetail.detail.user_score) / Number(locationDetail.detail.user_count)) : "NR"}
|
||||
<div className={'text-4xl text-center mt-2'} style={{ width: 95, float: 'left' }}>
|
||||
{state.user_count !== 0 ? state.user_score : "NR"}
|
||||
<div className={"items-center p-2"}>
|
||||
<div className={'mr-3 users-score-bar'}>
|
||||
<div className={"mt-1"} style={{ height: 4, width: 80, backgroundColor: "#72767d" }}>
|
||||
<div style={{ height: 4, width: ` ${locationDetail.detail.user_count !== 0 ? Number(locationDetail.detail.user_score) / Number(locationDetail.detail.user_count) : 0}%`, backgroundColor: 'green' }} />
|
||||
<div style={{ height: 4, width: ` ${state.user_count !== 0 ? Number(state.user_score) / Number(state.user_score) * 10 : 0}%`, backgroundColor: 'green' }} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{locationDetail.detail.user_count !== 0 &&
|
||||
<div className={'ml-14 text-sm'}>
|
||||
Based on {locationDetail.detail.user_count} reviews
|
||||
{state.user_count !== 0 &&
|
||||
<div className={'ml-4'}>
|
||||
Based on {state.user_count} reviews
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
@ -296,33 +212,23 @@ function LocationDetail() {
|
||||
<section name={'REVIEWS SECTION'}>
|
||||
<div className={'mt-5'} style={{ tableLayout: 'fixed', display: 'table', width: '100%' }}>
|
||||
<div className={'wideLeft'} style={{ textAlign: 'left', paddingRight: 20, maxWidth: 1096, minWidth: 680, display: 'table-cell', position: 'relative', verticalAlign: 'top', width: '100%', boxSizing: 'border-box' }}>
|
||||
{!user.username ?
|
||||
<div className={'bg-secondary text-center p-3'} style={{ width: '100%' }}><a href={'#'} onClick={handleSignInNavigation} style={{ borderBottom: '1px solid white' }}>SIGN IN</a> TO REVIEW</div>
|
||||
:
|
||||
|
||||
{/* <div className={'bg-secondary text-center p-3'} style={{ width: '100%'}}><a href={'#'}>SIGN IN</a> TO REVIEW</div> */}
|
||||
<div name="REVIEW INPUT TEXTAREA" className={'reviewContainer p-4'} style={{ backgroundColor: '#2f3136' }}>
|
||||
<div className={'reviewBoxContent'} style={{ width: '75%', margin: '0 auto' }}>
|
||||
|
||||
<div className={'userImage mr-3'} style={{ width: 55, float: 'left' }}>
|
||||
<a href={'#'}>
|
||||
<img loading={'lazy'} src={user.avatar_picture != '' ? user.avatar_picture.toString() : DEFAULT_AVATAR_IMG} style={{ aspectRatio: '1/1' }} />
|
||||
<img loading={'lazy'} src={'https://cdn.discordapp.com/attachments/743422487882104837/1153985664849805392/421-4212617_person-placeholder-image-transparent-hd-png-download.png'} />
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div style={{ display: 'block' }}>
|
||||
<a href={'#'}>{user.username}</a>
|
||||
<a href={'#'}>user</a>
|
||||
</div>
|
||||
|
||||
<div className={'ratingInput'} style={currentUserReview ? { margin: '0 0 10px' } : { margin: '5px 0 10px' }}>
|
||||
{currentUserReview ?
|
||||
<div style={{ display: 'inline-block' }}>
|
||||
{console.log(currentUserReview)}
|
||||
<p className={'ml-2'}>{currentUserReview.score}</p>
|
||||
<div style={{ height: 4, width: 35, backgroundColor: "#72767d" }}>
|
||||
<div style={{ height: 4, width: `${currentUserReview.score}%`, backgroundColor: 'green' }} />
|
||||
</div>
|
||||
</div>
|
||||
:
|
||||
<>
|
||||
<div className={'ratingInput'} style={{ margin: '5px 0 10px' }}>
|
||||
<div style={{ float: 'left' }}>
|
||||
<input
|
||||
type={'text'}
|
||||
pattern={"\d*"}
|
||||
@ -334,21 +240,11 @@ function LocationDetail() {
|
||||
autoComplete={'off'}
|
||||
/>
|
||||
<div className={'inline-block text-xs ml-2 text-tertiary'}>/ score</div>
|
||||
{pageState.is_score_rating_panic_msg &&
|
||||
<div className={'inline-block text-xs ml-2 text-error'}>{pageState.is_score_rating_panic_msg}</div>
|
||||
}
|
||||
</>
|
||||
|
||||
}
|
||||
</div>
|
||||
<div style={{ clear: 'both' }} />
|
||||
</div>
|
||||
|
||||
<div className={'mt-3'} style={{ width: '100%' }}>
|
||||
{currentUserReview ?
|
||||
<CustomInterweave
|
||||
content={currentUserReview.comments}
|
||||
/>
|
||||
:
|
||||
<textarea
|
||||
onChange={handleTextAreaChange}
|
||||
ref={textAreaRef}
|
||||
@ -356,27 +252,21 @@ function LocationDetail() {
|
||||
value={reviewValue.review_textArea}
|
||||
style={{ border: 'none', overflow: 'auto', outline: 'none', boxShadow: 'none', backgroundColor: '#40444b', width: '100%', minHeight: 100, overflowY: 'hidden' }}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
|
||||
<div style={{ textAlign: 'right', width: "100%" }}>
|
||||
<div style={{ display: 'inline-block', fontSize: 11, verticalAlign: 'middle', margin: '0 10px 0 0', letterSpacing: .5 }}>
|
||||
<a>Review Guidelines</a>
|
||||
</div>
|
||||
{pageState.on_submit_loading ?
|
||||
<SpinnerLoading />
|
||||
:
|
||||
<span className={'text-xxs p-1 text-area-button'} style={pageState.enable_post ? '' : { display: 'none'}}>
|
||||
<a href={'#'} onClick={handleSubmitReview}>
|
||||
<span className={'text-xxs p-1'} style={{ backgroundColor: 'gray', letterSpacing: 1 }}>
|
||||
<a href={'#'}>
|
||||
POST
|
||||
</a>
|
||||
</span>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
}
|
||||
<div name={'CRTICITS REVIEW'} style={{ margin: '50px 0', textAlign: 'left' }}>
|
||||
<SeparatorWithAnchor pageName={"critic's review"} pageLink='#' />
|
||||
<div className={'criticSortFilter'}>
|
||||
@ -393,14 +283,13 @@ function LocationDetail() {
|
||||
</div>
|
||||
<div style={{ clear: 'both' }} />
|
||||
|
||||
{locationDetail.critics_review.map(x => (
|
||||
<div className={''} style={{ padding: '15px 0' }}>
|
||||
<div style={{ float: 'left' }}>
|
||||
<div style={{ fontSize: 20, marginRight: 20, textAlign: 'center', width: 55, marginBottom: 3 }}>
|
||||
{x.score}
|
||||
90
|
||||
</div>
|
||||
<div style={{ height: 4, width: 55, position: 'relative', backgroundColor: '#d8d8d8' }}>
|
||||
<div style={{ height: 4, backgroundColor: '#85ce73', width: `${x.score}%` }} />
|
||||
<div style={{ height: 4, backgroundColor: '#85ce73', width: '90%' }} />
|
||||
</div>
|
||||
</div>
|
||||
<div className={'mr-3'} style={{ display: 'inline-block', width: 40 }}>
|
||||
@ -408,21 +297,19 @@ function LocationDetail() {
|
||||
<img
|
||||
loading={'lazy'}
|
||||
style={{ width: '100%' }}
|
||||
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'}
|
||||
src={'https://cdn.discordapp.com/attachments/743422487882104837/1153985664849805392/421-4212617_person-placeholder-image-transparent-hd-png-download.png'}
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div style={{ display: 'inline-block', verticalAlign: 'top' }}>
|
||||
<div style={{ fontWeight: 700, fontSize: 16, lineHeight: 'initial' }}>
|
||||
<a>
|
||||
<span>{x.username}</span>
|
||||
<span>Benito Mussolini</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ fontSize: 15, lineHeight: '24px', margin: '5px 75px 1px' }}>
|
||||
<CustomInterweave
|
||||
content={x.comments}
|
||||
/>
|
||||
<div style={{ fontSize: 15, lineHeight: '24px', margin: '5px 75px 1px', wordWrap: 'break-word' }}>
|
||||
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro nihil dolor delectus ex minima aliquid quidem veniam officiis temporibus ipsum ea incidunt voluptatum a, repellat illum, cumque consequatur saepe assumenda.</p>
|
||||
</div>
|
||||
<div className={'reviewLinks'} style={{ marginLeft: 72 }}>
|
||||
<div className={'mr-2'} style={{ minWidth: 55, display: 'inline-block', verticalAlign: 'middle' }}>
|
||||
@ -439,41 +326,166 @@ function LocationDetail() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<div className={''} style={{ padding: '15px 0', borderTop: '1px solid #38444d' }}>
|
||||
<div style={{ float: 'left' }}>
|
||||
<div style={{ fontSize: 20, marginRight: 20, textAlign: 'center', width: 55, marginBottom: 3 }}>
|
||||
90
|
||||
</div>
|
||||
<div style={{ height: 4, width: 55, position: 'relative', backgroundColor: '#d8d8d8' }}>
|
||||
<div style={{ height: 4, backgroundColor: '#85ce73', width: '90%' }} />
|
||||
</div>
|
||||
</div>
|
||||
<div className={'mr-3'} style={{ display: 'inline-block', width: 40 }}>
|
||||
<a href="#">
|
||||
<img
|
||||
loading={'lazy'}
|
||||
style={{ width: '100%' }}
|
||||
src={'https://cdn.discordapp.com/attachments/743422487882104837/1153985664849805392/421-4212617_person-placeholder-image-transparent-hd-png-download.png'}
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div style={{ display: 'inline-block', verticalAlign: 'top' }}>
|
||||
<div style={{ fontWeight: 700, fontSize: 16, lineHeight: 'initial' }}>
|
||||
<a>
|
||||
<span>Benito Mussolini</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ fontSize: 15, lineHeight: '24px', margin: '5px 75px 1px', wordWrap: 'break-word' }}>
|
||||
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro nihil dolor delectus ex minima aliquid quidem veniam officiis temporibus ipsum ea incidunt voluptatum a, repellat illum, cumque consequatur saepe assumenda.</p>
|
||||
</div>
|
||||
<div className={'reviewLinks'} style={{ marginLeft: 72 }}>
|
||||
<div className={'mr-2'} style={{ minWidth: 55, display: 'inline-block', verticalAlign: 'middle' }}>
|
||||
<a className={'text-sm'} href={'#'}>
|
||||
<svg className={'inline-block mr-1'} fill={'currentColor'} xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 -960 960 960"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h280v80H200v560h560v-280h80v280q0 33-23.5 56.5T760-120H200Zm188-212-56-56 372-372H560v-80h280v280h-80v-144L388-332Z" /></svg>
|
||||
<div className={'inline-block'}>Video</div>
|
||||
</a>
|
||||
</div>
|
||||
<div style={{ minWidth: 55, display: 'inline-block', verticalAlign: 'middle' }}>
|
||||
<a className={'text-sm'} href={'#'}>
|
||||
<svg className={'inline-block mr-1'} fill={'currentColor'} xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 -960 960 960"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h280v80H200v560h560v-280h80v280q0 33-23.5 56.5T760-120H200Zm188-212-56-56 372-372H560v-80h280v280h-80v-144L388-332Z" /></svg>
|
||||
<div className={'inline-block'}>Instagram</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className={''} style={{ padding: '15px 0', borderTop: '1px solid #38444d' }}>
|
||||
<div style={{ float: 'left' }}>
|
||||
<div style={{ fontSize: 20, marginRight: 20, textAlign: 'center', width: 55, marginBottom: 3 }}>
|
||||
90
|
||||
</div>
|
||||
<div style={{ height: 4, width: 55, position: 'relative', backgroundColor: '#d8d8d8' }}>
|
||||
<div style={{ height: 4, backgroundColor: '#85ce73', width: '90%' }} />
|
||||
</div>
|
||||
</div>
|
||||
<div className={'mr-3'} style={{ display: 'inline-block', width: 40 }}>
|
||||
<a href="#">
|
||||
<img
|
||||
loading={'lazy'}
|
||||
style={{ width: '100%' }}
|
||||
src={'https://cdn.discordapp.com/attachments/743422487882104837/1153985664849805392/421-4212617_person-placeholder-image-transparent-hd-png-download.png'}
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div style={{ display: 'inline-block', verticalAlign: 'top' }}>
|
||||
<div style={{ fontWeight: 700, fontSize: 16, lineHeight: 'initial' }}>
|
||||
<a>
|
||||
<span>Benito Mussolini</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ fontSize: 15, lineHeight: '24px', margin: '5px 75px 1px', wordWrap: 'break-word' }}>
|
||||
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro nihil dolor delectus ex minima aliquid quidem veniam officiis temporibus ipsum ea incidunt voluptatum a, repellat illum, cumque consequatur saepe assumenda.</p>
|
||||
</div>
|
||||
<div className={'reviewLinks'} style={{ marginLeft: 72 }}>
|
||||
<div className={'mr-2'} style={{ minWidth: 55, display: 'inline-block', verticalAlign: 'middle' }}>
|
||||
<a className={'text-sm'} href={'#'}>
|
||||
<svg className={'inline-block mr-1'} fill={'currentColor'} xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 -960 960 960"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h280v80H200v560h560v-280h80v280q0 33-23.5 56.5T760-120H200Zm188-212-56-56 372-372H560v-80h280v280h-80v-144L388-332Z" /></svg>
|
||||
<div className={'inline-block'}>Video</div>
|
||||
</a>
|
||||
</div>
|
||||
<div style={{ minWidth: 55, display: 'inline-block', verticalAlign: 'middle' }}>
|
||||
<a className={'text-sm'} href={'#'}>
|
||||
<svg className={'inline-block mr-1'} fill={'currentColor'} xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 -960 960 960"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h280v80H200v560h560v-280h80v280q0 33-23.5 56.5T760-120H200Zm188-212-56-56 372-372H560v-80h280v280h-80v-144L388-332Z" /></svg>
|
||||
<div className={'inline-block'}>Instagram</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div name={'USERS REVIEW'} style={{ margin: '50px 0', textAlign: 'left' }}>
|
||||
<SeparatorWithAnchor pageName={"User's review"} pageLink='#' secondLink={locationDetail.users_review.length > 0 ? '#' : ''} />
|
||||
{ locationDetail.users_review.length > 0 ?
|
||||
<>
|
||||
{locationDetail.users_review.map(x => (
|
||||
<div style={{ padding: '15px 0' }}>
|
||||
<SeparatorWithAnchor pageName={"Popular User's review"} pageLink='#' secondLink='#'/>
|
||||
|
||||
<div className={''} style={{ padding: '15px 0' }}>
|
||||
<div className={'mr-5'} style={{ width: 45, float: 'left' }}>
|
||||
<a href="#">
|
||||
<img
|
||||
loading={'lazy'}
|
||||
style={{ width: '100%' }}
|
||||
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'}
|
||||
src={'https://cdn.discordapp.com/attachments/743422487882104837/1153985664849805392/421-4212617_person-placeholder-image-transparent-hd-png-download.png'}
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ fontWeight: 700, fontSize: 16, lineHeight: 'initial' }}>
|
||||
<a>
|
||||
<span>{x.username}</span>
|
||||
<span>Benito Mussolini</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className={'inline-block'}>
|
||||
<div className={'text-sm text-center'} >{x.score}</div>
|
||||
<div className={'text-sm text-center'} >80</div>
|
||||
<div style={{ height: 4, width: 25, position: 'relative', backgroundColor: '#d8d8d8' }}>
|
||||
<div style={{ height: 4, backgroundColor: '#85ce73', width: `${x.score}%` }} />
|
||||
<div style={{ height: 4, backgroundColor: '#85ce73', width: '90%' }} />
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ fontSize: 15, lineHeight: '24px', margin: '10px 65px 1px', wordWrap: 'break-word' }}>
|
||||
<CustomInterweave
|
||||
content={x.comments}
|
||||
/>
|
||||
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro nihil dolor delectus ex minima aliquid quidem veniam officiis temporibus ipsum ea incidunt voluptatum a, repellat illum, cumque consequatur saepe assumenda.</p>
|
||||
</div>
|
||||
<div className={'reviewLinks'} style={{ marginLeft: 63 }}>
|
||||
<div className={'mr-2'} style={{ minWidth: 55, display: 'inline-block', verticalAlign: 'middle' }}>
|
||||
<a className={'text-sm'} href={'#'}>
|
||||
<svg className={'inline-block mr-1'} fill={'currentColor'} xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 -960 960 960"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h280v80H200v560h560v-280h80v280q0 33-23.5 56.5T760-120H200Zm188-212-56-56 372-372H560v-80h280v280h-80v-144L388-332Z" /></svg>
|
||||
<div className={'inline-block'}>Video</div>
|
||||
</a>
|
||||
</div>
|
||||
<div style={{ minWidth: 55, display: 'inline-block', verticalAlign: 'middle' }}>
|
||||
<a className={'text-sm'} href={'#'}>
|
||||
<svg className={'inline-block mr-1'} fill={'currentColor'} xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 -960 960 960"><path d="M200-120q-33 0-56.5-23.5T120-200v-560q0-33 23.5-56.5T200-840h280v80H200v560h560v-280h80v280q0 33-23.5 56.5T760-120H200Zm188-212-56-56 372-372H560v-80h280v280h-80v-144L388-332Z" /></svg>
|
||||
<div className={'inline-block'}>Instagram</div>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className={''} style={{ padding: '15px 0', borderTop: '1px solid #38444d' }}>
|
||||
<div className={'mr-5'} style={{ width: 45, float: 'left' }}>
|
||||
<a href="#">
|
||||
<img
|
||||
loading={'lazy'}
|
||||
style={{ width: '100%' }}
|
||||
src={'https://cdn.discordapp.com/attachments/743422487882104837/1153985664849805392/421-4212617_person-placeholder-image-transparent-hd-png-download.png'}
|
||||
/>
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<div style={{ fontWeight: 700, fontSize: 16, lineHeight: 'initial' }}>
|
||||
<a>
|
||||
<span>Benito Mussolini</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<div className={'inline-block'}>
|
||||
<div className={'text-sm text-center'} >80</div>
|
||||
<div style={{ height: 4, width: 25, position: 'relative', backgroundColor: '#d8d8d8' }}>
|
||||
<div style={{ height: 4, backgroundColor: '#85ce73', width: '90%' }} />
|
||||
</div>
|
||||
</div>
|
||||
<div style={{ fontSize: 15, lineHeight: '24px', margin: '10px 65px 1px', wordWrap: 'break-word' }}>
|
||||
<p>Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro nihil dolor delectus ex minima aliquid quidem veniam officiis temporibus ipsum ea incidunt voluptatum a, repellat illum, cumque consequatur saepe assumenda.</p>
|
||||
</div>
|
||||
<div className={'reviewLinks'} style={{ marginLeft: 63 }}>
|
||||
<div className={'mr-2'} style={{ minWidth: 55, display: 'inline-block', verticalAlign: 'middle' }}>
|
||||
@ -490,24 +502,17 @@ function LocationDetail() {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
|
||||
<div className={'review-more-button text-center text-sm mt-5'}>
|
||||
<a style={{ borderRadius: 15, padding: '8px 32px', border: '1px solid #d8d8d8' }}>
|
||||
<a style={{ borderRadius: 15, padding: '8px 32px', border: '1px solid #d8d8d8'}}>
|
||||
More
|
||||
</a>
|
||||
</div>
|
||||
</>
|
||||
:
|
||||
<>
|
||||
<span className={'text-sm italic'}>No users review to display</span>
|
||||
</>
|
||||
}
|
||||
</div>
|
||||
|
||||
|
||||
{/* <div name={'USERS REVIEW'} style={{ margin: '50px 0', textAlign: 'left' }}>
|
||||
<SeparatorWithAnchor pageName={"Popular User's review"} pageLink='#' secondLink='#' />
|
||||
<div name={'USERS REVIEW'} style={{ margin: '50px 0', textAlign: 'left' }}>
|
||||
<SeparatorWithAnchor pageName={"Recent User's review"} pageLink='#' secondLink='#'/>
|
||||
<div className={''} style={{ padding: '15px 0' }}>
|
||||
<div className={'mr-5'} style={{ width: 45, float: 'left' }}>
|
||||
<a href="#">
|
||||
@ -592,24 +597,24 @@ function LocationDetail() {
|
||||
</div>
|
||||
</div>
|
||||
<div className={'review-more-button text-center text-sm mt-5'}>
|
||||
<a style={{ borderRadius: 15, padding: '8px 32px', border: '1px solid #d8d8d8' }}>
|
||||
<a style={{ borderRadius: 15, padding: '8px 32px', border: '1px solid #d8d8d8'}}>
|
||||
More
|
||||
</a>
|
||||
</div>
|
||||
</div> */}
|
||||
</div>
|
||||
<div className={'mb-5'}>
|
||||
CONTRUBITION
|
||||
<DefaultSeparator />
|
||||
anoeantoeh aoenthaoe aoenth aot
|
||||
</div>
|
||||
</div>
|
||||
{/* {screen.width >= 1024 &&
|
||||
{screen.width >= 1024 &&
|
||||
<div className={'bg-secondary'} style={{ display: 'table-cell', position: 'relative', verticalAlign: 'top', width: 330, textAlign: 'left', padding: 15, boxSizing: 'border-box', height: 1080 }}>
|
||||
Lorem ipsum dolor sit amet consectetur adipisicing elit. Reprehenderit cumque aliquam doloribus in reiciendis? Laborum, ea assumenda, tempora dolore placeat aspernatur, cumque totam sequi debitis dolor nam eligendi suscipit aliquid?
|
||||
</div>
|
||||
} */}
|
||||
}
|
||||
</div>
|
||||
<div style={{ clear: 'both' }} />
|
||||
<div style={{ clear: 'both'}} />
|
||||
</section>
|
||||
|
||||
<section>
|
||||
|
@ -4,16 +4,13 @@ export interface ILocationDetail {
|
||||
id: Number,
|
||||
name: String,
|
||||
address: String,
|
||||
regency_name: String,
|
||||
province_name: String,
|
||||
region_name: String,
|
||||
google_maps_link: String,
|
||||
thumbnail: NullValueRes<"String", String>,
|
||||
submitted_by: Number,
|
||||
critic_score: Number,
|
||||
critic_count: Number,
|
||||
user_score: Number,
|
||||
user_count: Number
|
||||
regency_name: String,
|
||||
province_name: String,
|
||||
region_name: String,
|
||||
submitted_by_user: String
|
||||
}
|
||||
|
||||
export function emptyLocationDetail(): ILocationDetail {
|
||||
@ -27,38 +24,19 @@ export function emptyLocationDetail(): ILocationDetail {
|
||||
regency_name: '',
|
||||
region_name: '',
|
||||
submitted_by: 0,
|
||||
critic_score: 0,
|
||||
critic_count: 0,
|
||||
user_score: 0,
|
||||
user_count: 0,
|
||||
submitted_by_user: ''
|
||||
}
|
||||
}
|
||||
|
||||
export interface LocationReviewsResponse {
|
||||
id: number,
|
||||
score: number,
|
||||
comments: string,
|
||||
user_id: number,
|
||||
username: string,
|
||||
user_avatar: NullValueRes<"String", string>,
|
||||
created_at: string,
|
||||
updated_at: string
|
||||
}
|
||||
|
||||
export interface LocationDetailResponse {
|
||||
detail: ILocationDetail,
|
||||
tags: Array<String>
|
||||
users_review: Array<LocationReviewsResponse>,
|
||||
critics_review: Array<LocationReviewsResponse>
|
||||
}
|
||||
|
||||
|
||||
export function EmptyLocationDetailResponse(): LocationDetailResponse {
|
||||
return {
|
||||
detail: emptyLocationDetail(),
|
||||
tags: [],
|
||||
critics_review: Array<LocationReviewsResponse>(),
|
||||
users_review: Array<LocationReviewsResponse>()
|
||||
tags: []
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,6 +47,15 @@ export interface LocationImage extends SlideImage {
|
||||
uploaded_by: String
|
||||
}
|
||||
|
||||
export function emptyLocationImage(): LocationImage {
|
||||
return {
|
||||
id: 0,
|
||||
src: '',
|
||||
created_at: '',
|
||||
uploaded_by: ''
|
||||
}
|
||||
}
|
||||
|
||||
export interface LocationResponse {
|
||||
total_image: Number,
|
||||
images: Array<LocationImage>
|
||||
@ -77,18 +64,6 @@ export interface LocationResponse {
|
||||
export function emptyLocationResponse(): LocationResponse {
|
||||
return {
|
||||
total_image: 0,
|
||||
images: Array<LocationImage>()
|
||||
images: [emptyLocationImage()]
|
||||
}
|
||||
}
|
||||
|
||||
export type CurrentUserLocationReviews = {
|
||||
id: Number,
|
||||
comments: string,
|
||||
is_from_critic: boolean,
|
||||
is_hided: boolean,
|
||||
location_id: Number,
|
||||
score: Number,
|
||||
submitted_by: Number,
|
||||
created_at: NullValueRes<"Time", string>,
|
||||
updated_at: NullValueRes<"Time", string>,
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
input {
|
||||
padding: 5px;
|
||||
font-size: 14px;
|
||||
}
|
@ -1,120 +0,0 @@
|
||||
import { ChangeEvent, TargetedEvent, useState } from "preact/compat";
|
||||
import { createAccountService, loginService } from "../../services";
|
||||
import { useLocation, useNavigate } from "react-router-dom";
|
||||
import { useDispatch } from "react-redux";
|
||||
import { authAdded } from "../../features/auth/authSlice/authSlice";
|
||||
import './index.css';
|
||||
|
||||
function Login() {
|
||||
const dispatch = useDispatch();
|
||||
const { state } = useLocation()
|
||||
const [form, setFrom] = useState({
|
||||
username: '',
|
||||
password: ''
|
||||
})
|
||||
|
||||
const [errorMsg, setErrorMsg] = useState([{
|
||||
field: '',
|
||||
msg: ''
|
||||
}])
|
||||
|
||||
const navigation = useNavigate()
|
||||
|
||||
async function handleSignIn(e: TargetedEvent) {
|
||||
e.preventDefault();
|
||||
try {
|
||||
const res = await loginService({ username: form.username, password: form.password })
|
||||
if (res.error) {
|
||||
setErrorMsg(res.error.response.data.errors)
|
||||
return
|
||||
}
|
||||
|
||||
dispatch(authAdded(res.data))
|
||||
|
||||
if (state) {
|
||||
navigation(state.from)
|
||||
return
|
||||
}
|
||||
|
||||
navigation("/")
|
||||
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
}
|
||||
|
||||
async function handleSignUp(e: TargetedEvent) {
|
||||
e.preventDefault();
|
||||
try {
|
||||
const res = await createAccountService({
|
||||
username: form.username,
|
||||
password: form.password
|
||||
})
|
||||
|
||||
if (res.error) {
|
||||
setErrorMsg(res.error.response.data.errors)
|
||||
return;
|
||||
}
|
||||
|
||||
dispatch(authAdded(res.data))
|
||||
|
||||
if (state) {
|
||||
navigation(state.from)
|
||||
return
|
||||
}
|
||||
navigation("/")
|
||||
|
||||
} catch (err) {
|
||||
alert(err)
|
||||
}
|
||||
}
|
||||
|
||||
function onChangeInput(e: ChangeEvent<HTMLInputElement>) {
|
||||
const val = e.target as HTMLInputElement;
|
||||
setFrom({ ...form, [val.placeholder]: val.value })
|
||||
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={'p-2'}>
|
||||
<h1 className={'text-2xl mb-2'}>Sign in</h1>
|
||||
<form onSubmit={handleSignIn}>
|
||||
<table style={{ borderSpacing: '0 0.5em', borderCollapse: 'separate' }}>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>username: </td>
|
||||
<td><input value={form.username} onChange={onChangeInput} placeholder={'username'} className={'bg-secondary'} /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>password: </td>
|
||||
<td><input value={form.password} onChange={onChangeInput} type={'password'} placeholder={'password'} className={'bg-secondary'} /></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<a className={'block'}>Forgout account ?</a>
|
||||
<input type={'submit'} value={'sign in'} className={'p-1 text-sm text-primary mt-4'} style={{ backgroundColor: '#a8adb3', borderRadius: 7 }} />
|
||||
</form>
|
||||
<h1 className={'text-2xl mt-10'}>Create Account</h1>
|
||||
<form onSubmit={handleSignUp} >
|
||||
<table style={{ borderSpacing: '0 0.5em', borderCollapse: 'separate' }}>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>username: </td>
|
||||
<td><input value={form.username} onChange={onChangeInput} placeholder={'username'} className={'bg-secondary'} /></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>password: </td>
|
||||
<td><input value={form.password} onChange={onChangeInput} type={'password'} placeholder={'password'} className={'bg-secondary'} /></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{errorMsg.map(x => (
|
||||
<p>{x.msg}</p>
|
||||
))}
|
||||
<input type={'submit'} value={'create account'} className={'p-1 text-sm text-primary mt-4'} style={{ backgroundColor: '#a8adb3', borderRadius: 7 }} />
|
||||
</form>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Login;
|
@ -1,9 +0,0 @@
|
||||
const NotFound = () => (
|
||||
<div class={'main-content content'}>
|
||||
<img
|
||||
src={'https://external-content.duckduckgo.com/iu/?u=https%3A%2F%2Fmedia.tenor.com%2FUWHgJ8QRcZsAAAAi%2Fturtle-huh-meme.gif&f=1&nofb=1&ipt=64af045b4bd24f01c00528f14b53fb17c49ed5b603fc58332e8a5de65a1b89ef&ipo=images'}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default NotFound;
|
@ -4,16 +4,10 @@ import Discovery from "./Discovery";
|
||||
import Story from "./Stories";
|
||||
import NewsEvent from "./NewsEvents";
|
||||
import LocationDetail from "./LocationDetail";
|
||||
import Login from './Login';
|
||||
import NotFound from "./NotFound";
|
||||
|
||||
export {
|
||||
Login,
|
||||
|
||||
Home,
|
||||
|
||||
NotFound,
|
||||
|
||||
BestLocation,
|
||||
LocationDetail,
|
||||
|
||||
|
@ -1,18 +0,0 @@
|
||||
import { combineReducers } from "@reduxjs/toolkit";
|
||||
import { LOGOUT } from "../constants/actions";
|
||||
import { authSlice } from "../features";
|
||||
|
||||
const appReducer = combineReducers({
|
||||
auth: authSlice
|
||||
});
|
||||
|
||||
const rootReducer = (state: any, action: any) => {
|
||||
if (action.type === LOGOUT) {
|
||||
// remove token
|
||||
state = undefined
|
||||
}
|
||||
|
||||
return appReducer(state, action);
|
||||
}
|
||||
|
||||
export default rootReducer;
|
@ -4,8 +4,7 @@ import {
|
||||
Home,
|
||||
LocationDetail,
|
||||
NewsEvent,
|
||||
Story,
|
||||
Login
|
||||
Story
|
||||
} from '../pages';
|
||||
|
||||
const routes = [
|
||||
|
@ -1,59 +0,0 @@
|
||||
import { AxiosError } from "axios";
|
||||
import { LOGIN_URI, SIGNUP_URI } from "../constants/api";
|
||||
import { client } from "./config";
|
||||
|
||||
const initialState: IEmptyResponseState = {
|
||||
data: null,
|
||||
error: AxiosError
|
||||
}
|
||||
|
||||
interface IAuthentication {
|
||||
username: String
|
||||
password: String
|
||||
}
|
||||
|
||||
async function createAccountService({ username, password }: IAuthentication) {
|
||||
const newState = { ...initialState };
|
||||
try {
|
||||
const response = await client({ method: 'POST', url: SIGNUP_URI, data: { username, password } })
|
||||
newState.data = response.data
|
||||
newState.error = null
|
||||
return newState
|
||||
} catch (error) {
|
||||
newState.error = error
|
||||
return newState
|
||||
}
|
||||
}
|
||||
|
||||
async function loginService({ username, password }: IAuthentication) {
|
||||
const newState = { ...initialState };
|
||||
try {
|
||||
const response = await client({ method: 'POST', url: LOGIN_URI, data: { username, password }, withCredentials: true })
|
||||
newState.data = response.data
|
||||
newState.error = null
|
||||
return newState
|
||||
} catch (error) {
|
||||
newState.error = error
|
||||
return newState
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
async function logoutService() {
|
||||
const newState = { ...initialState };
|
||||
try {
|
||||
const response = await client({ method: 'POST', url: LOGIN_URI})
|
||||
newState.data = response.data
|
||||
newState.error = null
|
||||
return newState
|
||||
} catch (error) {
|
||||
newState.error = error
|
||||
return newState
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
loginService,
|
||||
createAccountService,
|
||||
logoutService
|
||||
};
|
@ -6,8 +6,7 @@ export const client = (props: AxiosRequestConfig): AxiosPromise => axios({
|
||||
baseURL: `${BASE_URL}`,
|
||||
url: props.url,
|
||||
headers: props.headers,
|
||||
data: props.data,
|
||||
...props
|
||||
data: props.data
|
||||
})
|
||||
|
||||
// export const authClient = (props: AxiosRequestConfig) => axios({
|
||||
|
@ -5,21 +5,14 @@ import {
|
||||
getLocationService,
|
||||
getLocationTagsService,
|
||||
} from "./locations";
|
||||
|
||||
import { getImagesByLocationService } from "./images"
|
||||
import { createAccountService, loginService, logoutService } from "./auth";
|
||||
import { postReviewLocation } from "./review";
|
||||
|
||||
export {
|
||||
createAccountService,
|
||||
loginService,
|
||||
logoutService,
|
||||
|
||||
getListLocationsService,
|
||||
getListRecentLocationsRatingsService,
|
||||
getListTopLocationsService,
|
||||
getLocationService,
|
||||
getLocationTagsService,
|
||||
getImagesByLocationService,
|
||||
|
||||
postReviewLocation
|
||||
}
|
@ -80,7 +80,7 @@ async function getLocationService(id: Number) {
|
||||
return newState;
|
||||
}
|
||||
} catch (error) {
|
||||
throw(error)
|
||||
console.log(error)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,34 +0,0 @@
|
||||
import { AxiosError } from "axios"
|
||||
import { client } from "./config";
|
||||
import { POST_REVIEW_LOCATION_URI } from "../constants/api";
|
||||
|
||||
const initialState: IEmptyResponseState = {
|
||||
data: null,
|
||||
error: AxiosError
|
||||
}
|
||||
|
||||
interface postReviewLocationReq {
|
||||
submitted_by: number,
|
||||
comments: string,
|
||||
score: number,
|
||||
is_from_critic: boolean,
|
||||
is_hided: boolean,
|
||||
location_id: number
|
||||
}
|
||||
|
||||
async function postReviewLocation(req: postReviewLocationReq) {
|
||||
const newState = { ...initialState };
|
||||
try {
|
||||
const response = await client({ method: 'POST', url: POST_REVIEW_LOCATION_URI, data: req, withCredentials: true})
|
||||
newState.data = response.data
|
||||
newState.error = null
|
||||
return newState
|
||||
} catch (error) {
|
||||
newState.error = error
|
||||
throw(error)
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
postReviewLocation
|
||||
}
|
@ -1,25 +0,0 @@
|
||||
import { applyMiddleware, createStore, compose } from '@reduxjs/toolkit'
|
||||
import storage from 'redux-persist/lib/storage'
|
||||
import persistReducer from 'redux-persist/es/persistReducer';
|
||||
import rootReducer from '../reducers';
|
||||
import thunk from 'redux-thunk';
|
||||
import { persistStore } from 'redux-persist';
|
||||
|
||||
const composeEnhancers = (window as any)['__REDUX_DEVTOOLS_EXTENSION_COMPOSE__'] as typeof compose || compose;
|
||||
|
||||
const persistConfig = {
|
||||
key: 'root',
|
||||
blacklist: [],
|
||||
whitelist: [
|
||||
"auth"
|
||||
],
|
||||
storage
|
||||
}
|
||||
|
||||
const persistedReducer = persistReducer(persistConfig, rootReducer);
|
||||
|
||||
export type RootState = ReturnType<typeof store.getState>
|
||||
|
||||
export const store = createStore(persistedReducer, composeEnhancers(applyMiddleware(thunk)))
|
||||
|
||||
export const persistore = persistStore(store)
|
@ -1,6 +0,0 @@
|
||||
import { IUser } from "../features/auth/authSlice/type";
|
||||
import { RootState } from "./config";
|
||||
|
||||
export interface UserRootState extends RootState {
|
||||
auth: IUser
|
||||
}
|
@ -5,9 +5,3 @@ interface GetRequestPagination {
|
||||
page: number,
|
||||
page_size: number,
|
||||
}
|
||||
|
||||
|
||||
interface IEmptyResponseState {
|
||||
data: any,
|
||||
error: any,
|
||||
};
|
@ -1,5 +0,0 @@
|
||||
import { AxiosError } from "axios";
|
||||
|
||||
export function handleAxiosError(error: AxiosError) {
|
||||
return error.response?.data
|
||||
}
|
@ -1,7 +1,5 @@
|
||||
import useAutosizeTextArea from "./useAutosizeTextArea";
|
||||
import { handleAxiosError } from "./common";
|
||||
|
||||
export {
|
||||
useAutosizeTextArea,
|
||||
handleAxiosError
|
||||
useAutosizeTextArea
|
||||
}
|
@ -7,8 +7,7 @@ export default {
|
||||
current: 'currentColor',
|
||||
primary: '#202225',
|
||||
secondary: '#2f3136',
|
||||
tertiary: '#a8adb3',
|
||||
error: '#ff5454',
|
||||
tertiary: '#a8adb3'
|
||||
},
|
||||
borderColor: {
|
||||
primary: '#38444d',
|
||||
|
191
yarn.lock
191
yarn.lock
@ -197,13 +197,6 @@
|
||||
"@babel/plugin-syntax-jsx" "^7.22.5"
|
||||
"@babel/types" "^7.22.5"
|
||||
|
||||
"@babel/runtime@^7.12.1", "@babel/runtime@^7.9.2":
|
||||
version "7.22.15"
|
||||
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.22.15.tgz#38f46494ccf6cf020bd4eed7124b425e83e523b8"
|
||||
integrity sha512-T0O+aa+4w0u06iNmapipJXMV4HoUir03hpx3/YqXXhu9xim3w+dVphjFWl1OH8NbZHw5Lbm9k45drDkgq2VNNA==
|
||||
dependencies:
|
||||
regenerator-runtime "^0.14.0"
|
||||
|
||||
"@babel/template@^7.22.5":
|
||||
version "7.22.5"
|
||||
resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.5.tgz#0c8c4d944509875849bd0344ff0050756eefc6ec"
|
||||
@ -441,16 +434,6 @@
|
||||
"@prefresh/utils" "^1.2.0"
|
||||
"@rollup/pluginutils" "^4.2.1"
|
||||
|
||||
"@reduxjs/toolkit@^1.9.5":
|
||||
version "1.9.5"
|
||||
resolved "https://registry.yarnpkg.com/@reduxjs/toolkit/-/toolkit-1.9.5.tgz#d3987849c24189ca483baa7aa59386c8e52077c4"
|
||||
integrity sha512-Rt97jHmfTeaxL4swLRNPD/zV4OxTes4la07Xc4hetpUW/vc75t5m1ANyxG6ymnEQ2FsLQsoMlYB2vV1sO3m8tQ==
|
||||
dependencies:
|
||||
immer "^9.0.21"
|
||||
redux "^4.2.1"
|
||||
redux-thunk "^2.4.2"
|
||||
reselect "^4.1.8"
|
||||
|
||||
"@remix-run/router@1.9.0":
|
||||
version "1.9.0"
|
||||
resolved "https://registry.yarnpkg.com/@remix-run/router/-/router-1.9.0.tgz#9033238b41c4cbe1e961eccb3f79e2c588328cf6"
|
||||
@ -464,48 +447,6 @@
|
||||
estree-walker "^2.0.1"
|
||||
picomatch "^2.2.2"
|
||||
|
||||
"@types/hoist-non-react-statics@^3.3.0", "@types/hoist-non-react-statics@^3.3.1":
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#dc1e9ded53375d37603c479cc12c693b0878aa2a"
|
||||
integrity sha512-YIQtIg4PKr7ZyqNPZObpxfHsHEmuB8dXCxd6qVcGuQVDK2bpsF7bYNnBJ4Nn7giuACZg+WewExgrtAJ3XnA4Xw==
|
||||
dependencies:
|
||||
"@types/react" "*"
|
||||
hoist-non-react-statics "^3.3.0"
|
||||
|
||||
"@types/prop-types@*":
|
||||
version "15.7.6"
|
||||
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.6.tgz#bbf819813d6be21011b8f5801058498bec555572"
|
||||
integrity sha512-RK/kBbYOQQHLYj9Z95eh7S6t7gq4Ojt/NT8HTk8bWVhA5DaF+5SMnxHKkP4gPNN3wAZkKP+VjAf0ebtYzf+fxg==
|
||||
|
||||
"@types/react-redux@^7.1.26":
|
||||
version "7.1.26"
|
||||
resolved "https://registry.yarnpkg.com/@types/react-redux/-/react-redux-7.1.26.tgz#84149f5614e40274bb70fcbe8f7cae6267d548b1"
|
||||
integrity sha512-UKPo7Cm7rswYU6PH6CmTNCRv5NYF3HrgKuHEYTK8g/3czYLrUux50gQ2pkxc9c7ZpQZi+PNhgmI8oNIRoiVIxg==
|
||||
dependencies:
|
||||
"@types/hoist-non-react-statics" "^3.3.0"
|
||||
"@types/react" "*"
|
||||
hoist-non-react-statics "^3.3.0"
|
||||
redux "^4.0.0"
|
||||
|
||||
"@types/react@*":
|
||||
version "18.2.22"
|
||||
resolved "https://registry.yarnpkg.com/@types/react/-/react-18.2.22.tgz#abe778a1c95a07fa70df40a52d7300a40b949ccb"
|
||||
integrity sha512-60fLTOLqzarLED2O3UQImc/lsNRgG0jE/a1mPW9KjMemY0LMITWEsbS4VvZ4p6rorEHd5YKxxmMKSDK505GHpA==
|
||||
dependencies:
|
||||
"@types/prop-types" "*"
|
||||
"@types/scheduler" "*"
|
||||
csstype "^3.0.2"
|
||||
|
||||
"@types/scheduler@*":
|
||||
version "0.16.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/scheduler/-/scheduler-0.16.3.tgz#cef09e3ec9af1d63d2a6cc5b383a737e24e6dcf5"
|
||||
integrity sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==
|
||||
|
||||
"@types/use-sync-external-store@^0.0.3":
|
||||
version "0.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@types/use-sync-external-store/-/use-sync-external-store-0.0.3.tgz#b6725d5f4af24ace33b36fafd295136e75509f43"
|
||||
integrity sha512-EwmlvuaxPNej9+T4v5AuBPJa2x2UOJVdjCtDHgcDqitUeOtjnJKJ+apYjVcAoBEMjKW1VVFGZLUb5+qqa09XFA==
|
||||
|
||||
ansi-styles@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
|
||||
@ -670,11 +611,6 @@ cssesc@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
|
||||
integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
|
||||
|
||||
csstype@^3.0.2:
|
||||
version "3.1.2"
|
||||
resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.2.tgz#1d4bf9d572f11c14031f0436e1c10bc1f571f50b"
|
||||
integrity sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==
|
||||
|
||||
debug@^4.1.0, debug@^4.3.1:
|
||||
version "4.3.4"
|
||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
|
||||
@ -702,21 +638,6 @@ electron-to-chromium@^1.4.477:
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.499.tgz#dc36b67f4c8e273524e8d2080c5203a6a76987b6"
|
||||
integrity sha512-0NmjlYBLKVHva4GABWAaHuPJolnDuL0AhV3h1hES6rcLCWEIbRL6/8TghfsVwkx6TEroQVdliX7+aLysUpKvjw==
|
||||
|
||||
emojibase-regex@^6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/emojibase-regex/-/emojibase-regex-6.0.1.tgz#dc0b33d05c02f045ea44795d453698b205d41f0f"
|
||||
integrity sha512-Mj1UT6IIk4j91yMFE0QetpUYcmsr5ZDkkOIMSGafhIgC086mBMaCh2Keaykx8YEllmV7hmx5zdANDzCYBYAVDw==
|
||||
|
||||
emojibase@^15.0.0:
|
||||
version "15.0.0"
|
||||
resolved "https://registry.yarnpkg.com/emojibase/-/emojibase-15.0.0.tgz#f41b7773ec9a8a332373c18628ff4471255bd769"
|
||||
integrity sha512-bvSIs98sHaVnyKPmW+obRjo49MFx0g+rhfSz6mTePAagEZSlDPosq0b6AcSJa5gt48z3VP2ooXclyBs8vIkpGA==
|
||||
|
||||
emojibase@^6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/emojibase/-/emojibase-6.1.0.tgz#c3bc281e998a0e06398416090c23bac8c5ed3ee8"
|
||||
integrity sha512-1GkKJPXP6tVkYJHOBSJHoGOr/6uaDxZ9xJ6H7m6PfdGXTmQgbALHLWaVRY4Gi/qf5x/gT/NUXLPuSHYLqtLtrQ==
|
||||
|
||||
esbuild@^0.18.10:
|
||||
version "0.18.20"
|
||||
resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.18.20.tgz#4709f5a34801b43b799ab7d6d82f7284a9b7a7a6"
|
||||
@ -750,11 +671,6 @@ escalade@^3.1.1:
|
||||
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
|
||||
integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
|
||||
|
||||
escape-html@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
|
||||
integrity sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==
|
||||
|
||||
escape-string-regexp@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
|
||||
@ -872,18 +788,6 @@ has@^1.0.3:
|
||||
dependencies:
|
||||
function-bind "^1.1.1"
|
||||
|
||||
hoist-non-react-statics@^3.3.0, hoist-non-react-statics@^3.3.2:
|
||||
version "3.3.2"
|
||||
resolved "https://registry.yarnpkg.com/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz#ece0acaf71d62c2969c2ec59feff42a4b1a85b45"
|
||||
integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==
|
||||
dependencies:
|
||||
react-is "^16.7.0"
|
||||
|
||||
immer@^9.0.21:
|
||||
version "9.0.21"
|
||||
resolved "https://registry.yarnpkg.com/immer/-/immer-9.0.21.tgz#1e025ea31a40f24fb064f1fef23e931496330176"
|
||||
integrity sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==
|
||||
|
||||
inflight@^1.0.4:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
|
||||
@ -897,26 +801,6 @@ inherits@2:
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
interweave-autolink@^5.1.0:
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/interweave-autolink/-/interweave-autolink-5.1.0.tgz#a5a5438c45c5e4d631838473845be1fdd38a664b"
|
||||
integrity sha512-WOEakAdwqv/W2H85cLdigkpMM7o6qVg4CWM6iO5cHrFCywwUh+ILVmZgX1tHphEpa55sFdzpKNO2EHhAjbR4GA==
|
||||
|
||||
interweave-emoji@^7.0.0:
|
||||
version "7.0.0"
|
||||
resolved "https://registry.yarnpkg.com/interweave-emoji/-/interweave-emoji-7.0.0.tgz#937455fcc616121761034d0c120edec4af8586c6"
|
||||
integrity sha512-3yFBreW2h+I/Tjf9LpF/bKKdjGSi5DT1RxrRFibmmDjTB1tCyPe5X3XFNdglwoRPErgFL1qqFpQWQJKUlUwARg==
|
||||
dependencies:
|
||||
emojibase "^6.1.0"
|
||||
emojibase-regex "^6.0.1"
|
||||
|
||||
interweave@^13.1.0:
|
||||
version "13.1.0"
|
||||
resolved "https://registry.yarnpkg.com/interweave/-/interweave-13.1.0.tgz#4b7a0a87a7eb32001bef64525f68d95296dee03c"
|
||||
integrity sha512-JIDq0+2NYg0cgL7AB26fBcV0yZdiJvPDBp+aF6k8gq6Cr1kH5Gd2/Xqn7j8z+TGb8jCWZn739jzalCz+nPYwcA==
|
||||
dependencies:
|
||||
escape-html "^1.0.3"
|
||||
|
||||
is-binary-path@~2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
|
||||
@ -953,7 +837,7 @@ jiti@^1.18.2:
|
||||
resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.19.3.tgz#ef554f76465b3c2b222dc077834a71f0d4a37569"
|
||||
integrity sha512-5eEbBDQT/jF1xg6l36P+mWGGoH9Spuy0PCdSr2dtWRDGC6ph/w9ZCL4lmESW8f8F7MwT3XKescfP0wnZWAKL9w==
|
||||
|
||||
"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
|
||||
js-tokens@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||
integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
|
||||
@ -983,13 +867,6 @@ lines-and-columns@^1.1.6:
|
||||
resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
|
||||
integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
|
||||
|
||||
loose-envify@^1.1.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
|
||||
dependencies:
|
||||
js-tokens "^3.0.0 || ^4.0.0"
|
||||
|
||||
lru-cache@^5.1.1:
|
||||
version "5.1.1"
|
||||
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
|
||||
@ -1029,11 +906,6 @@ minimatch@^3.0.4:
|
||||
dependencies:
|
||||
brace-expansion "^1.1.7"
|
||||
|
||||
moment@^2.29.4:
|
||||
version "2.29.4"
|
||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108"
|
||||
integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==
|
||||
|
||||
ms@2.1.2:
|
||||
version "2.1.2"
|
||||
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
|
||||
@ -1183,28 +1055,6 @@ queue-microtask@^1.2.2:
|
||||
resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
|
||||
integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
|
||||
|
||||
react-is@^16.7.0:
|
||||
version "16.13.1"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
|
||||
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
|
||||
|
||||
react-is@^18.0.0:
|
||||
version "18.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b"
|
||||
integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==
|
||||
|
||||
react-redux@^8.1.2:
|
||||
version "8.1.2"
|
||||
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-8.1.2.tgz#9076bbc6b60f746659ad6d51cb05de9c5e1e9188"
|
||||
integrity sha512-xJKYI189VwfsFc4CJvHqHlDrzyFTY/3vZACbE+rr/zQ34Xx1wQfB4OTOSeOSNrF6BDVe8OOdxIrAnMGXA3ggfw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.12.1"
|
||||
"@types/hoist-non-react-statics" "^3.3.1"
|
||||
"@types/use-sync-external-store" "^0.0.3"
|
||||
hoist-non-react-statics "^3.3.2"
|
||||
react-is "^18.0.0"
|
||||
use-sync-external-store "^1.0.0"
|
||||
|
||||
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"
|
||||
@ -1220,13 +1070,6 @@ react-router@6.16.0:
|
||||
dependencies:
|
||||
"@remix-run/router" "1.9.0"
|
||||
|
||||
react@^18.2.0:
|
||||
version "18.2.0"
|
||||
resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5"
|
||||
integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==
|
||||
dependencies:
|
||||
loose-envify "^1.1.0"
|
||||
|
||||
read-cache@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/read-cache/-/read-cache-1.0.0.tgz#e664ef31161166c9751cdbe8dbcf86b5fb58f774"
|
||||
@ -1241,33 +1084,6 @@ readdirp@~3.6.0:
|
||||
dependencies:
|
||||
picomatch "^2.2.1"
|
||||
|
||||
redux-persist@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/redux-persist/-/redux-persist-6.0.0.tgz#b4d2972f9859597c130d40d4b146fecdab51b3a8"
|
||||
integrity sha512-71LLMbUq2r02ng2We9S215LtPu3fY0KgaGE0k8WRgl6RkqxtGfl7HUozz1Dftwsb0D/5mZ8dwAaPbtnzfvbEwQ==
|
||||
|
||||
redux-thunk@^2.4.2:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.2.tgz#b9d05d11994b99f7a91ea223e8b04cf0afa5ef3b"
|
||||
integrity sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==
|
||||
|
||||
redux@^4.0.0, redux@^4.2.1:
|
||||
version "4.2.1"
|
||||
resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197"
|
||||
integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.9.2"
|
||||
|
||||
regenerator-runtime@^0.14.0:
|
||||
version "0.14.0"
|
||||
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz#5e19d68eb12d486f797e15a3c6a918f7cec5eb45"
|
||||
integrity sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==
|
||||
|
||||
reselect@^4.1.8:
|
||||
version "4.1.8"
|
||||
resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524"
|
||||
integrity sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==
|
||||
|
||||
resolve@^1.1.7, resolve@^1.20.0, resolve@^1.22.2:
|
||||
version "1.22.4"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.4.tgz#1dc40df46554cdaf8948a486a10f6ba1e2026c34"
|
||||
@ -1403,11 +1219,6 @@ update-browserslist-db@^1.0.11:
|
||||
escalade "^3.1.1"
|
||||
picocolors "^1.0.0"
|
||||
|
||||
use-sync-external-store@^1.0.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a"
|
||||
integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==
|
||||
|
||||
util-deprecate@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
|
Loading…
Reference in New Issue
Block a user