diff --git a/packages/web/assets/search-icon.svg b/packages/web/assets/search-icon.svg index 6eabbeaa..0fc3fdb8 100644 --- a/packages/web/assets/search-icon.svg +++ b/packages/web/assets/search-icon.svg @@ -1,10 +1,3 @@ - - - - - - - - - + + diff --git a/packages/web/components/MegaMenu.tsx b/packages/web/components/MegaMenu.tsx index 72bda9dc..6f6c9e57 100644 --- a/packages/web/components/MegaMenu.tsx +++ b/packages/web/components/MegaMenu.tsx @@ -2,7 +2,6 @@ import { Avatar, Badge, Box, - BoxedNextImage, Button, ChevronDownIcon, ChevronUpIcon, @@ -11,12 +10,7 @@ import { Flex, HamburgerIcon, Icon, - Input, - InputGroup, - InputLeftElement, Link, - LinkBox, - LinkOverlay, LogOut, Menu, MenuButton, @@ -24,7 +18,6 @@ import { MenuList, MetaButton, Profile, - SelectSearch, SimpleGrid, Spinner, Stack, @@ -61,19 +54,17 @@ import { MetaLink } from 'components/Link'; import { PlayerFragmentFragment } from 'graphql/autogen/types'; import { usePSeedBalance } from 'lib/hooks/balances'; import Image from 'next/image'; -import { useRouter } from 'next/router'; +import router from 'next/router'; import React, { useCallback } from 'react'; -import { components } from 'react-select'; import AsyncSelect from 'react-select/async'; import { useDebouncedCallback } from 'use-debounce'; import { getPlayerImage, getPlayerName } from 'utils/playerHelpers'; -import SearchIcon from '../assets/search-icon.svg'; +// import SearchIcon from '../assets/search-icon.svg'; import SeedMarket from '../assets/seed-icon.svg'; import XPStar from '../assets/xp-star.svg'; -import { useNavSearch } from '../contexts/NavSearchContext'; -import { getGuildsByText } from '../graphql/getGuilds'; import { getPlayersByText } from '../graphql/getPlayers'; +import { getGuildsByText } from '../graphql/queries/guild'; import { useUser, useWeb3 } from '../lib/hooks'; import { MenuLinkItem, @@ -341,14 +332,13 @@ const SeeAllComponent = ({ text, url }: { text: string; url: string }) => ( // Search -- not working yet const Search = () => { const [inputValue, setValue] = React.useState(''); - const [selectedValue, setSelectedValue] = React.useState(null); - const [searchQuery, setSearchQuery] = React.useState(''); + const [selectedValue, setSelectedValue] = React.useState(''); const debounced = useDebouncedCallback(async () => { const { players } = await getPlayersByText(`%${inputValue}%`); const { guilds } = await getGuildsByText(`%${inputValue}%`); - const mappedPlayersOptions = players.map((player) => ({ + let mappedPlayersOptions = players.map((player) => ({ label: ( @@ -365,7 +355,7 @@ const Search = () => { value: player.username, })); - const mappedGuildsOptions = guilds.map((guild) => ({ + let mappedGuildsOptions = guilds.map((guild) => ({ value: guild.guildname, label: ( @@ -377,48 +367,58 @@ const Search = () => { ), })); - const mappedPlayers = - mappedPlayersOptions.length === 3 - ? [ - ...mappedPlayersOptions, - { - label: ( - - ), - value: '', - }, - ] - : mappedPlayersOptions; + if (mappedPlayersOptions.length === 3) { + mappedPlayersOptions = [ + ...mappedPlayersOptions, + { + label: ( + + ), + value: '', + }, + ]; + } + + if (mappedGuildsOptions.length === 3) { + mappedGuildsOptions = [ + ...mappedGuildsOptions, + { + label: ( + + ), + value: '', + }, + ]; + } return [ { label: 'Players', - options: mappedPlayers, + options: mappedPlayersOptions, }, { label: 'Guilds', options: mappedGuildsOptions, }, ]; - }, 300); - - const { setSearch } = useNavSearch(); - + }, 200); const handleSubmit = (e: React.ChangeEvent) => { e.preventDefault(); - setSearch(searchQuery); - setSearchQuery(''); + router.push(`/search/players?q=${inputValue}`); }; - const handleInputChange = (value: any) => { + const handleInputChange = (value: string) => { setValue(value); }; // handle selection - const handleChange = (value: any) => { + const handleChange = (value: string) => { setSelectedValue(value); }; @@ -556,7 +556,6 @@ const PlayerStats: React.FC = ({ player }) => { export const MegaMenu: React.FC = () => { const { connected, connect } = useWeb3(); - const router = useRouter(); const handleLoginClick = useCallback(async () => { await connect(); diff --git a/packages/web/components/SearchFilters.tsx b/packages/web/components/SearchFilters.tsx new file mode 100644 index 00000000..e673a6ec --- /dev/null +++ b/packages/web/components/SearchFilters.tsx @@ -0,0 +1,80 @@ +import { Box, Text, VStack, Wrap } from '@metafam/ds'; +// import NextLink from 'next/link'; +import { useRouter } from 'next/router'; +import React from 'react'; + +import { GlobalFilters } from '../utils/GlobalSearch'; + +const FilterItems = [ + { + name: GlobalFilters.PLAYERS, + baseUrl: '/search/players', + }, + { + name: GlobalFilters.GUILDS, + baseUrl: '/search/guilds', + }, + { + name: GlobalFilters.PATRONS, + baseUrl: '/search/patrons', + }, +]; + +const SearchFilters: any = ({ + activeFilter, + search, +}: { + activeFilter: string; + search: string; +}) => { + const router = useRouter(); + + return ( + + + Search Results for "{search}" + + + {FilterItems.map((item) => ( + router.push(`${item.baseUrl}?q=${search}`)} + > + + {item.name} + + + ))} + + + ); +}; + +export default SearchFilters; diff --git a/packages/web/components/Setup/SetupSkills.tsx b/packages/web/components/Setup/SetupSkills.tsx index 23610b56..dc15fae2 100644 --- a/packages/web/components/Setup/SetupSkills.tsx +++ b/packages/web/components/Setup/SetupSkills.tsx @@ -111,7 +111,6 @@ export const SetupSkills: React.FC = ({ setLoading(false); } }; - return ( {isWizard && ( diff --git a/packages/web/contexts/NavSearchContext.tsx b/packages/web/contexts/NavSearchContext.tsx deleted file mode 100644 index 2b6ababe..00000000 --- a/packages/web/contexts/NavSearchContext.tsx +++ /dev/null @@ -1,69 +0,0 @@ -import { useRouter } from 'next/router'; -import React, { useContext, useReducer } from 'react'; - -enum ActionKind { - SET_SEARCH = 'SET_SEARCH', - CLEAR_SEARCH = 'CLEAR_SEARCH', -} - -const INITIAL_STATE = { - search: '', -}; - -type NavSearchContextType = { - search: string; - setSearch: (search: string) => void; - clearSearch: () => void; -}; - -type State = { - search: string; -}; - -interface Action { - type: string; - payload: string; -} - -function searchReducer(state: State, action: Action) { - switch (action.type) { - case ActionKind.SET_SEARCH: - return { - ...state, - search: action.payload, - }; - default: - return state; - } -} - -export const NavSearchContext = React.createContext({ - search: '', - setSearch: () => {}, - clearSearch: () => {}, -}); - -export const NavSearchContextProvider: React.FC = ({ children }) => { - const [state, dispatch] = useReducer(searchReducer, INITIAL_STATE); - const router = useRouter(); - - const setSearch = (search: string) => { - dispatch({ type: ActionKind.SET_SEARCH, payload: search }); - router.push('/players'); - }; - - const clearSearch = () => { - dispatch({ type: ActionKind.SET_SEARCH, payload: '' }); - }; - - return ( - - {children} - - ); -}; - -export const useNavSearch = (): NavSearchContextType => - useContext(NavSearchContext); diff --git a/packages/web/graphql/getGuilds.ts b/packages/web/graphql/getGuilds.ts deleted file mode 100644 index 7bca2b4e..00000000 --- a/packages/web/graphql/getGuilds.ts +++ /dev/null @@ -1,38 +0,0 @@ -import gql from 'fake-tag'; -import { Client } from 'urql'; - -import { - GetGuildsByTextSearchDocument, - GetGuildsByTextSearchQuery, - GetGuildsByTextSearchQueryVariables, -} from './autogen/types'; -import { client as defaultClient } from './client'; -// eslint-disable-next-line @typescript-eslint/no-unused-expressions -gql` - query getGuildsByTextSearch($text: String) { - search_guilds(args: { search: $text }, limit: 3) { - id - guildname - logo - } - } -`; - -export const getGuildsByText = async ( - text: string, - client: Client = defaultClient, -) => { - const { data, error } = await client - .query( - GetGuildsByTextSearchDocument, - { - text, - }, - ) - .toPromise(); - - return { - guilds: data?.search_guilds || [], - error, - }; -}; diff --git a/packages/web/graphql/queries/guild.ts b/packages/web/graphql/queries/guild.ts index 29a1b846..647bdf81 100644 --- a/packages/web/graphql/queries/guild.ts +++ b/packages/web/graphql/queries/guild.ts @@ -2,6 +2,9 @@ import gql from 'fake-tag'; import { GuildPlayer } from 'graphql/types'; import { + GetCompleteGuildsByTextSearchDocument, + GetCompleteGuildsByTextSearchQuery, + GetCompleteGuildsByTextSearchQueryVariables, GetGuildMetadataQuery, GetGuildMetadataQueryVariables, GetGuildnamesQuery, @@ -10,6 +13,9 @@ import { GetGuildPlayersQueryVariables, GetGuildQuery, GetGuildQueryVariables, + GetGuildsByTextSearchDocument, + GetGuildsByTextSearchQuery, + GetGuildsByTextSearchQueryVariables, GetGuildsQuery, GetGuildsQueryVariables, GuildFragmentFragment, @@ -165,3 +171,55 @@ export const getGuildPlayers = async ( return guildPlayers; }; + +// eslint-disable-next-line @typescript-eslint/no-unused-expressions +gql` + query getGuildsByTextSearch($text: String) { + search_guilds(args: { search: $text }, limit: 3) { + id + guildname + logo + } + } +`; + +export const getGuildsByText = async (text: string) => { + const { data, error } = await client + .query( + GetGuildsByTextSearchDocument, + { + text, + }, + ) + .toPromise(); + + return { + guilds: data?.search_guilds || [], + error, + }; +}; + +// eslint-disable-next-line @typescript-eslint/no-unused-expressions +gql` + query getCompleteGuildsByTextSearch($text: String) { + search_guilds(args: { search: $text }, limit: 50) { + ...GuildFragment + } + } +`; + +export const getCompleteGuildsByText = async (text: string) => { + const { data, error } = await client + .query< + GetCompleteGuildsByTextSearchQuery, + GetCompleteGuildsByTextSearchQueryVariables + >(GetCompleteGuildsByTextSearchDocument, { + text, + }) + .toPromise(); + + return { + guilds: data?.search_guilds || [], + error, + }; +}; diff --git a/packages/web/package.json b/packages/web/package.json index 6657e72d..0f39fd01 100644 --- a/packages/web/package.json +++ b/packages/web/package.json @@ -55,17 +55,20 @@ "react-icons": "4.2.0", "react-qr-svg": "2.3.0", "react-resizable": "^3.0.4", + "react-select": "5.2.1", "react-vis": "^1.11.7", "rss-to-json": "2.0.2", "swr": "1.0.1", "urql": "2.0.2", + "use-debounce": "7.0.0", "web3modal": "1.9.4", "sourcecred": "0.9.0" }, "devDependencies": { "@types/react": "17.0.6", "@types/react-grid-layout": "^1.1.3", - "@types/react-vis": "^1.11.10" + "@types/react-vis": "^1.11.10", + "@types/react-select": "5.2.1" }, "resolutions": {} } diff --git a/packages/web/pages/_app.tsx b/packages/web/pages/_app.tsx index 590884a8..eaeabebb 100644 --- a/packages/web/pages/_app.tsx +++ b/packages/web/pages/_app.tsx @@ -7,7 +7,6 @@ import Head from 'next/head'; import { WithUrqlProps } from 'next-urql'; import React from 'react'; -import { NavSearchContextProvider } from '../contexts/NavSearchContext'; import { wrapUrqlClient } from '../graphql/client'; const App: React.FC = ({ @@ -55,13 +54,11 @@ const App: React.FC = ({ )} - - <> - {!pageProps.hideTopMenu && } - {!pageProps.hideTopMenu && } - - - + <> + {!pageProps.hideTopMenu && } + {!pageProps.hideTopMenu && } + + ); diff --git a/packages/web/pages/community/players.tsx b/packages/web/pages/community/players.tsx index 64514fc6..a2362eb8 100644 --- a/packages/web/pages/community/players.tsx +++ b/packages/web/pages/community/players.tsx @@ -17,8 +17,6 @@ import { useOnScreen } from 'lib/hooks/useOnScreen'; import { InferGetStaticPropsType } from 'next'; import React, { useEffect, useMemo, useRef } from 'react'; -import { useNavSearch } from '../contexts/NavSearchContext'; - type Props = InferGetStaticPropsType; export const getStaticProps = async () => { @@ -55,15 +53,6 @@ const Players: React.FC = () => { moreAvailable, } = usePlayerFilter(); - const { search, clearSearch } = useNavSearch(); - - useEffect(() => { - if (search !== '' && setQueryVariable) { - setQueryVariable('search', `%${search}%`); - clearSearch(); - } - }, [search, setQueryVariable, clearSearch]); - const moreRef = useRef(null); const onScreen = useOnScreen(moreRef); @@ -127,7 +116,7 @@ type MorePlayersProps = { showSeasonalXP?: boolean; }; -const MorePlayers = React.forwardRef( +export const MorePlayers = React.forwardRef( ({ fetching, totalCount, queryVariables, showSeasonalXP = false }, ref) => { const isTimezoneSelected = useMemo( () => queryVariables.timezones && queryVariables.timezones.length > 0, diff --git a/packages/web/pages/search/guilds.tsx b/packages/web/pages/search/guilds.tsx new file mode 100644 index 00000000..61abb931 --- /dev/null +++ b/packages/web/pages/search/guilds.tsx @@ -0,0 +1,33 @@ +import { PageContainer } from 'components/Container'; +import { GuildList } from 'components/Guild/GuildList'; +import { HeadComponent } from 'components/Seo'; +import { GuildFragmentFragment } from 'graphql/autogen/types'; +import { useRouter } from 'next/router'; +import React, { useEffect, useState } from 'react'; + +import SearchFilters from '../../components/SearchFilters'; +import { getCompleteGuildsByText } from '../../graphql/queries/guild'; +import { GlobalFilters } from '../../utils/GlobalSearch'; + +const GuildSearchPage = () => { + const { query } = useRouter(); + const [guilds, setGuilds] = useState([]); + const search: string = decodeURI(query.q as string); + useEffect(() => { + if (search) { + const getData = async () => { + const res = await getCompleteGuildsByText(`%${search}%`); + setGuilds(res.guilds); + }; + getData(); + } + }, [search]); + return ( + + + + + + ); +}; +export default GuildSearchPage; diff --git a/schema.graphql b/schema.graphql index de36198c..509e6995 100644 --- a/schema.graphql +++ b/schema.graphql @@ -206,23 +206,6 @@ type BoxProfile { website: String } -scalar bpchar - -""" -expression to compare columns of type bpchar. All fields are combined with logical 'AND'. -""" -input bpchar_comparison_exp { - _eq: bpchar - _gt: bpchar - _gte: bpchar - _in: [bpchar!] - _is_null: Boolean - _lt: bpchar - _lte: bpchar - _neq: bpchar - _nin: [bpchar!] -} - type BrightIdStatus { app: String! context: String! @@ -876,7 +859,7 @@ columns and relationships of "guild_metadata" """ type guild_metadata { - creator_id: uuid! + creator_id: uuid """Remote relationship field""" discordRoles: [DiscordRole!]! @@ -891,7 +874,7 @@ type guild_metadata { guild_id: uuid! """An object relationship""" - player: player! + player: player } """ @@ -3937,8 +3920,6 @@ type player { """An object relationship""" profile_cache: profile_cache - playerType: player_type - player_type_id: Int pronouns: String """An array relationship""" @@ -5976,7 +5957,6 @@ columns and relationships of "PlayerRole" """ type PlayerRole { description: String - emoji: bpchar label: String! role: String! } @@ -6023,7 +6003,6 @@ input PlayerRole_bool_exp { _not: PlayerRole_bool_exp _or: [PlayerRole_bool_exp] description: String_comparison_exp - emoji: bpchar_comparison_exp label: String_comparison_exp role: String_comparison_exp } @@ -6041,7 +6020,6 @@ input type for inserting data into table "PlayerRole" """ input PlayerRole_insert_input { description: String - emoji: bpchar label: String role: String } @@ -6111,7 +6089,6 @@ ordering options when selecting data from "PlayerRole" """ input PlayerRole_order_by { description: order_by - emoji: order_by label: order_by role: order_by } @@ -6130,9 +6107,6 @@ enum PlayerRole_select_column { """column name""" description - """column name""" - emoji - """column name""" label @@ -6145,7 +6119,6 @@ input type for updating data in table "PlayerRole" """ input PlayerRole_set_input { description: String - emoji: bpchar label: String role: String } @@ -6157,9 +6130,6 @@ enum PlayerRole_update_column { """column name""" description - """column name""" - emoji - """column name""" label @@ -7545,6 +7515,106 @@ type query_root { """fetch data from the table: "quest_skill" using primary key columns""" quest_skill_by_pk(quest_id: uuid!, skill_id: uuid!): quest_skill + """ + execute function "search_guilds" which returns "guild" + """ + search_guilds( + """ + input parameters for function "search_guilds" + """ + args: search_guilds_args! + + """distinct select on columns""" + distinct_on: [guild_select_column!] + + """limit the number of rows returned""" + limit: Int + + """skip the first n rows. Use only with order_by""" + offset: Int + + """sort the rows by one or more columns""" + order_by: [guild_order_by!] + + """filter the rows returned""" + where: guild_bool_exp + ): [guild!]! + + """ + execute function "search_guilds" and query aggregates on result of table type "guild" + """ + search_guilds_aggregate( + """ + input parameters for function "search_guilds" + """ + args: search_guilds_args! + + """distinct select on columns""" + distinct_on: [guild_select_column!] + + """limit the number of rows returned""" + limit: Int + + """skip the first n rows. Use only with order_by""" + offset: Int + + """sort the rows by one or more columns""" + order_by: [guild_order_by!] + + """filter the rows returned""" + where: guild_bool_exp + ): guild_aggregate! + + """ + execute function "search_players" which returns "player" + """ + search_players( + """ + input parameters for function "search_players" + """ + args: search_players_args! + + """distinct select on columns""" + distinct_on: [player_select_column!] + + """limit the number of rows returned""" + limit: Int + + """skip the first n rows. Use only with order_by""" + offset: Int + + """sort the rows by one or more columns""" + order_by: [player_order_by!] + + """filter the rows returned""" + where: player_bool_exp + ): [player!]! + + """ + execute function "search_players" and query aggregates on result of table type "player" + """ + search_players_aggregate( + """ + input parameters for function "search_players" + """ + args: search_players_args! + + """distinct select on columns""" + distinct_on: [player_select_column!] + + """limit the number of rows returned""" + limit: Int + + """skip the first n rows. Use only with order_by""" + offset: Int + + """sort the rows by one or more columns""" + order_by: [player_order_by!] + + """filter the rows returned""" + where: player_bool_exp + ): player_aggregate! + """ fetch data from the table: "skill" """ @@ -9176,6 +9246,14 @@ type SaveGuildResponse { success: Boolean } +input search_guilds_args { + search: String +} + +input search_players_args { + search: String +} + """ columns and relationships of "skill" """ @@ -10662,6 +10740,106 @@ type subscription_root { """fetch data from the table: "quest_skill" using primary key columns""" quest_skill_by_pk(quest_id: uuid!, skill_id: uuid!): quest_skill + """ + execute function "search_guilds" which returns "guild" + """ + search_guilds( + """ + input parameters for function "search_guilds" + """ + args: search_guilds_args! + + """distinct select on columns""" + distinct_on: [guild_select_column!] + + """limit the number of rows returned""" + limit: Int + + """skip the first n rows. Use only with order_by""" + offset: Int + + """sort the rows by one or more columns""" + order_by: [guild_order_by!] + + """filter the rows returned""" + where: guild_bool_exp + ): [guild!]! + + """ + execute function "search_guilds" and query aggregates on result of table type "guild" + """ + search_guilds_aggregate( + """ + input parameters for function "search_guilds" + """ + args: search_guilds_args! + + """distinct select on columns""" + distinct_on: [guild_select_column!] + + """limit the number of rows returned""" + limit: Int + + """skip the first n rows. Use only with order_by""" + offset: Int + + """sort the rows by one or more columns""" + order_by: [guild_order_by!] + + """filter the rows returned""" + where: guild_bool_exp + ): guild_aggregate! + + """ + execute function "search_players" which returns "player" + """ + search_players( + """ + input parameters for function "search_players" + """ + args: search_players_args! + + """distinct select on columns""" + distinct_on: [player_select_column!] + + """limit the number of rows returned""" + limit: Int + + """skip the first n rows. Use only with order_by""" + offset: Int + + """sort the rows by one or more columns""" + order_by: [player_order_by!] + + """filter the rows returned""" + where: player_bool_exp + ): [player!]! + + """ + execute function "search_players" and query aggregates on result of table type "player" + """ + search_players_aggregate( + """ + input parameters for function "search_players" + """ + args: search_players_args! + + """distinct select on columns""" + distinct_on: [player_select_column!] + + """limit the number of rows returned""" + limit: Int + + """skip the first n rows. Use only with order_by""" + offset: Int + + """sort the rows by one or more columns""" + order_by: [player_order_by!] + + """filter the rows returned""" + where: player_bool_exp + ): player_aggregate! + """ fetch data from the table: "skill" """ @@ -10767,3 +10945,4 @@ input uuid_comparison_exp { _neq: uuid _nin: [uuid!] } +