Add optional toggle for Extra grid slots
This commit is contained in:
parent
59096faec9
commit
d1b8e52bdb
12 changed files with 300 additions and 34 deletions
32
src/components/ExtraWeapons/index.scss
Normal file
32
src/components/ExtraWeapons/index.scss
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
.ExtraWeapons {
|
||||
background: #ECEBFF;
|
||||
border-radius: 8px;
|
||||
box-sizing: border-box;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin: 20px auto;
|
||||
max-width: 766px;
|
||||
padding: 16px 16px 16px 0;
|
||||
position: relative;
|
||||
left: 8px;
|
||||
|
||||
& > span {
|
||||
color: #4F3C79;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
line-height: 1.2;
|
||||
font-weight: 500;
|
||||
margin-right: 16px;
|
||||
text-align: center;
|
||||
width: 206px;
|
||||
}
|
||||
|
||||
.WeaponUnit .WeaponImage {
|
||||
background: #D5D3F6;
|
||||
}
|
||||
|
||||
.WeaponUnit .WeaponImage .icon svg {
|
||||
fill: #8F8AC6;
|
||||
}
|
||||
}
|
||||
54
src/components/ExtraWeapons/index.tsx
Normal file
54
src/components/ExtraWeapons/index.tsx
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
import React from 'react'
|
||||
import WeaponUnit from '~components/WeaponUnit'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
// GridType
|
||||
export enum GridType {
|
||||
Class,
|
||||
Character,
|
||||
Weapon,
|
||||
Summon
|
||||
}
|
||||
|
||||
// Props
|
||||
interface Props {
|
||||
grid: GridArray<Weapon>
|
||||
editable: boolean
|
||||
exists: boolean
|
||||
found?: boolean
|
||||
onSelect: (type: GridType, weapon: Weapon, position: number) => void
|
||||
}
|
||||
|
||||
const ExtraWeapons = (props: Props) => {
|
||||
const numWeapons: number = 3
|
||||
|
||||
function receiveWeapon(weapon: Weapon, position: number) {
|
||||
props.onSelect(GridType.Weapon, weapon, position)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="ExtraWeapons">
|
||||
<span>Additional<br />Weapons</span>
|
||||
<ul id="grid_weapons">
|
||||
{
|
||||
Array.from(Array(numWeapons)).map((x, i) => {
|
||||
return (
|
||||
<li key={`grid_unit_${i}`} >
|
||||
<WeaponUnit
|
||||
editable={props.editable}
|
||||
onReceiveData={receiveWeapon}
|
||||
position={i}
|
||||
unitType={1}
|
||||
weapon={props.grid[i]}
|
||||
/>
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default ExtraWeapons
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
.Extra {
|
||||
color: #888;
|
||||
display: flex;
|
||||
font-weight: 500;
|
||||
gap: 8px;
|
||||
line-height: 34px;
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import React, { useEffect, useState } from 'react'
|
||||
import React, { ChangeEvent, useEffect, useState } from 'react'
|
||||
import { useCookies } from 'react-cookie'
|
||||
import api from '~utils/api'
|
||||
|
||||
|
|
@ -28,6 +28,7 @@ interface Props {
|
|||
characters?: GridArray<Character>
|
||||
weapons?: GridArray<Weapon>
|
||||
summons?: GridArray<Summon>
|
||||
extra: boolean
|
||||
editable: boolean
|
||||
exists: boolean
|
||||
pushHistory?: (path: string) => void
|
||||
|
|
@ -51,6 +52,8 @@ const Party = (props: Props) => {
|
|||
const [mainSummon, setMainSummon] = useState<Summon>()
|
||||
const [friendSummon, setFriendSummon] = useState<Summon>()
|
||||
|
||||
const [extra, setExtra] = useState<boolean>(false)
|
||||
|
||||
useEffect(() => {
|
||||
setPartyId(props.partyId || '')
|
||||
setMainWeapon(props.mainWeapon)
|
||||
|
|
@ -59,7 +62,8 @@ const Party = (props: Props) => {
|
|||
setCharacters(props.characters || {})
|
||||
setWeapons(props.weapons || {})
|
||||
setSummons(props.summons || {})
|
||||
}, [props.partyId, props.mainWeapon, props.mainSummon, props.friendSummon, props.characters, props.weapons, props.summons])
|
||||
setExtra(props.extra || false)
|
||||
}, [props.partyId, props.mainWeapon, props.mainSummon, props.friendSummon, props.characters, props.weapons, props.summons, props.extra])
|
||||
|
||||
const weaponGrid = (
|
||||
<WeaponGrid
|
||||
|
|
@ -68,6 +72,7 @@ const Party = (props: Props) => {
|
|||
grid={weapons}
|
||||
editable={props.editable}
|
||||
exists={props.exists}
|
||||
extra={extra}
|
||||
onSelect={itemSelected}
|
||||
/>
|
||||
)
|
||||
|
|
@ -97,8 +102,15 @@ const Party = (props: Props) => {
|
|||
const [currentTab, setCurrentTab] = useState<GridType>(GridType.Weapon)
|
||||
const [partyId, setPartyId] = useState('')
|
||||
|
||||
function checkboxChanged(event: React.ChangeEvent<HTMLInputElement>) {
|
||||
setExtra(event.target.checked)
|
||||
}
|
||||
|
||||
function segmentClicked(event: React.ChangeEvent<HTMLInputElement>) {
|
||||
switch(event.target.value) {
|
||||
case 'class':
|
||||
setCurrentTab(GridType.Class)
|
||||
break
|
||||
case 'characters':
|
||||
setCurrentTab(GridType.Character)
|
||||
break
|
||||
|
|
@ -136,9 +148,14 @@ const Party = (props: Props) => {
|
|||
}
|
||||
|
||||
async function createParty() {
|
||||
const body = (cookies.userId === undefined) ? {} : {
|
||||
const body = (cookies.userId === undefined) ? {
|
||||
party: {
|
||||
user_id: cookies.userId
|
||||
is_extra: extra
|
||||
}
|
||||
} : {
|
||||
party: {
|
||||
user_id: cookies.userId,
|
||||
is_extra: extra
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -249,8 +266,11 @@ const Party = (props: Props) => {
|
|||
return (
|
||||
<div>
|
||||
<PartySegmentedControl
|
||||
extra={extra}
|
||||
editable={props.editable}
|
||||
selectedTab={currentTab}
|
||||
onClick={segmentClicked}
|
||||
onCheckboxChange={checkboxChanged}
|
||||
/>
|
||||
|
||||
{
|
||||
|
|
|
|||
16
src/components/PartySegmentedControl/index.scss
Normal file
16
src/components/PartySegmentedControl/index.scss
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
.PartyNavigation {
|
||||
display: flex;
|
||||
gap: 58px;
|
||||
justify-content: right;
|
||||
margin: 0 auto;
|
||||
max-width: 760px;
|
||||
}
|
||||
|
||||
.Extra {
|
||||
color: #888;
|
||||
display: flex;
|
||||
font-weight: 500;
|
||||
gap: 8px;
|
||||
line-height: 34px;
|
||||
height: 100%;
|
||||
}
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
import React from 'react'
|
||||
import './index.scss'
|
||||
|
||||
import SegmentedControl from '~components/SegmentedControl'
|
||||
import Segment from '~components/Segment'
|
||||
import ToggleSwitch from '~components/ToggleSwitch'
|
||||
|
||||
// GridType
|
||||
export enum GridType {
|
||||
|
|
@ -11,21 +14,23 @@ export enum GridType {
|
|||
}
|
||||
|
||||
interface Props {
|
||||
editable: boolean
|
||||
extra: boolean
|
||||
selectedTab: GridType
|
||||
onClick: (event: React.ChangeEvent<HTMLInputElement>) => void
|
||||
onCheckboxChange: (event: React.ChangeEvent<HTMLInputElement>) => void
|
||||
}
|
||||
|
||||
const PartySegmentedControl = (props: Props) => {
|
||||
|
||||
return (
|
||||
<div>
|
||||
<div className="PartyNavigation">
|
||||
<SegmentedControl>
|
||||
{/* <Segment
|
||||
<Segment
|
||||
groupName="grid"
|
||||
name="class"
|
||||
selected={props.selectedTab === GridType.Class}
|
||||
onClick={props.onClick}
|
||||
>Class</Segment> */}
|
||||
>Class</Segment>
|
||||
|
||||
<Segment
|
||||
groupName="grid"
|
||||
|
|
@ -48,6 +53,16 @@ const PartySegmentedControl = (props: Props) => {
|
|||
onClick={props.onClick}
|
||||
>Summons</Segment>
|
||||
</SegmentedControl>
|
||||
|
||||
<div className="Extra">
|
||||
Extra
|
||||
<ToggleSwitch
|
||||
name="Extra"
|
||||
editable={props.editable}
|
||||
checked={props.extra}
|
||||
onChange={props.onCheckboxChange}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
60
src/components/ToggleSwitch/index.scss
Normal file
60
src/components/ToggleSwitch/index.scss
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
.toggle-switch {
|
||||
background: #fff;
|
||||
border-radius: 18px;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 58px;
|
||||
|
||||
&-checkbox {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&-label {
|
||||
border-radius: 17px;
|
||||
display: block;
|
||||
cursor: pointer;
|
||||
height: 34px;
|
||||
margin: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
&-disabled {
|
||||
background-color: #ddd;
|
||||
cursor: not-allowed;
|
||||
|
||||
&:before {
|
||||
background-color: #ddd;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
}
|
||||
|
||||
&-switch {
|
||||
background: #e4e4e4;
|
||||
display: block;
|
||||
width: 24px;
|
||||
margin: 5px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
right: 24px;
|
||||
border-radius: 17px;
|
||||
transition: all 0.18s ease-in 0s;
|
||||
}
|
||||
|
||||
&-checkbox:checked + &-label {
|
||||
background: #ECEBFF;
|
||||
}
|
||||
|
||||
&-checkbox:checked + &-label &-switch {
|
||||
background: #8C86FF;
|
||||
}
|
||||
|
||||
&-checkbox:checked + &-label {
|
||||
.toggle-switch-inner {
|
||||
margin-left: 0;
|
||||
}
|
||||
.toggle-switch-switch {
|
||||
right: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
31
src/components/ToggleSwitch/index.tsx
Normal file
31
src/components/ToggleSwitch/index.tsx
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
import React from 'react'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
interface Props {
|
||||
name: string
|
||||
checked: boolean
|
||||
editable: boolean
|
||||
onChange: (event: React.ChangeEvent<HTMLInputElement>) => void
|
||||
}
|
||||
|
||||
const ToggleSwitch: React.FC<Props> = (props: Props) => {
|
||||
return (
|
||||
<div className="toggle-switch">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={props.checked}
|
||||
disabled={!props.editable}
|
||||
className="toggle-switch-checkbox"
|
||||
name={props.name}
|
||||
id={props.name}
|
||||
onChange={props.onChange}
|
||||
/>
|
||||
<label className="toggle-switch-label" htmlFor={props.name}>
|
||||
<span className="toggle-switch-switch" />
|
||||
</label>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ToggleSwitch
|
||||
|
|
@ -3,6 +3,10 @@
|
|||
justify-content: center;
|
||||
}
|
||||
|
||||
.ExtraWeapons #grid_weapons > * {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
#grid_weapons {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
import React from 'react'
|
||||
import WeaponUnit from '~components/WeaponUnit'
|
||||
import ExtraWeapons from '~components/ExtraWeapons'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
|
|
@ -17,6 +18,7 @@ interface Props {
|
|||
partyId?: string
|
||||
mainhand?: Weapon | undefined
|
||||
grid: GridArray<Weapon>
|
||||
extra: boolean
|
||||
editable: boolean
|
||||
exists: boolean
|
||||
found?: boolean
|
||||
|
|
@ -26,38 +28,59 @@ interface Props {
|
|||
const WeaponGrid = (props: Props) => {
|
||||
const numWeapons: number = 9
|
||||
|
||||
const extraGrid = (
|
||||
<ExtraWeapons
|
||||
grid={props.grid}
|
||||
editable={props.editable}
|
||||
exists={false}
|
||||
onSelect={
|
||||
function (type: GridType, weapon: Weapon, position: number): void {
|
||||
throw new Error('Function not implemented.')
|
||||
}
|
||||
}
|
||||
/>
|
||||
)
|
||||
|
||||
function receiveWeapon(weapon: Weapon, position: number) {
|
||||
props.onSelect(GridType.Weapon, weapon, position)
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="WeaponGrid">
|
||||
<WeaponUnit
|
||||
editable={props.editable}
|
||||
key="grid_mainhand"
|
||||
onReceiveData={receiveWeapon}
|
||||
position={-1}
|
||||
unitType={0}
|
||||
weapon={props.mainhand}
|
||||
/>
|
||||
<div id="weapon_grids">
|
||||
<div className="WeaponGrid">
|
||||
<WeaponUnit
|
||||
editable={props.editable}
|
||||
key="grid_mainhand"
|
||||
onReceiveData={receiveWeapon}
|
||||
position={-1}
|
||||
unitType={0}
|
||||
weapon={props.mainhand}
|
||||
/>
|
||||
|
||||
<ul id="grid_weapons">
|
||||
{
|
||||
Array.from(Array(numWeapons)).map((x, i) => {
|
||||
return (
|
||||
<li key={`grid_unit_${i}`} >
|
||||
<WeaponUnit
|
||||
editable={props.editable}
|
||||
onReceiveData={receiveWeapon}
|
||||
position={i}
|
||||
unitType={1}
|
||||
weapon={props.grid[i]}
|
||||
/>
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
<ul id="grid_weapons">
|
||||
{
|
||||
Array.from(Array(numWeapons)).map((x, i) => {
|
||||
return (
|
||||
<li key={`grid_unit_${i}`} >
|
||||
<WeaponUnit
|
||||
editable={props.editable}
|
||||
onReceiveData={receiveWeapon}
|
||||
position={i}
|
||||
unitType={1}
|
||||
weapon={props.grid[i]}
|
||||
/>
|
||||
</li>
|
||||
)
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
{ (() => {
|
||||
if(props.extra) {
|
||||
return extraGrid
|
||||
}
|
||||
})() }
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ const NewRoute: React.FC<Props> = () => {
|
|||
<div id="Content">
|
||||
<Party
|
||||
editable={true}
|
||||
extra={false}
|
||||
exists={false}
|
||||
pushHistory={callback}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ const PartyRoute: React.FC<PartyProps> = ({ match }) => {
|
|||
const [friendSummon, setFriendSummon] = useState<Summon>()
|
||||
|
||||
const [partyId, setPartyId] = useState('')
|
||||
const [extra, setExtra] = useState<boolean>(false)
|
||||
const [cookies, setCookie] = useCookies(['user'])
|
||||
const shortcode = match.params.hash || ''
|
||||
|
||||
|
|
@ -69,6 +70,7 @@ const PartyRoute: React.FC<PartyProps> = ({ match }) => {
|
|||
summons[gridSummon.position] = gridSummon.summon
|
||||
})
|
||||
|
||||
setExtra(response.data.party.is_extra)
|
||||
setFound(true)
|
||||
setLoading(false)
|
||||
setCharacters(characters)
|
||||
|
|
@ -101,6 +103,7 @@ const PartyRoute: React.FC<PartyProps> = ({ match }) => {
|
|||
summons={summons}
|
||||
editable={editable}
|
||||
exists={found}
|
||||
extra={extra}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue