dev
This commit is contained in:
parent
f1fd9bcbb9
commit
8a5281a0f2
@ -12,6 +12,7 @@
|
||||
"@floating-ui/react": "^0.26.9",
|
||||
"@reduxjs/toolkit": "^1.9.5",
|
||||
"axios": "^1.5.0",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"emojibase": "^15.0.0",
|
||||
"interweave": "^13.1.0",
|
||||
"interweave-autolink": "^5.1.0",
|
||||
@ -27,6 +28,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@preact/preset-vite": "^2.5.0",
|
||||
"@types/react-redux": "^7.1.34",
|
||||
"autoprefixer": "^10.4.15",
|
||||
"postcss": "^8.4.28",
|
||||
"tailwindcss": "^3.3.3",
|
||||
|
110
pnpm-lock.yaml
110
pnpm-lock.yaml
@ -10,13 +10,16 @@ importers:
|
||||
dependencies:
|
||||
'@floating-ui/react':
|
||||
specifier: ^0.26.9
|
||||
version: 0.26.9(react-dom@18.2.0)(react@18.2.0)
|
||||
version: 0.26.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
'@reduxjs/toolkit':
|
||||
specifier: ^1.9.5
|
||||
version: 1.9.7(react-redux@8.1.3)(react@18.2.0)
|
||||
version: 1.9.7(react-redux@8.1.3(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(redux@4.2.1))(react@18.2.0)
|
||||
axios:
|
||||
specifier: ^1.5.0
|
||||
version: 1.6.7
|
||||
class-variance-authority:
|
||||
specifier: ^0.7.0
|
||||
version: 0.7.0
|
||||
emojibase:
|
||||
specifier: ^15.0.0
|
||||
version: 15.3.0
|
||||
@ -25,25 +28,25 @@ importers:
|
||||
version: 13.1.0(react@18.2.0)
|
||||
interweave-autolink:
|
||||
specifier: ^5.1.0
|
||||
version: 5.1.1(interweave@13.1.0)(react@18.2.0)
|
||||
version: 5.1.1(interweave@13.1.0(react@18.2.0))(react@18.2.0)
|
||||
interweave-emoji:
|
||||
specifier: ^7.0.0
|
||||
version: 7.0.0(interweave@13.1.0)(react@18.2.0)
|
||||
version: 7.0.0(interweave@13.1.0(react@18.2.0))(react@18.2.0)
|
||||
preact:
|
||||
specifier: ^10.16.0
|
||||
version: 10.19.3
|
||||
react-redux:
|
||||
specifier: ^8.1.2
|
||||
version: 8.1.3(react-dom@18.2.0)(react@18.2.0)(redux@4.2.1)
|
||||
version: 8.1.3(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(redux@4.2.1)
|
||||
react-router-dom:
|
||||
specifier: ^6.16.0
|
||||
version: 6.21.3(react-dom@18.2.0)(react@18.2.0)
|
||||
version: 6.21.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
react-select:
|
||||
specifier: ^5.8.0
|
||||
version: 5.8.0(react-dom@18.2.0)(react@18.2.0)
|
||||
version: 5.8.0(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
react-textarea-autosize:
|
||||
specifier: ^8.5.3
|
||||
version: 8.5.3(react@18.2.0)
|
||||
version: 8.5.3(@types/react@18.2.48)(react@18.2.0)
|
||||
redux-persist:
|
||||
specifier: ^6.0.0
|
||||
version: 6.0.0(react@18.2.0)(redux@4.2.1)
|
||||
@ -52,11 +55,14 @@ importers:
|
||||
version: 2.4.2(redux@4.2.1)
|
||||
yet-another-react-lightbox:
|
||||
specifier: ^3.12.2
|
||||
version: 3.16.0(react-dom@18.2.0)(react@18.2.0)
|
||||
version: 3.16.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
devDependencies:
|
||||
'@preact/preset-vite':
|
||||
specifier: ^2.5.0
|
||||
version: 2.8.1(@babel/core@7.23.9)(preact@10.19.3)(vite@4.5.2)
|
||||
'@types/react-redux':
|
||||
specifier: ^7.1.34
|
||||
version: 7.1.34
|
||||
autoprefixer:
|
||||
specifier: ^10.4.15
|
||||
version: 10.4.17(postcss@8.4.33)
|
||||
@ -486,6 +492,9 @@ packages:
|
||||
'@types/prop-types@15.7.11':
|
||||
resolution: {integrity: sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng==}
|
||||
|
||||
'@types/react-redux@7.1.34':
|
||||
resolution: {integrity: sha512-GdFaVjEbYv4Fthm2ZLvj1VSCedV7TqE5y1kNwnjSdBOTXuRSgowux6J8TAct15T3CKBr63UMk+2CO7ilRhyrAQ==}
|
||||
|
||||
'@types/react-transition-group@4.4.10':
|
||||
resolution: {integrity: sha512-hT/+s0VQs2ojCX823m60m5f0sL5idt9SO6Tj6Dg+rdphGPIeJbJ6CxvBYkgkGKrYeDjvIpKTR38UzmtHJOGW3Q==}
|
||||
|
||||
@ -591,6 +600,13 @@ packages:
|
||||
resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==}
|
||||
engines: {node: '>= 8.10.0'}
|
||||
|
||||
class-variance-authority@0.7.0:
|
||||
resolution: {integrity: sha512-jFI8IQw4hczaL4ALINxqLEXQbWcNjoSkloa4IaufXCJr6QawJyw7tuRysRsrE8w2p/4gGaxKIt/hX3qz/IbD1A==}
|
||||
|
||||
clsx@2.0.0:
|
||||
resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
color-convert@1.9.3:
|
||||
resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==}
|
||||
|
||||
@ -1557,7 +1573,7 @@ snapshots:
|
||||
|
||||
'@emotion/memoize@0.8.1': {}
|
||||
|
||||
'@emotion/react@11.11.3(react@18.2.0)':
|
||||
'@emotion/react@11.11.3(@types/react@18.2.48)(react@18.2.0)':
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.9
|
||||
'@emotion/babel-plugin': 11.11.0
|
||||
@ -1568,6 +1584,8 @@ snapshots:
|
||||
'@emotion/weak-memoize': 0.3.1
|
||||
hoist-non-react-statics: 3.3.2
|
||||
react: 18.2.0
|
||||
optionalDependencies:
|
||||
'@types/react': 18.2.48
|
||||
|
||||
'@emotion/serialize@1.1.3':
|
||||
dependencies:
|
||||
@ -1669,15 +1687,15 @@ snapshots:
|
||||
'@floating-ui/core': 1.6.0
|
||||
'@floating-ui/utils': 0.2.1
|
||||
|
||||
'@floating-ui/react-dom@2.0.8(react-dom@18.2.0)(react@18.2.0)':
|
||||
'@floating-ui/react-dom@2.0.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
|
||||
dependencies:
|
||||
'@floating-ui/dom': 1.6.3
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
|
||||
'@floating-ui/react@0.26.9(react-dom@18.2.0)(react@18.2.0)':
|
||||
'@floating-ui/react@0.26.9(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
|
||||
dependencies:
|
||||
'@floating-ui/react-dom': 2.0.8(react-dom@18.2.0)(react@18.2.0)
|
||||
'@floating-ui/react-dom': 2.0.8(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
'@floating-ui/utils': 0.2.1
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
@ -1764,14 +1782,15 @@ snapshots:
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@reduxjs/toolkit@1.9.7(react-redux@8.1.3)(react@18.2.0)':
|
||||
'@reduxjs/toolkit@1.9.7(react-redux@8.1.3(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(redux@4.2.1))(react@18.2.0)':
|
||||
dependencies:
|
||||
immer: 9.0.21
|
||||
react: 18.2.0
|
||||
react-redux: 8.1.3(react-dom@18.2.0)(react@18.2.0)(redux@4.2.1)
|
||||
redux: 4.2.1
|
||||
redux-thunk: 2.4.2(redux@4.2.1)
|
||||
reselect: 4.1.8
|
||||
optionalDependencies:
|
||||
react: 18.2.0
|
||||
react-redux: 8.1.3(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(redux@4.2.1)
|
||||
|
||||
'@remix-run/router@1.14.2': {}
|
||||
|
||||
@ -1789,6 +1808,13 @@ snapshots:
|
||||
|
||||
'@types/prop-types@15.7.11': {}
|
||||
|
||||
'@types/react-redux@7.1.34':
|
||||
dependencies:
|
||||
'@types/hoist-non-react-statics': 3.3.5
|
||||
'@types/react': 18.2.48
|
||||
hoist-non-react-statics: 3.3.2
|
||||
redux: 4.2.1
|
||||
|
||||
'@types/react-transition-group@4.4.10':
|
||||
dependencies:
|
||||
'@types/react': 18.2.48
|
||||
@ -1901,6 +1927,12 @@ snapshots:
|
||||
optionalDependencies:
|
||||
fsevents: 2.3.3
|
||||
|
||||
class-variance-authority@0.7.0:
|
||||
dependencies:
|
||||
clsx: 2.0.0
|
||||
|
||||
clsx@2.0.0: {}
|
||||
|
||||
color-convert@1.9.3:
|
||||
dependencies:
|
||||
color-name: 1.1.3
|
||||
@ -2116,12 +2148,12 @@ snapshots:
|
||||
parent-module: 1.0.1
|
||||
resolve-from: 4.0.0
|
||||
|
||||
interweave-autolink@5.1.1(interweave@13.1.0)(react@18.2.0):
|
||||
interweave-autolink@5.1.1(interweave@13.1.0(react@18.2.0))(react@18.2.0):
|
||||
dependencies:
|
||||
interweave: 13.1.0(react@18.2.0)
|
||||
react: 18.2.0
|
||||
|
||||
interweave-emoji@7.0.0(interweave@13.1.0)(react@18.2.0):
|
||||
interweave-emoji@7.0.0(interweave@13.1.0(react@18.2.0))(react@18.2.0):
|
||||
dependencies:
|
||||
emojibase: 6.1.0
|
||||
emojibase-regex: 6.0.1
|
||||
@ -2288,8 +2320,9 @@ snapshots:
|
||||
postcss-load-config@4.0.2(postcss@8.4.33):
|
||||
dependencies:
|
||||
lilconfig: 3.0.0
|
||||
postcss: 8.4.33
|
||||
yaml: 2.3.4
|
||||
optionalDependencies:
|
||||
postcss: 8.4.33
|
||||
|
||||
postcss-nested@6.0.1(postcss@8.4.33):
|
||||
dependencies:
|
||||
@ -2331,19 +2364,21 @@ snapshots:
|
||||
|
||||
react-is@18.2.0: {}
|
||||
|
||||
react-redux@8.1.3(react-dom@18.2.0)(react@18.2.0)(redux@4.2.1):
|
||||
react-redux@8.1.3(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(redux@4.2.1):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.9
|
||||
'@types/hoist-non-react-statics': 3.3.5
|
||||
'@types/use-sync-external-store': 0.0.3
|
||||
hoist-non-react-statics: 3.3.2
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
react-is: 18.2.0
|
||||
redux: 4.2.1
|
||||
use-sync-external-store: 1.2.0(react@18.2.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 18.2.48
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
redux: 4.2.1
|
||||
|
||||
react-router-dom@6.21.3(react-dom@18.2.0)(react@18.2.0):
|
||||
react-router-dom@6.21.3(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
|
||||
dependencies:
|
||||
'@remix-run/router': 1.14.2
|
||||
react: 18.2.0
|
||||
@ -2355,32 +2390,32 @@ snapshots:
|
||||
'@remix-run/router': 1.14.2
|
||||
react: 18.2.0
|
||||
|
||||
react-select@5.8.0(react-dom@18.2.0)(react@18.2.0):
|
||||
react-select@5.8.0(@types/react@18.2.48)(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.9
|
||||
'@emotion/cache': 11.11.0
|
||||
'@emotion/react': 11.11.3(react@18.2.0)
|
||||
'@emotion/react': 11.11.3(@types/react@18.2.48)(react@18.2.0)
|
||||
'@floating-ui/dom': 1.6.0
|
||||
'@types/react-transition-group': 4.4.10
|
||||
memoize-one: 6.0.0
|
||||
prop-types: 15.8.1
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
react-transition-group: 4.4.5(react-dom@18.2.0)(react@18.2.0)
|
||||
use-isomorphic-layout-effect: 1.1.2(react@18.2.0)
|
||||
react-transition-group: 4.4.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
|
||||
use-isomorphic-layout-effect: 1.1.2(@types/react@18.2.48)(react@18.2.0)
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
|
||||
react-textarea-autosize@8.5.3(react@18.2.0):
|
||||
react-textarea-autosize@8.5.3(@types/react@18.2.48)(react@18.2.0):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.9
|
||||
react: 18.2.0
|
||||
use-composed-ref: 1.3.0(react@18.2.0)
|
||||
use-latest: 1.2.1(react@18.2.0)
|
||||
use-latest: 1.2.1(@types/react@18.2.48)(react@18.2.0)
|
||||
transitivePeerDependencies:
|
||||
- '@types/react'
|
||||
|
||||
react-transition-group@4.4.5(react-dom@18.2.0)(react@18.2.0):
|
||||
react-transition-group@4.4.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
|
||||
dependencies:
|
||||
'@babel/runtime': 7.23.9
|
||||
dom-helpers: 5.2.1
|
||||
@ -2403,8 +2438,9 @@ snapshots:
|
||||
|
||||
redux-persist@6.0.0(react@18.2.0)(redux@4.2.1):
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
redux: 4.2.1
|
||||
optionalDependencies:
|
||||
react: 18.2.0
|
||||
|
||||
redux-thunk@2.4.2(redux@4.2.1):
|
||||
dependencies:
|
||||
@ -2549,14 +2585,18 @@ snapshots:
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
|
||||
use-isomorphic-layout-effect@1.1.2(react@18.2.0):
|
||||
use-isomorphic-layout-effect@1.1.2(@types/react@18.2.48)(react@18.2.0):
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
optionalDependencies:
|
||||
'@types/react': 18.2.48
|
||||
|
||||
use-latest@1.2.1(react@18.2.0):
|
||||
use-latest@1.2.1(@types/react@18.2.48)(react@18.2.0):
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
use-isomorphic-layout-effect: 1.1.2(react@18.2.0)
|
||||
use-isomorphic-layout-effect: 1.1.2(@types/react@18.2.48)(react@18.2.0)
|
||||
optionalDependencies:
|
||||
'@types/react': 18.2.48
|
||||
|
||||
use-sync-external-store@1.2.0(react@18.2.0):
|
||||
dependencies:
|
||||
@ -2594,7 +2634,7 @@ snapshots:
|
||||
|
||||
yaml@2.3.4: {}
|
||||
|
||||
yet-another-react-lightbox@3.16.0(react-dom@18.2.0)(react@18.2.0):
|
||||
yet-another-react-lightbox@3.16.0(react-dom@18.2.0(react@18.2.0))(react@18.2.0):
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
|
@ -2,7 +2,7 @@ import { JSXInternal } from "node_modules/preact/src/jsx";
|
||||
import { LocationInfo } from "../../../domains";
|
||||
|
||||
interface ComponentProps {
|
||||
onCardClick: (id: Number) => void,
|
||||
onCardClick: (id: number) => void,
|
||||
data: LocationInfo,
|
||||
containerClass?: string,
|
||||
containerStyle?: JSXInternal.CSSProperties
|
||||
|
@ -1,14 +1,14 @@
|
||||
import React from "preact/compat";
|
||||
import { useState } from "preact/hooks";
|
||||
import { useSelector, useDispatch } from "react-redux";
|
||||
import { useEffect, useState } from "preact/hooks";
|
||||
import { UserRootState } from "../../store/type";
|
||||
import { logout } from '../../actions';
|
||||
import AsyncSelect from 'react-select/async';
|
||||
import './style.css';
|
||||
import { logoutService } from "../../services";
|
||||
import { getSearchLocationService } from "../../services/locations";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Link, useNavigate } from "react-router-dom";
|
||||
import { ReactSelectData } from "src/types/common";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
|
||||
|
||||
function Header() {
|
||||
@ -17,16 +17,37 @@ function Header() {
|
||||
const [pageState, setPageState] = useState({
|
||||
profileMenu: false
|
||||
})
|
||||
const [searchResult, setSearchResult] = useState([])
|
||||
|
||||
const dispatch = useDispatch();
|
||||
const navigate = useNavigate();
|
||||
const user = useSelector((state: UserRootState) => state.auth)
|
||||
|
||||
const onInput = (val: string): void => {
|
||||
// const val = e.target as HTMLInputElement;
|
||||
const onInput = async (val: any) => {
|
||||
setSearchVal(val.toLowerCase())
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
try {
|
||||
setTimeout(async () => {
|
||||
const results = await getSearchLocationService({
|
||||
name: searchVal,
|
||||
page: 1,
|
||||
page_size: 7
|
||||
})
|
||||
const resultData = results.data.map((x: any) => {
|
||||
return {
|
||||
value: x.id,
|
||||
label: x.name
|
||||
}
|
||||
})
|
||||
setSearchResult(resultData)
|
||||
}, 900)
|
||||
} catch (err) {
|
||||
alert(err)
|
||||
}
|
||||
}, [searchVal])
|
||||
|
||||
const handleLogout = async (): Promise<void> => {
|
||||
try {
|
||||
await logoutService()
|
||||
@ -59,7 +80,13 @@ function Header() {
|
||||
label: x.name
|
||||
}
|
||||
})
|
||||
return resultData
|
||||
const firstObj = {
|
||||
value: 0,
|
||||
label: `search: ${inputValue}`
|
||||
}
|
||||
const result = [firstObj, ...resultData]
|
||||
setSearchResult(resultData)
|
||||
return result
|
||||
} catch (err) {
|
||||
alert(err)
|
||||
}
|
||||
@ -75,39 +102,41 @@ function Header() {
|
||||
setDropdown(!dropdown)
|
||||
}
|
||||
|
||||
|
||||
return (
|
||||
<header>
|
||||
<div className="flex flex-row content">
|
||||
<a href={"/"}>
|
||||
<Link to={"/"}>
|
||||
<h1 className={`title ${dropdown ? 'title-dropdown' : ""}`}>Hilingin</h1>
|
||||
</a>
|
||||
</Link>
|
||||
<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 }) : ''}>
|
||||
<Link to={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>
|
||||
</Link>
|
||||
{user.username &&
|
||||
<div className={'profile-dropdown-img bg-secondary text-left'} style={pageState.profileMenu ? { display: 'block' } : { display: 'none' }}>
|
||||
<a href={'/user/profile'}><div className={'p-2'}>Profile</div></a>
|
||||
<a href={'#'}><div className={'p-2'}>Feed</div></a>
|
||||
<a href={'/add-location'}><div className={'p-2'}>Add location</div></a>
|
||||
<a href={'/add-location'}><div className={'p-2'}>Settings</div></a>
|
||||
<a href={'#'} onClick={handleLogout}><div className={'p-2'}>Logout</div></a>
|
||||
<Link to={'/user/profile'}><div className={'p-2'}>Profile</div></Link>
|
||||
<Link to={'#'}><div className={'p-2'}>Feed</div></Link>
|
||||
<Link to={'/add-location'}><div className={'p-2'}>Add location</div></Link>
|
||||
<Link to={'/add-location'}><div className={'p-2'}>Settings</div></Link>
|
||||
<Link to={'#'} onClick={handleLogout}><div className={'p-2'}>Logout</div></Link>
|
||||
{/* <div className={'p-2'}><a href={'#'}>Halo</a></div> */}
|
||||
{/* <div className={'p-2'}><a href={'#'}>Halo</a></div> */}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<form onSubmit={onSearchSubmit} className={`header-search-input ${dropdown ? "search-input-dropdown" : ""}`}>
|
||||
<form onSubmit={onSearchSubmit} style={{ marginTop: 'auto', marginBottom: 'auto' }} className={`header-search-input ${dropdown ? "search-input-dropdown" : ""}`}>
|
||||
<AsyncSelect
|
||||
onInputChange={onInput}
|
||||
inputValue={searchVal}
|
||||
isSearchable
|
||||
isClearable
|
||||
menuIsOpen={searchVal.length > 1}
|
||||
placeholder={"Candi Borobudur, Tunjungan Plaza, ...."}
|
||||
|
||||
components={{
|
||||
DropdownIndicator: () => null,
|
||||
NoOptionsMessage: () => null,
|
||||
@ -145,11 +174,6 @@ function Header() {
|
||||
...base,
|
||||
backgroundColor: isFocused ? '#202225' : 'none',
|
||||
}),
|
||||
// container: (base, props) => ({
|
||||
// ...base,
|
||||
// border: 0,
|
||||
// color: "white"
|
||||
// })
|
||||
}}
|
||||
onChange={(v: ReactSelectData | unknown, _) => onSelectedSearchOption(v)}
|
||||
/>
|
||||
@ -162,23 +186,23 @@ function Header() {
|
||||
{dropdown &&
|
||||
<a href="/" className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>Home</a>
|
||||
}
|
||||
<a href="/best-places" className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>Top Places</a>
|
||||
<a href="/discover" className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>Discover</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>
|
||||
<Link to="/best-places" className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>Top Places</Link>
|
||||
<Link to="/discover" className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>Discover</Link>
|
||||
<Link to="/stories" className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>Stories</Link>
|
||||
<Link to="/news-events" className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>News / Events</Link>
|
||||
<Link to="#" className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>Forum</Link>
|
||||
<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>
|
||||
<Link to={user.username ? '#' : '/login'} onClick={() => user.username ? setPageState({ ...pageState, profileMenu: !pageState.profileMenu }) : ''} className={`navLink ${!dropdown ? "navLink-disabled" : ""}`}>{user.username ? user.username : 'Sign in'}</Link>
|
||||
{user && screen.width > 600 &&
|
||||
<div className={'profile-dropdown bg-secondary ml-6'} style={pageState.profileMenu ? { display: 'block' } : { display: 'none' }}>
|
||||
<a href={'/add-location'}><div className={'p-1'}>Add location</div></a>
|
||||
<a href={'/user/profile'}><div className={'p-1'}>Profile</div></a>
|
||||
<a href={'#'}><div className={'p-1'}>Feed</div></a>
|
||||
<a href={'/user/settings'}><div className={'p-1'}>Settings</div></a>
|
||||
<Link to={'/add-location'} onClick={() => setPageState({ ...pageState, profileMenu: !pageState.profileMenu })}><div className={'p-1'}>Add location</div></Link>
|
||||
<Link to={'/user/profile'}><div className={'p-1'}>Profile</div></Link>
|
||||
<Link to={'#'}><div className={'p-1'}>Feed</div></Link>
|
||||
<Link to={'/user/settings'}><div className={'p-1'}>Settings</div></Link>
|
||||
{user.is_admin &&
|
||||
<a href={'/submissions'} ><div className={'p-1'}>Submissions</div></a>
|
||||
<Link to={'/submissions'} ><div className={'p-1'}>Submissions</div></Link>
|
||||
}
|
||||
<a href={'#'} onClick={handleLogout}><div className={'p-1'}>Logout</div></a>
|
||||
<Link to={'#'} onClick={handleLogout}><div className={'p-1'}>Logout</div></Link>
|
||||
{/* <div className={'p-2'}><a href={'#'}>Halo</a></div> */}
|
||||
{/* <div className={'p-2'}><a href={'#'}>Halo</a></div> */}
|
||||
</div>
|
||||
|
12
src/components/LoadingAnimation/Default/index.tsx
Executable file
12
src/components/LoadingAnimation/Default/index.tsx
Executable file
@ -0,0 +1,12 @@
|
||||
import { JSXInternal } from "node_modules/preact/src/jsx";
|
||||
import "../style.css"
|
||||
|
||||
type DefaultLoadingAnimationProps = {
|
||||
style: JSXInternal.CSSProperties
|
||||
}
|
||||
|
||||
const DefaultLoadingAnimation = (props: DefaultLoadingAnimationProps) => (
|
||||
<div style={props.style} class="loader"></div>
|
||||
)
|
||||
|
||||
export default DefaultLoadingAnimation;
|
21
src/components/LoadingAnimation/style.css
Executable file
21
src/components/LoadingAnimation/style.css
Executable file
@ -0,0 +1,21 @@
|
||||
.loader {
|
||||
width: 30px;
|
||||
padding: 8px;
|
||||
aspect-ratio: 1;
|
||||
border-radius: 50%;
|
||||
background: #a8adb3;
|
||||
--_m:
|
||||
conic-gradient(#0000 10%, #000),
|
||||
linear-gradient(#000 0 0) content-box;
|
||||
-webkit-mask: var(--_m);
|
||||
mask: var(--_m);
|
||||
-webkit-mask-composite: source-out;
|
||||
mask-composite: subtract;
|
||||
animation: l3 1s infinite linear;
|
||||
}
|
||||
|
||||
@keyframes l3 {
|
||||
to {
|
||||
transform: rotate(1turn)
|
||||
}
|
||||
}
|
113
src/components/Select/Default.tsx
Executable file
113
src/components/Select/Default.tsx
Executable file
@ -0,0 +1,113 @@
|
||||
// import { cx } from "class-variance-authority";
|
||||
// import Downshift from "downshift";
|
||||
// import "../Header/style.css";
|
||||
|
||||
// type DefaultSelectProps = {
|
||||
// data: any,
|
||||
// onInput: (val: string) => void;
|
||||
// inputValue: string
|
||||
// }
|
||||
|
||||
// function DefaultSelect(props: DefaultSelectProps) {
|
||||
// const items = [
|
||||
// { author: 'Harper Lee', title: 'To Kill a Mockingbird' },
|
||||
// { author: 'Lev Tolstoy', title: 'War and Peace' },
|
||||
// { author: 'Fyodor Dostoyevsy', title: 'The Idiot' },
|
||||
// { author: 'Oscar Wilde', title: 'A Picture of Dorian Gray' },
|
||||
// { author: 'George Orwell', title: '1984' },
|
||||
// { author: 'Jane Austen', title: 'Pride and Prejudice' },
|
||||
// { author: 'Marcus Aurelius', title: 'Meditations' },
|
||||
// { author: 'Fyodor Dostoevsky', title: 'The Brothers Karamazov' },
|
||||
// { author: 'Lev Tolstoy', title: 'Anna Karenina' },
|
||||
// { author: 'Fyodor Dostoevsky', title: 'Crime and Punishment' },
|
||||
// ];
|
||||
|
||||
// return (
|
||||
// <Downshift
|
||||
// onChange={selection =>
|
||||
// alert(
|
||||
// selection
|
||||
// ? `You selected "${selection.title}" by ${selection.author}. Great Choice!`
|
||||
// : 'Selection Cleared',
|
||||
// )
|
||||
// }
|
||||
// itemToString={item => (item ? item.title : '')}
|
||||
// >
|
||||
// {({
|
||||
// getInputProps,
|
||||
// getItemProps,
|
||||
// getLabelProps,
|
||||
// getMenuProps,
|
||||
// getToggleButtonProps,
|
||||
// isOpen,
|
||||
// inputValue,
|
||||
// highlightedIndex,
|
||||
// selectedItem,
|
||||
// closeMenu,
|
||||
// }) => {
|
||||
// inputValue = props.inputValue
|
||||
|
||||
// return (
|
||||
// <div>
|
||||
// <div className="w-72 flex flex-col gap-1">
|
||||
// <div style={{ borderRadius: 2 }}>
|
||||
// <input
|
||||
// placeholder="Candi Borobudur, Tunjungan Plaza ..."
|
||||
// style={{ minHeight: 45 }}
|
||||
// className="w-full bg-secondary p-1.5"
|
||||
// {...getInputProps({
|
||||
// onChange: val => props.onInput(val),
|
||||
// onKeyDown: event => {
|
||||
// if (event.key === 'ArrowUp' && highlightedIndex === 0) {
|
||||
// // If at the top, close the menu
|
||||
// event.preventDefault();
|
||||
// closeMenu();
|
||||
// }
|
||||
|
||||
// if(event.key === 'Enter') {
|
||||
// alert(props.inputValue)
|
||||
// }
|
||||
// },
|
||||
// })}
|
||||
// />
|
||||
// </div>
|
||||
// </div>
|
||||
// <ul
|
||||
// className={`absolute w-72 bg-secondary mt-1 shadow-md max-h-80 overflow-scroll p-0 z-10 ${!(isOpen && items.length) && 'hidden'
|
||||
// }`}
|
||||
// {...getMenuProps()}
|
||||
// >
|
||||
// {isOpen
|
||||
// ? items
|
||||
// .filter(
|
||||
// item =>
|
||||
// !inputValue ||
|
||||
// item.title.toLowerCase().includes(inputValue.toLowerCase()) ||
|
||||
// item.author.toLowerCase().includes(inputValue.toLowerCase()),
|
||||
// )
|
||||
// .map((item, index) => (
|
||||
// <li
|
||||
// className={cx(
|
||||
// highlightedIndex === index && 'bg-tertiary',
|
||||
// 'py-2 px-3 flex flex-col',
|
||||
// )}
|
||||
// {...getItemProps({
|
||||
// key: item.title,
|
||||
// index,
|
||||
// item,
|
||||
// })}
|
||||
// >
|
||||
// <span>{item.title}</span>
|
||||
// <span className="text-sm text-gray-700">{item.author}</span>
|
||||
// </li>
|
||||
// ))
|
||||
// : null}
|
||||
// </ul>
|
||||
// </div>
|
||||
// )
|
||||
// }}
|
||||
// </Downshift>
|
||||
// );
|
||||
// }
|
||||
|
||||
// export default DefaultSelect;
|
@ -1,11 +1,11 @@
|
||||
export type LocationInfo = {
|
||||
id: Number,
|
||||
id: number,
|
||||
name: string,
|
||||
thumbnail: string | null,
|
||||
regency_name: String,
|
||||
province_name: String,
|
||||
critic_score: Number,
|
||||
critic_count: Number,
|
||||
user_score: Number,
|
||||
user_count: Number
|
||||
critic_score: number,
|
||||
critic_count: number,
|
||||
user_score: number,
|
||||
user_count: number
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import './style.css';
|
||||
import { createLocationService } from "../../services/locations";
|
||||
import { useSelector } from "react-redux";
|
||||
import { UserRootState } from "../../store/type";
|
||||
import DefaultLoadingAnimation from "../../components/LoadingAnimation/Default";
|
||||
|
||||
function AddLocation() {
|
||||
const [recentLocations, setRecentLocations] = useState<Array<LocationInfo>>()
|
||||
@ -24,6 +25,7 @@ function AddLocation() {
|
||||
regency: emptyRegency(),
|
||||
thumbnails: [],
|
||||
})
|
||||
const [submitLoading, setSubmitLoading ] = useState<boolean>(false)
|
||||
|
||||
const user = useSelector((state: UserRootState) => state.auth)
|
||||
|
||||
@ -33,7 +35,7 @@ function AddLocation() {
|
||||
|
||||
async function getRecentLocations() {
|
||||
try {
|
||||
const locations = await getListRecentLocationsRatingsService(9)
|
||||
const locations = await getListRecentLocationsRatingsService(10, 1)
|
||||
setRecentLocations(locations.data)
|
||||
// setIsLoading(false)
|
||||
} catch (error) {
|
||||
@ -61,6 +63,8 @@ function AddLocation() {
|
||||
async function onSubmitForm(e: TargetedEvent) {
|
||||
e.preventDefault();
|
||||
|
||||
setSubmitLoading(true)
|
||||
|
||||
if(form.regency.regency_name === '') {
|
||||
setPageState({ regency_form_error: true })
|
||||
return
|
||||
@ -86,8 +90,8 @@ function AddLocation() {
|
||||
|
||||
try {
|
||||
await createLocationService(formData)
|
||||
alert("Location Added")
|
||||
|
||||
setSubmitLoading(false)
|
||||
alert("Location Added\nModerator will check the submission because we don't trust you")
|
||||
} catch(error) {
|
||||
console.log(error)
|
||||
}
|
||||
@ -214,8 +218,11 @@ function AddLocation() {
|
||||
{form.thumbnails.length > 0 &&
|
||||
<a className={'block mt-2'} onClick={onDeleteAllThumbnails}>Delete All Thumbnails</a>
|
||||
}
|
||||
|
||||
<input type={'submit'} value={'Submit'} className={'block p-1 text-sm text-primary mt-4'} style={{ backgroundColor: '#a8adb3', letterSpacing: .5, width: 75 }} />
|
||||
{submitLoading ?
|
||||
<DefaultLoadingAnimation style={{ marginTop: 20 }} />
|
||||
:
|
||||
<input type={'submit'} value={'Submit'} className={'block p-1 text-sm text-primary mt-4'} style={{ backgroundColor: '#a8adb3', letterSpacing: .5, width: 75 }} />
|
||||
}
|
||||
</form>
|
||||
<span className={'mt-5 text-sm font-bold block'}>NOTE: LOCATION SUBMISSION MAY BE EDITED BY MODERATOR SO DON'T PUT STUPID ASS THUMBNAILS YOU 1 CENT DOORKNOB</span>
|
||||
</div>
|
||||
|
@ -4,6 +4,7 @@ import { getListTopLocationsService } from "../../services";
|
||||
import { DefaultSeparator } from "../../components";
|
||||
import './style.css';
|
||||
import { useClick, useFloating, useInteractions } from "@floating-ui/react";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
interface TopLocation {
|
||||
row_number: Number,
|
||||
@ -139,12 +140,12 @@ 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>
|
||||
<Link className={'text-xl'} to={`/location/${x.id}`}>{x.row_number}.{x.name}</Link>
|
||||
</div>
|
||||
<div style={{ maxWidth: 200, maxHeight: 200, margin: '0 30px 30px 10px', float: 'left' }}>
|
||||
<a href={`/location/${x.id}`} >
|
||||
<Link to={`/location/${x.id}`} >
|
||||
<img src={x.thumbnail ? x.thumbnail : ""} loading={'lazy'} style={{ width: '100%', objectFit: 'cover', height: '100%', aspectRatio: '1/1' }} />
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
<div className={'text-md font-bold'}>{x.regency_name}</div>
|
||||
<div className={'text-xs mb-2'}>{x.address}</div>
|
||||
|
@ -5,10 +5,10 @@ import { JSXInternal } from "node_modules/preact/src/jsx";
|
||||
import { getListRecentLocationsRatingsService, getRegenciesService, } from "../../services";
|
||||
import { LocationInfo, Regency } from "../../domains";
|
||||
import { ChangeEvent, TargetedEvent } from "preact/compat";
|
||||
import { LocationType, capitalize } from "../../types/common";
|
||||
import './style.css';
|
||||
import { LocationType } from "../../types/common";
|
||||
import { enumKeys } from "../../utils";
|
||||
import { getSearchLocationService } from "../../services/locations";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import './style.css';
|
||||
|
||||
|
||||
interface floatFilterArgs<T> {
|
||||
@ -129,6 +129,7 @@ function Discovery() {
|
||||
locationType: []
|
||||
});
|
||||
const [isFloatFilterOpen, setFloatFilterOpen] = useState(false)
|
||||
const navigate = useNavigate()
|
||||
|
||||
useEffect(() => {
|
||||
getLocationType()
|
||||
@ -147,8 +148,8 @@ function Discovery() {
|
||||
|
||||
async function getRecentLocations() {
|
||||
try {
|
||||
const locations = await getListRecentLocationsRatingsService(15)
|
||||
setData((prevState) => ({ ...prevState, locations: locations.data.locations }))
|
||||
const locations = await getListRecentLocationsRatingsService(15, 1)
|
||||
setData((prevState) => ({ ...prevState, locations: locations.data }))
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
}
|
||||
@ -232,6 +233,21 @@ function Discovery() {
|
||||
|
||||
}
|
||||
|
||||
function onClickLocation(id: number) {
|
||||
navigate(`/location/${id}`)
|
||||
}
|
||||
|
||||
function onDeleteByCityFilter(value: any) {
|
||||
const dataRegencies = data.searchRegencies as (Regency & { isSelected?: boolean })[];
|
||||
const regencyIdx = dataRegencies.findIndex(x => x.id == value.id);
|
||||
dataRegencies[regencyIdx].isSelected = !dataRegencies[regencyIdx].isSelected
|
||||
setData({
|
||||
...data,
|
||||
regencies: dataRegencies,
|
||||
searchRegencies: dataRegencies
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="content main-content mt-3">
|
||||
<section name="header">
|
||||
@ -252,6 +268,7 @@ function Discovery() {
|
||||
{data.regencies.filter(x => x.isSelected).map(x => (
|
||||
<div style="align-self: stretch; justify-content: flex-start; align-items: center; gap: 12px; display: inline-flex">
|
||||
<div style="flex: 1 1 0; color: white; font-size: 14px; font-family: Poppins; font-weight: 500; line-height: 21px; letter-spacing: 0.56px; word-wrap: break-word">{x.regency_name}</div>
|
||||
<button onClick={() => onDeleteByCityFilter(x)} style={{ color: "white"}}>x</button>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
@ -291,7 +308,7 @@ function Discovery() {
|
||||
{data.locations.map(x => (
|
||||
<LocationCard
|
||||
containerClass='card-list-container'
|
||||
onCardClick={(id) => console.log(id)}
|
||||
onCardClick={onClickLocation}
|
||||
data={x}
|
||||
/>
|
||||
))}
|
||||
|
@ -27,8 +27,8 @@ function Home() {
|
||||
|
||||
async function getRecentLocations() {
|
||||
try {
|
||||
const locations = await getListRecentLocationsRatingsService(12)
|
||||
setRecentLocations(locations.data.locations)
|
||||
const locations = await getListRecentLocationsRatingsService(12, 1)
|
||||
setRecentLocations(locations.data)
|
||||
// setIsLoading(false)
|
||||
} catch (error) {
|
||||
console.log(error)
|
||||
|
@ -10,6 +10,7 @@ import { IHttpResponse } from "../../../src/types/common";
|
||||
import { useSelector } from "react-redux";
|
||||
import { UserRootState } from "src/store/type";
|
||||
import "./style.css"
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
function NewsEvent() {
|
||||
const [news, setNews] = useState<Array<News>>([]);
|
||||
@ -170,7 +171,7 @@ function NewsEvent() {
|
||||
</div>
|
||||
<div className={'submitted-info'} style={{ display: 'inline-block' }}>
|
||||
1d ago by
|
||||
<a> {x.submitted_by}</a>
|
||||
<Link to={'#'}> {x.submitted_by}</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -5,6 +5,7 @@ import "./style.css"
|
||||
import { useEffect, useState } from "preact/compat";
|
||||
import { getUserStatsService } from "../../services";
|
||||
import { CustomInterweave, SeparatorWithAnchor } from "../../components";
|
||||
import { Link } from "react-router-dom";
|
||||
|
||||
interface UserStats {
|
||||
followers: number,
|
||||
@ -105,31 +106,31 @@ function UserProfile() {
|
||||
|
||||
<section name={"profile-navigation"}>
|
||||
<div className={'bg-secondary profile-nav'}>
|
||||
<a>
|
||||
<Link to='#'>
|
||||
<div>
|
||||
summary
|
||||
</div>
|
||||
</a>
|
||||
<a>
|
||||
</Link>
|
||||
<Link to='#'>
|
||||
<div>
|
||||
reviews
|
||||
</div>
|
||||
</a>
|
||||
<a>
|
||||
</Link>
|
||||
<Link to='#'>
|
||||
<div>
|
||||
likes
|
||||
</div>
|
||||
</a>
|
||||
<a>
|
||||
</Link>
|
||||
<Link to='#'>
|
||||
<div>
|
||||
stories
|
||||
</div>
|
||||
</a>
|
||||
<a>
|
||||
</Link>
|
||||
<Link to='#'>
|
||||
<div>
|
||||
tags
|
||||
</div>
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
|
@ -36,7 +36,7 @@ function UserSettings() {
|
||||
const [form, setForm] = useState<UserInfo>({
|
||||
about: user.about,
|
||||
website: user.website,
|
||||
social_media: user.social_media
|
||||
social_media: user.social_media ?? []
|
||||
})
|
||||
|
||||
|
||||
@ -218,7 +218,7 @@ function UserSettings() {
|
||||
value={form.about}
|
||||
style={{ border: 'none', overflow: 'auto', outline: 'none', boxShadow: 'none', width: '100%', minHeight: 100, overflowY: 'hidden' }}
|
||||
/>
|
||||
<div className={'mt-2 mb-1'}>
|
||||
<div className={'mt-2 mb-5'}>
|
||||
<h2 className={'font-bold text-sm mb-1'}>WEBSITE</h2>
|
||||
<input className={'bg-secondary text-sm'} placeholder={'www.mywebsite.com'} style={{ width: '100%', borderRadius: 7, padding: '5px 10px' }} type={'text'} onChange={onChangeFormInput} name={'website'} value={form.website} />
|
||||
</div>
|
||||
|
@ -45,9 +45,9 @@ async function getListLocationsService({ page, page_size }: GetListLocationsArg)
|
||||
}
|
||||
}
|
||||
|
||||
async function getListRecentLocationsRatingsService(page_size: Number) {
|
||||
async function getListRecentLocationsRatingsService(page_size: number, page: number) {
|
||||
const newState = { ...initialState };
|
||||
const url = `${GET_LIST_RECENT_LOCATIONS_RATING_URI}?page_size=${page_size}`
|
||||
const url = `${GET_LIST_RECENT_LOCATIONS_RATING_URI}?page_size=${page_size}&page=${page}`
|
||||
try {
|
||||
const response = await client({ method: 'GET', url: url })
|
||||
switch (response.request.status) {
|
||||
|
@ -1,10 +1,11 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
"compilerOptions": {
|
||||
"composite": true,
|
||||
"skipLibCheck": true,
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"allowSyntheticDefaultImports": true
|
||||
},
|
||||
"include": ["vite.config.ts"]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user