Add optional toggle for Extra grid slots

This commit is contained in:
Justin Edmund 2022-01-14 20:39:49 -08:00
parent 59096faec9
commit d1b8e52bdb
12 changed files with 300 additions and 34 deletions

View 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;
}
}

View 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

View file

@ -0,0 +1,7 @@
.Extra {
color: #888;
display: flex;
font-weight: 500;
gap: 8px;
line-height: 34px;
}

View file

@ -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}
/>
{

View 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%;
}

View file

@ -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>
)
}

View 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;
}
}
}

View 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

View file

@ -3,6 +3,10 @@
justify-content: center;
}
.ExtraWeapons #grid_weapons > * {
margin-bottom: 0;
}
#grid_weapons {
display: flex;
flex-direction: row;

View file

@ -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>
)
}

View file

@ -15,6 +15,7 @@ const NewRoute: React.FC<Props> = () => {
<div id="Content">
<Party
editable={true}
extra={false}
exists={false}
pushHistory={callback}
/>

View file

@ -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>
)