Implement searching for/adding guidebooks to party
This commit is contained in:
parent
926e892b51
commit
c793fdb6a9
6 changed files with 147 additions and 10 deletions
37
components/extra/GuidebookResult/index.scss
Normal file
37
components/extra/GuidebookResult/index.scss
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
.GuidebookResult {
|
||||||
|
border-radius: 6px;
|
||||||
|
display: flex;
|
||||||
|
gap: $unit;
|
||||||
|
padding: $unit * 1.5;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: var(--button-contained-bg);
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.Info h5 {
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
background: $grey-80;
|
||||||
|
border-radius: 6px;
|
||||||
|
display: inline-block;
|
||||||
|
height: auto;
|
||||||
|
width: 90px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
flex-grow: 1;
|
||||||
|
gap: $unit-half;
|
||||||
|
|
||||||
|
h5 {
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
display: inline-block;
|
||||||
|
font-size: $font-medium;
|
||||||
|
font-weight: $medium;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
32
components/extra/GuidebookResult/index.tsx
Normal file
32
components/extra/GuidebookResult/index.tsx
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
import React from 'react'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
|
||||||
|
import './index.scss'
|
||||||
|
|
||||||
|
interface Props {
|
||||||
|
data: Guidebook
|
||||||
|
onClick: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const GuidebookResult = (props: Props) => {
|
||||||
|
const router = useRouter()
|
||||||
|
const locale =
|
||||||
|
router.locale && ['en', 'ja'].includes(router.locale) ? router.locale : 'en'
|
||||||
|
|
||||||
|
const guidebook = props.data
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li className="GuidebookResult" onClick={props.onClick}>
|
||||||
|
<img
|
||||||
|
alt={guidebook.name[locale]}
|
||||||
|
src={`${process.env.NEXT_PUBLIC_SIERO_IMG_URL}/guidebooks/book_${guidebook.granblue_id}.png`}
|
||||||
|
/>
|
||||||
|
<div className="Info">
|
||||||
|
<h5>{guidebook.name[locale]}</h5>
|
||||||
|
<p>{guidebook.description[locale]}</p>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GuidebookResult
|
||||||
|
|
@ -22,9 +22,6 @@ import type { DetailsObject } from '~types'
|
||||||
|
|
||||||
import './index.scss'
|
import './index.scss'
|
||||||
|
|
||||||
import WeaponRep from '~components/reps/WeaponRep'
|
|
||||||
import CharacterRep from '~components/reps/CharacterRep'
|
|
||||||
import SummonRep from '~components/reps/SummonRep'
|
|
||||||
import PartyHeader from '../PartyHeader'
|
import PartyHeader from '../PartyHeader'
|
||||||
|
|
||||||
// Props
|
// Props
|
||||||
|
|
@ -139,8 +136,11 @@ const Party = (props: Props) => {
|
||||||
if (details.turnCount) payload.turn_count = details.turnCount
|
if (details.turnCount) payload.turn_count = details.turnCount
|
||||||
if (details.extra) payload.extra = details.extra
|
if (details.extra) payload.extra = details.extra
|
||||||
if (details.job) payload.job_id = details.job.id
|
if (details.job) payload.job_id = details.job.id
|
||||||
|
if (details.guidebook0_id) payload.guidebook0_id = details.guidebook0_id
|
||||||
|
if (details.guidebook1_id) payload.guidebook1_id = details.guidebook1_id
|
||||||
|
if (details.guidebook2_id) payload.guidebook2_id = details.guidebook2_id
|
||||||
|
|
||||||
if (Object.keys(payload).length > 1) return { party: payload }
|
if (Object.keys(payload).length >= 1) return { party: payload }
|
||||||
else return {}
|
else return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,17 +154,31 @@ const Party = (props: Props) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkboxChanged(event: React.ChangeEvent<HTMLInputElement>) {
|
function checkboxChanged(enabled: boolean) {
|
||||||
appState.party.extra = event.target.checked
|
appState.party.extra = enabled
|
||||||
|
|
||||||
// Only save if this is a saved party
|
// Only save if this is a saved party
|
||||||
if (props.team && props.team.id) {
|
if (props.team && props.team.id) {
|
||||||
api.endpoints.parties.update(props.team.id, {
|
api.endpoints.parties.update(props.team.id, {
|
||||||
party: { extra: event.target.checked },
|
party: { extra: enabled },
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateGuidebook(book: Guidebook, position: number) {
|
||||||
|
const details: DetailsObject = {
|
||||||
|
guidebook0_id: position === 0 ? book.id : undefined,
|
||||||
|
guidebook1_id: position === 1 ? book.id : undefined,
|
||||||
|
guidebook2_id: position === 2 ? book.id : undefined,
|
||||||
|
}
|
||||||
|
|
||||||
|
if (props.team && props.team.id) {
|
||||||
|
updateParty(details)
|
||||||
|
} else {
|
||||||
|
createParty(details)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Remixing the party
|
// Remixing the party
|
||||||
function remixTeam() {
|
function remixTeam() {
|
||||||
// setOriginalName(partySnapshot.name ? partySnapshot.name : t('no_title'))
|
// setOriginalName(partySnapshot.name ? partySnapshot.name : t('no_title'))
|
||||||
|
|
@ -230,6 +244,7 @@ const Party = (props: Props) => {
|
||||||
appState.party.id = team.id
|
appState.party.id = team.id
|
||||||
appState.party.shortcode = team.shortcode
|
appState.party.shortcode = team.shortcode
|
||||||
appState.party.extra = team.extra
|
appState.party.extra = team.extra
|
||||||
|
appState.party.guidebooks = team.guidebooks
|
||||||
appState.party.user = team.user
|
appState.party.user = team.user
|
||||||
appState.party.favorited = team.favorited
|
appState.party.favorited = team.favorited
|
||||||
appState.party.remix = team.remix
|
appState.party.remix = team.remix
|
||||||
|
|
@ -334,8 +349,11 @@ const Party = (props: Props) => {
|
||||||
new={props.new || false}
|
new={props.new || false}
|
||||||
editable={editable}
|
editable={editable}
|
||||||
weapons={props.team?.weapons}
|
weapons={props.team?.weapons}
|
||||||
|
guidebooks={props.team?.guidebooks}
|
||||||
createParty={createParty}
|
createParty={createParty}
|
||||||
pushHistory={props.pushHistory}
|
pushHistory={props.pushHistory}
|
||||||
|
updateExtra={checkboxChanged}
|
||||||
|
updateGuidebook={updateGuidebook}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -384,6 +402,7 @@ const Party = (props: Props) => {
|
||||||
{navigation}
|
{navigation}
|
||||||
|
|
||||||
<section id="Party">{currentGrid()}</section>
|
<section id="Party">{currentGrid()}</section>
|
||||||
|
|
||||||
<PartyDetails
|
<PartyDetails
|
||||||
party={props.team}
|
party={props.team}
|
||||||
new={props.new || false}
|
new={props.new || false}
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,11 @@
|
||||||
#Results {
|
#Results {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0 ($unit * 1.5);
|
padding: 0 ($unit * 1.5);
|
||||||
|
padding-bottom: $unit * 1.5;
|
||||||
|
|
||||||
|
// Infinite scroll
|
||||||
|
overflow-y: auto;
|
||||||
|
max-height: 500px;
|
||||||
|
|
||||||
@include breakpoint(phone) {
|
@include breakpoint(phone) {
|
||||||
max-height: inherit;
|
max-height: inherit;
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ import CharacterResult from '~components/character/CharacterResult'
|
||||||
import WeaponResult from '~components/weapon/WeaponResult'
|
import WeaponResult from '~components/weapon/WeaponResult'
|
||||||
import SummonResult from '~components/summon/SummonResult'
|
import SummonResult from '~components/summon/SummonResult'
|
||||||
import JobSkillResult from '~components/job/JobSkillResult'
|
import JobSkillResult from '~components/job/JobSkillResult'
|
||||||
|
import GuidebookResult from '~components/extra/GuidebookResult'
|
||||||
|
|
||||||
import type { DialogProps } from '@radix-ui/react-dialog'
|
import type { DialogProps } from '@radix-ui/react-dialog'
|
||||||
import type { SearchableObject, SearchableObjectArray } from '~types'
|
import type { SearchableObject, SearchableObjectArray } from '~types'
|
||||||
|
|
@ -31,7 +32,7 @@ interface Props extends DialogProps {
|
||||||
placeholderText: string
|
placeholderText: string
|
||||||
fromPosition: number
|
fromPosition: number
|
||||||
job?: Job
|
job?: Job
|
||||||
object: 'weapons' | 'characters' | 'summons' | 'job_skills'
|
object: 'weapons' | 'characters' | 'summons' | 'job_skills' | 'guidebooks'
|
||||||
}
|
}
|
||||||
|
|
||||||
const SearchModal = (props: Props) => {
|
const SearchModal = (props: Props) => {
|
||||||
|
|
@ -184,7 +185,7 @@ const SearchModal = (props: Props) => {
|
||||||
} else if (open && currentPage == 1) {
|
} else if (open && currentPage == 1) {
|
||||||
fetchResults({ replace: true })
|
fetchResults({ replace: true })
|
||||||
}
|
}
|
||||||
}, [currentPage])
|
}, [open, currentPage])
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Filters changed
|
// Filters changed
|
||||||
|
|
@ -219,6 +220,17 @@ const SearchModal = (props: Props) => {
|
||||||
}
|
}
|
||||||
}, [query])
|
}, [query])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (open && props.object === 'guidebooks') {
|
||||||
|
setCurrentPage(1)
|
||||||
|
fetchResults({ replace: true })
|
||||||
|
}
|
||||||
|
}, [query, open])
|
||||||
|
|
||||||
|
function incrementPage() {
|
||||||
|
setCurrentPage(currentPage + 1)
|
||||||
|
}
|
||||||
|
|
||||||
function renderResults() {
|
function renderResults() {
|
||||||
let jsx
|
let jsx
|
||||||
|
|
||||||
|
|
@ -235,12 +247,15 @@ const SearchModal = (props: Props) => {
|
||||||
case 'job_skills':
|
case 'job_skills':
|
||||||
jsx = renderJobSkillSearchResults(results)
|
jsx = renderJobSkillSearchResults(results)
|
||||||
break
|
break
|
||||||
|
case 'guidebooks':
|
||||||
|
jsx = renderGuidebookSearchResults(results)
|
||||||
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<InfiniteScroll
|
<InfiniteScroll
|
||||||
dataLength={results && results.length > 0 ? results.length : 0}
|
dataLength={results && results.length > 0 ? results.length : 0}
|
||||||
next={() => setCurrentPage(currentPage + 1)}
|
next={incrementPage}
|
||||||
hasMore={totalPages > currentPage}
|
hasMore={totalPages > currentPage}
|
||||||
scrollableTarget="Results"
|
scrollableTarget="Results"
|
||||||
loader={<div className="footer">Loading...</div>}
|
loader={<div className="footer">Loading...</div>}
|
||||||
|
|
@ -334,6 +349,27 @@ const SearchModal = (props: Props) => {
|
||||||
return jsx
|
return jsx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function renderGuidebookSearchResults(results: { [key: string]: any }) {
|
||||||
|
let jsx: React.ReactNode
|
||||||
|
|
||||||
|
const castResults: Guidebook[] = results as Guidebook[]
|
||||||
|
if (castResults && Object.keys(castResults).length > 0) {
|
||||||
|
jsx = castResults.map((result: Guidebook) => {
|
||||||
|
return (
|
||||||
|
<GuidebookResult
|
||||||
|
key={result.id}
|
||||||
|
data={result}
|
||||||
|
onClick={() => {
|
||||||
|
storeRecentResult(result)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return jsx
|
||||||
|
}
|
||||||
|
|
||||||
function openChange() {
|
function openChange() {
|
||||||
if (open) {
|
if (open) {
|
||||||
setQuery('')
|
setQuery('')
|
||||||
|
|
@ -365,6 +401,7 @@ const SearchModal = (props: Props) => {
|
||||||
<DialogContent
|
<DialogContent
|
||||||
className="Search"
|
className="Search"
|
||||||
headerref={headerRef}
|
headerref={headerRef}
|
||||||
|
scrollable={false}
|
||||||
onEscapeKeyDown={onEscapeKeyDown}
|
onEscapeKeyDown={onEscapeKeyDown}
|
||||||
onOpenAutoFocus={onOpenAutoFocus}
|
onOpenAutoFocus={onOpenAutoFocus}
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -121,6 +121,13 @@ const WeaponGrid = (props: Props) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function receiveGuidebookFromSearch(
|
||||||
|
object: SearchableObject,
|
||||||
|
position: number
|
||||||
|
) {
|
||||||
|
props.updateGuidebook(object as Guidebook, position)
|
||||||
|
}
|
||||||
|
|
||||||
async function handleWeaponResponse(data: any) {
|
async function handleWeaponResponse(data: any) {
|
||||||
if (data.hasOwnProperty('conflicts')) {
|
if (data.hasOwnProperty('conflicts')) {
|
||||||
if (data.incoming) setIncoming(data.incoming)
|
if (data.incoming) setIncoming(data.incoming)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue