From a32a16d6ba98d294a89b356e6bf42e7c15495d69 Mon Sep 17 00:00:00 2001 From: G3rg Date: Tue, 12 Oct 2021 14:32:33 +1000 Subject: [PATCH 01/15] Determine if a battlescribe file is for a roster or not --- src/parsers/KillTeam2021/BattlescribeParser.ts | 6 +++++- src/types/KillTeam2021.ts | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/parsers/KillTeam2021/BattlescribeParser.ts b/src/parsers/KillTeam2021/BattlescribeParser.ts index 5d8db855..16670e8d 100644 --- a/src/parsers/KillTeam2021/BattlescribeParser.ts +++ b/src/parsers/KillTeam2021/BattlescribeParser.ts @@ -126,6 +126,8 @@ export const parseBattlescribeXML = (doc: Document): Roster => { const operatives = [] const name = xpSelect('string(/bs:roster/@name)', doc, true).toString() const faction = xpSelect('string(//bs:force/@catalogueName)', doc, true).toString() + const isRoster = xpSelect('string(//bs:force/@name)', doc, true).toString() === 'Roster' + for (const model of xpSelect('//bs:selection[@type=\'model\']', doc) as Element[]) { operatives.push(parseOperative(model)) } @@ -149,12 +151,14 @@ export const parseBattlescribeXML = (doc: Document): Roster => { o.name = o.datacard + ' ' + romanNumerals[counts[o.datacard]++] } } + console.log(`Is Roster? ${isRoster}`) return { system: 'KillTeam2021', name, faction, operatives, psychicPowers, - fireteams + fireteams, + isRoster } } diff --git a/src/types/KillTeam2021.ts b/src/types/KillTeam2021.ts index 4aae186a..b5761589 100644 --- a/src/types/KillTeam2021.ts +++ b/src/types/KillTeam2021.ts @@ -93,6 +93,7 @@ export interface Roster { operatives: Operative[] psychicPowers: PsychicPower[] fireteams: string[] + isRoster?: boolean } export enum Archetype { From 42b60da4254f3041605a4e803e254f94477d42f6 Mon Sep 17 00:00:00 2001 From: G3rg Date: Tue, 12 Oct 2021 21:59:32 +1000 Subject: [PATCH 02/15] Display roster operatives --- src/App.tsx | 2 +- src/components/KillTeam2021/Roster.tsx | 18 +++++++++++++++++- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index db3308b3..5e092803 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -76,7 +76,7 @@ export function App () { {roster === null ? : <>} {(roster != null) && isRosterKT18(roster) ? : <>} - {(roster != null) && isRosterKT21(roster) ? : <>} + {(roster != null) && isRosterKT21(roster) ? : <>} diff --git a/src/components/KillTeam2021/Roster.tsx b/src/components/KillTeam2021/Roster.tsx index ec7a2eab..91eaf3c9 100644 --- a/src/components/KillTeam2021/Roster.tsx +++ b/src/components/KillTeam2021/Roster.tsx @@ -1,13 +1,14 @@ import React, { MouseEvent } from 'react' import { Col, Card } from 'react-bootstrap' import { CloseButton } from '../CloseButton' -import { Operative, Datacard, PsychicPower } from '../../types/KillTeam2021' +import {Operative, Datacard, PsychicPower, Stats, Weapon, Equipment, Action} from '../../types/KillTeam2021' import { Datasheet } from './Datasheet' import { RuleList } from './RuleList' import { PowerList } from './PowerList' import hash from 'node-object-hash' import _ from 'lodash' import { FactionSpecificData } from './FactionSpecificData' +import {Ability} from "../../types/Ability"; interface Props { name: string @@ -16,6 +17,7 @@ interface Props { psychicPowers: PsychicPower[] fireteams: string[] onClose: (event: MouseEvent) => void + isRoster?: boolean showWoundTrack: boolean } @@ -37,6 +39,7 @@ export function Roster (props: Props) { display: 'flex' } const datacards = groupByDatacard(props.operatives) + const fullOperatives = props.operatives.sort((a: Operative, b: Operative) => (a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0)) return ( <> @@ -48,6 +51,19 @@ export function Roster (props: Props) { + { props.isRoster && ( + + Roster + + Roster Size:{ fullOperatives.length } + { fullOperatives.map( (op, index) => { + return ( +
{index}:  {op.name} - {}
+ ) + })} +
+
+ )} {_.orderBy(datacards, ['leader', 'name'], ['desc', 'asc']).map((datacard: Datacard) => ( ))} From 7b8bfc0a5962d42bf25e237bbf3e35b5210b311b Mon Sep 17 00:00:00 2001 From: G3rg Date: Wed, 13 Oct 2021 13:33:25 +1000 Subject: [PATCH 03/15] Playing with operative display --- src/components/KillTeam2021/Roster.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/components/KillTeam2021/Roster.tsx b/src/components/KillTeam2021/Roster.tsx index 91eaf3c9..5e2c6739 100644 --- a/src/components/KillTeam2021/Roster.tsx +++ b/src/components/KillTeam2021/Roster.tsx @@ -1,5 +1,5 @@ import React, { MouseEvent } from 'react' -import { Col, Card } from 'react-bootstrap' +import { Col, Row, Card } from 'react-bootstrap' import { CloseButton } from '../CloseButton' import {Operative, Datacard, PsychicPower, Stats, Weapon, Equipment, Action} from '../../types/KillTeam2021' import { Datasheet } from './Datasheet' @@ -58,7 +58,11 @@ export function Roster (props: Props) { Roster Size:{ fullOperatives.length } { fullOperatives.map( (op, index) => { return ( -
{index}:  {op.name} - {}
+ + {op.name.toString()} + {JSON.stringify(op.datacard)} + {JSON.stringify(op.weapons)} + ) })} From e851e0a4f86a299d21ec2866d9efe3e735f7caef Mon Sep 17 00:00:00 2001 From: G3rg Date: Wed, 13 Oct 2021 15:29:51 +1000 Subject: [PATCH 04/15] Add parse and store BattleScribe UUID for use in Roster/Kill team selection --- src/parsers/KillTeam2021/BattlescribeParser.ts | 1 + src/types/KillTeam2021.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/parsers/KillTeam2021/BattlescribeParser.ts b/src/parsers/KillTeam2021/BattlescribeParser.ts index 16670e8d..c307f76a 100644 --- a/src/parsers/KillTeam2021/BattlescribeParser.ts +++ b/src/parsers/KillTeam2021/BattlescribeParser.ts @@ -99,6 +99,7 @@ const parseOperative = (model: Element): Operative => { const faction = _.intersection(allKeywords, factionKeywords).pop() || allKeywords.find((k) => (k === k.toUpperCase())) || null const keywords = _.remove(allKeywords, (x) => (x !== faction)) const details = { + id: xpSelect('string(@id)', model, true).toString(), datacard: xpSelect('string(@name)', model, true).toString(), name: xpSelect('string(@customName)', model, true).toString(), stats: { diff --git a/src/types/KillTeam2021.ts b/src/types/KillTeam2021.ts index b5761589..533b056e 100644 --- a/src/types/KillTeam2021.ts +++ b/src/types/KillTeam2021.ts @@ -58,6 +58,7 @@ export interface Equipment { } export interface Operative { + id: String datacard: string name: string stats: Stats From cde75947dece0aaac01bb52760a6f323d2b34897 Mon Sep 17 00:00:00 2001 From: G3rg Date: Fri, 15 Oct 2021 21:32:15 +1000 Subject: [PATCH 05/15] Move roster selection to a new component --- src/components/Homepage.tsx | 6 +- src/components/KillTeam2021/Roster.tsx | 40 +++++------ .../KillTeam2021/RosterSelection.tsx | 70 +++++++++++++++++++ src/types/KillTeam2021.ts | 2 +- 4 files changed, 91 insertions(+), 27 deletions(-) create mode 100644 src/components/KillTeam2021/RosterSelection.tsx diff --git a/src/components/Homepage.tsx b/src/components/Homepage.tsx index 4b82d550..9decb5af 100644 --- a/src/components/Homepage.tsx +++ b/src/components/Homepage.tsx @@ -50,10 +50,10 @@ function Homepage (props: Props) { - + diff --git a/src/components/KillTeam2021/Roster.tsx b/src/components/KillTeam2021/Roster.tsx index 5e2c6739..d3bd0280 100644 --- a/src/components/KillTeam2021/Roster.tsx +++ b/src/components/KillTeam2021/Roster.tsx @@ -1,14 +1,14 @@ -import React, { MouseEvent } from 'react' +import React, {MouseEvent, useEffect, useState} from 'react' import { Col, Row, Card } from 'react-bootstrap' import { CloseButton } from '../CloseButton' -import {Operative, Datacard, PsychicPower, Stats, Weapon, Equipment, Action} from '../../types/KillTeam2021' +import { Operative, Datacard, PsychicPower, Stats, Weapon, Equipment, Action } from '../../types/KillTeam2021' import { Datasheet } from './Datasheet' import { RuleList } from './RuleList' import { PowerList } from './PowerList' import hash from 'node-object-hash' import _ from 'lodash' import { FactionSpecificData } from './FactionSpecificData' -import {Ability} from "../../types/Ability"; +import { RosterSelection } from './RosterSelection' interface Props { name: string @@ -21,8 +21,10 @@ interface Props { showWoundTrack: boolean } -const groupByDatacard = (operatives: Operative[]): Datacard[] => { - const groupedOperatives = _.groupBy(operatives, (o) => (hash().hash({ datacard: o.datacard, weapons: o.weapons, equipment: o.equipment }))) +const groupByDatacard = (operatives: Operative[], selectedOperatives: string[]): Datacard[] => { + const filteredOperatives = operatives.filter((op) => { return selectedOperatives.includes(op.id) }) + console.log(filteredOperatives.length) + const groupedOperatives = _.groupBy(filteredOperatives, (o) => (hash().hash({ datacard: o.datacard, weapons: o.weapons, equipment: o.equipment }))) return _.map(groupedOperatives, (ops, hash) => ({ ...ops[0], name: ops[0].datacard, @@ -38,8 +40,9 @@ export function Roster (props: Props) { width: '100%', display: 'flex' } - const datacards = groupByDatacard(props.operatives) - const fullOperatives = props.operatives.sort((a: Operative, b: Operative) => (a.name > b.name) ? 1 : ((b.name > a.name) ? -1 : 0)) + + const [selectedOperatives, setSelectedOperatives] = useState(props.operatives.map((operative, index) => { return operative.id })) + let datacards = groupByDatacard(props.operatives, selectedOperatives) return ( <> @@ -51,22 +54,13 @@ export function Roster (props: Props) { - { props.isRoster && ( - - Roster - - Roster Size:{ fullOperatives.length } - { fullOperatives.map( (op, index) => { - return ( - - {op.name.toString()} - {JSON.stringify(op.datacard)} - {JSON.stringify(op.weapons)} - - ) - })} - - + {props.isRoster && ( + + Roster + + + + )} {_.orderBy(datacards, ['leader', 'name'], ['desc', 'asc']).map((datacard: Datacard) => ( diff --git a/src/components/KillTeam2021/RosterSelection.tsx b/src/components/KillTeam2021/RosterSelection.tsx new file mode 100644 index 00000000..fa255993 --- /dev/null +++ b/src/components/KillTeam2021/RosterSelection.tsx @@ -0,0 +1,70 @@ +import { Operative, Weapon } from '../../types/KillTeam2021' +import { Col, Row } from 'react-bootstrap' +import ReactBootstrapSlider from 'react-bootstrap-slider' +import React from 'react' + +interface Props { + operatives: Operative[] + selectedOperatives: string[] + setSelectedOperatives: (opIds: string[]) => void +} + +const weaponNames = (weapons: Weapon[]) => { + return weapons.map((weapon, index) => { + return {weapon.name} + }) +} + +const operativeName = (operative: Operative) => { + // TODO: Hasn't been tested with a roster with actual names for units, I think this is only supported if you pay for battlescribe + const name = operative.name.includes(operative.datacard) ? operative.name : `${operative.name} [${operative.datacard}]` + return {name} +} + +const selectionChanged = (selectedOperatives: string[], opId: string, selected: boolean) => { + let selectedOps = [] + if (selected) { + selectedOps = [ + opId, + ...selectedOperatives + ] + } else { + const idx = selectedOperatives.indexOf(opId) + if (idx > -1) { + selectedOperatives.splice(idx, 1) + } + selectedOps = selectedOperatives + } + console.log(selectedOps) + return selectedOps +} + +export function RosterSelection (props: Props) { + console.log(props.selectedOperatives) + return ( + <> + + Operative + Weapons + Include in Kill Team + + {props.operatives.map((op, index) => { + return ( + + {operativeName(op)} + {weaponNames(op.weapons)} + + props.setSelectedOperatives(selectionChanged(props.selectedOperatives, op.id, x.target.value))} + step={0.5} + max={1} + min={0} + /> + + + ) + })} + + ) +} diff --git a/src/types/KillTeam2021.ts b/src/types/KillTeam2021.ts index 533b056e..7ea6cbdc 100644 --- a/src/types/KillTeam2021.ts +++ b/src/types/KillTeam2021.ts @@ -58,7 +58,7 @@ export interface Equipment { } export interface Operative { - id: String + id: string datacard: string name: string stats: Stats From a66eab10cc25e9751da01b235ebfe2677da9d921 Mon Sep 17 00:00:00 2001 From: G3rg Date: Mon, 18 Oct 2021 10:16:21 +1000 Subject: [PATCH 06/15] Use table for Roster list --- .../KillTeam2021/RosterSelection.tsx | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/src/components/KillTeam2021/RosterSelection.tsx b/src/components/KillTeam2021/RosterSelection.tsx index fa255993..1f49ea7d 100644 --- a/src/components/KillTeam2021/RosterSelection.tsx +++ b/src/components/KillTeam2021/RosterSelection.tsx @@ -1,5 +1,5 @@ import { Operative, Weapon } from '../../types/KillTeam2021' -import { Col, Row } from 'react-bootstrap' +import {Col, Row, Table} from 'react-bootstrap' import ReactBootstrapSlider from 'react-bootstrap-slider' import React from 'react' @@ -42,18 +42,21 @@ const selectionChanged = (selectedOperatives: string[], opId: string, selected: export function RosterSelection (props: Props) { console.log(props.selectedOperatives) return ( - <> - - Operative - Weapons - Include in Kill Team - + + + + + + + + + {props.operatives.map((op, index) => { return ( - - {operativeName(op)} - {weaponNames(op.weapons)} - + + + + + ) })} - + +
OperativeWeaponsInclude in Kill Team
{operativeName(op)}{weaponNames(op.weapons)} props.setSelectedOperatives(selectionChanged(props.selectedOperatives, op.id, x.target.value))} @@ -61,10 +64,11 @@ export function RosterSelection (props: Props) { max={1} min={0} /> - - +
) } From b9dfdef98acfd123e2eab36e6b4541f8cacacede Mon Sep 17 00:00:00 2001 From: G3rg Date: Mon, 18 Oct 2021 16:58:52 +1000 Subject: [PATCH 07/15] Roster selection/deselection working --- src/components/KillTeam2021/Roster.tsx | 19 ++++++--- .../KillTeam2021/RosterSelection.tsx | 39 +++++++++---------- 2 files changed, 33 insertions(+), 25 deletions(-) diff --git a/src/components/KillTeam2021/Roster.tsx b/src/components/KillTeam2021/Roster.tsx index d3bd0280..66613c4e 100644 --- a/src/components/KillTeam2021/Roster.tsx +++ b/src/components/KillTeam2021/Roster.tsx @@ -1,7 +1,7 @@ -import React, {MouseEvent, useEffect, useState} from 'react' -import { Col, Row, Card } from 'react-bootstrap' +import React, { MouseEvent, useEffect, useState } from 'react' +import { Col, Card } from 'react-bootstrap' import { CloseButton } from '../CloseButton' -import { Operative, Datacard, PsychicPower, Stats, Weapon, Equipment, Action } from '../../types/KillTeam2021' +import { Operative, Datacard, PsychicPower } from '../../types/KillTeam2021' import { Datasheet } from './Datasheet' import { RuleList } from './RuleList' import { PowerList } from './PowerList' @@ -42,7 +42,16 @@ export function Roster (props: Props) { } const [selectedOperatives, setSelectedOperatives] = useState(props.operatives.map((operative, index) => { return operative.id })) - let datacards = groupByDatacard(props.operatives, selectedOperatives) + const [datacards, setDataCards] = useState([]) + + const updateSelectedOperatives = (operativeIds: string[]): void => { + setSelectedOperatives(operativeIds) + setDataCards(groupByDatacard(props.operatives, selectedOperatives)) + } + + useEffect(() => { + setDataCards(groupByDatacard(props.operatives, selectedOperatives)) + }, []) return ( <> @@ -58,7 +67,7 @@ export function Roster (props: Props) { Roster - + )} diff --git a/src/components/KillTeam2021/RosterSelection.tsx b/src/components/KillTeam2021/RosterSelection.tsx index 1f49ea7d..2e527fb9 100644 --- a/src/components/KillTeam2021/RosterSelection.tsx +++ b/src/components/KillTeam2021/RosterSelection.tsx @@ -1,5 +1,5 @@ import { Operative, Weapon } from '../../types/KillTeam2021' -import {Col, Row, Table} from 'react-bootstrap' +import { Row, Table } from 'react-bootstrap' import ReactBootstrapSlider from 'react-bootstrap-slider' import React from 'react' @@ -11,7 +11,7 @@ interface Props { const weaponNames = (weapons: Weapon[]) => { return weapons.map((weapon, index) => { - return {weapon.name} + return {weapon.name} }) } @@ -35,7 +35,6 @@ const selectionChanged = (selectedOperatives: string[], opId: string, selected: } selectedOps = selectedOperatives } - console.log(selectedOps) return selectedOps } @@ -51,23 +50,23 @@ export function RosterSelection (props: Props) { - {props.operatives.map((op, index) => { - return ( - - {operativeName(op)} - {weaponNames(op.weapons)} - - props.setSelectedOperatives(selectionChanged(props.selectedOperatives, op.id, x.target.value))} - step={0.5} - max={1} - min={0} - /> - - - ) - })} + {props.operatives.map((op, index) => { + return ( + + {operativeName(op)} + {weaponNames(op.weapons)} + + props.setSelectedOperatives(selectionChanged(props.selectedOperatives, op.id, x.target.value))} + step={0.5} + max={1} + min={0} + /> + + + ) + })} ) From 8c0211994f9ae270c156c6760435e07fcb95b702 Mon Sep 17 00:00:00 2001 From: G3rg Date: Mon, 18 Oct 2021 17:46:02 +1000 Subject: [PATCH 08/15] Switched to use checkbox to take up less room, and grey out row when not selected in roster selection --- src/components/KillTeam2021/Roster.tsx | 24 ++++++------- .../KillTeam2021/RosterSelection.tsx | 36 +++++++++++-------- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/src/components/KillTeam2021/Roster.tsx b/src/components/KillTeam2021/Roster.tsx index 66613c4e..463c283a 100644 --- a/src/components/KillTeam2021/Roster.tsx +++ b/src/components/KillTeam2021/Roster.tsx @@ -23,12 +23,11 @@ interface Props { const groupByDatacard = (operatives: Operative[], selectedOperatives: string[]): Datacard[] => { const filteredOperatives = operatives.filter((op) => { return selectedOperatives.includes(op.id) }) - console.log(filteredOperatives.length) const groupedOperatives = _.groupBy(filteredOperatives, (o) => (hash().hash({ datacard: o.datacard, weapons: o.weapons, equipment: o.equipment }))) return _.map(groupedOperatives, (ops, hash) => ({ ...ops[0], name: ops[0].datacard, - operativeNames: ops.map((c) => (c.name)).sort() + operativeNames: ops.map((op) => (op.name)).sort() })) } @@ -51,7 +50,7 @@ export function Roster (props: Props) { useEffect(() => { setDataCards(groupByDatacard(props.operatives, selectedOperatives)) - }, []) + }, [props.operatives, selectedOperatives]) return ( <> @@ -63,7 +62,7 @@ export function Roster (props: Props) { - {props.isRoster && ( + {(props.isRoster ?? false) && ( Roster @@ -71,8 +70,8 @@ export function Roster (props: Props) { )} - {_.orderBy(datacards, ['leader', 'name'], ['desc', 'asc']).map((datacard: Datacard) => ( - + {_.orderBy(datacards, ['leader', 'name'], ['desc', 'asc']).map((datacard: Datacard, idx) => ( + ))} Rules @@ -80,12 +79,13 @@ export function Roster (props: Props) { (m.rules))), 'name')} /> - {props.psychicPowers.length > 0 && - Psychic Powers - - - - } + {props.psychicPowers.length > 0 && + + Psychic Powers + + + + } diff --git a/src/components/KillTeam2021/RosterSelection.tsx b/src/components/KillTeam2021/RosterSelection.tsx index 2e527fb9..82c4984e 100644 --- a/src/components/KillTeam2021/RosterSelection.tsx +++ b/src/components/KillTeam2021/RosterSelection.tsx @@ -1,6 +1,5 @@ import { Operative, Weapon } from '../../types/KillTeam2021' -import { Row, Table } from 'react-bootstrap' -import ReactBootstrapSlider from 'react-bootstrap-slider' +import { Form, Row, Table } from 'react-bootstrap' import React from 'react' interface Props { @@ -9,19 +8,23 @@ interface Props { setSelectedOperatives: (opIds: string[]) => void } -const weaponNames = (weapons: Weapon[]) => { +const weaponNames = (weapons: Weapon[]): JSX.Element[] => { return weapons.map((weapon, index) => { - return {weapon.name} + return {weapon.name} }) } -const operativeName = (operative: Operative) => { +const operativeName = (operative: Operative): JSX.Element => { // TODO: Hasn't been tested with a roster with actual names for units, I think this is only supported if you pay for battlescribe const name = operative.name.includes(operative.datacard) ? operative.name : `${operative.name} [${operative.datacard}]` return {name} } -const selectionChanged = (selectedOperatives: string[], opId: string, selected: boolean) => { +const flipSelection = (selectedOperatives: string[], opId: string): string[] => { + return selectionChanged(selectedOperatives, opId, !selectedOperatives.includes(opId)) +} + +const selectionChanged = (selectedOperatives: string[], opId: string, selected: boolean): string[] => { let selectedOps = [] if (selected) { selectedOps = [ @@ -39,29 +42,32 @@ const selectionChanged = (selectedOperatives: string[], opId: string, selected: } export function RosterSelection (props: Props) { - console.log(props.selectedOperatives) return ( - + {props.operatives.map((op, index) => { + const selected = props.selectedOperatives.includes(op.id) + const className = selected ? '' : 'excluded' return ( - + { props.setSelectedOperatives(flipSelection(props.selectedOperatives, op.id)) }} + className={className} + > From f7f5777022e18e6ed42bb7169b2756736386327c Mon Sep 17 00:00:00 2001 From: G3rg Date: Mon, 18 Oct 2021 18:02:52 +1000 Subject: [PATCH 09/15] Allow hiding of roster list when printing, and add setting for it --- src/App.tsx | 8 ++++---- src/components/KillTeam2021/Roster.tsx | 5 ++++- .../KillTeam2021/RosterSelection.tsx | 2 +- src/components/SettingsDialog.tsx | 19 ++++++++++++++++++- src/index.scss | 10 ++++++++++ src/types/Settings.ts | 1 + 6 files changed, 38 insertions(+), 7 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 5e092803..9f72a364 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -14,7 +14,7 @@ import { Settings } from './types/Settings' export function App () { const [roster, setRoster] = useState(null) - const [settings, setSettings] = useState({ showWoundTrack: true }) + const [settings, setSettings] = useState({ showWoundTrack: true, printRosterList: false }) useEffect(() => { setSettings(loadSettingsFromLocalStorage()) @@ -31,9 +31,9 @@ export function App () { const loadSettingsFromLocalStorage = (): Settings => { try { - return JSON.parse(localStorage.getItem('settings') ?? '{ showWoundTrack: true, touchscreenMode: false, dropboxSelector: false }') + return JSON.parse(localStorage.getItem('settings') ?? '{ showWoundTrack: true, printRosterList: false }') } catch (e) { - return { showWoundTrack: false } + return { showWoundTrack: true, printRosterList: false } } } @@ -76,7 +76,7 @@ export function App () { {roster === null ? : <>} {(roster != null) && isRosterKT18(roster) ? : <>} - {(roster != null) && isRosterKT21(roster) ? : <>} + {(roster != null) && isRosterKT21(roster) ? : <>} diff --git a/src/components/KillTeam2021/Roster.tsx b/src/components/KillTeam2021/Roster.tsx index 463c283a..20aed3b7 100644 --- a/src/components/KillTeam2021/Roster.tsx +++ b/src/components/KillTeam2021/Roster.tsx @@ -19,6 +19,7 @@ interface Props { onClose: (event: MouseEvent) => void isRoster?: boolean showWoundTrack: boolean + printRosterList: boolean } const groupByDatacard = (operatives: Operative[], selectedOperatives: string[]): Datacard[] => { @@ -52,6 +53,8 @@ export function Roster (props: Props) { setDataCards(groupByDatacard(props.operatives, selectedOperatives)) }, [props.operatives, selectedOperatives]) + const rosterClassName = props.printRosterList ? '' : 'noprint' + return ( <>

@@ -63,7 +66,7 @@ export function Roster (props: Props) {

{(props.isRoster ?? false) && ( - + Roster diff --git a/src/components/KillTeam2021/RosterSelection.tsx b/src/components/KillTeam2021/RosterSelection.tsx index 82c4984e..1d802e7e 100644 --- a/src/components/KillTeam2021/RosterSelection.tsx +++ b/src/components/KillTeam2021/RosterSelection.tsx @@ -54,7 +54,7 @@ export function RosterSelection (props: Props) {
{props.operatives.map((op, index) => { const selected = props.selectedOperatives.includes(op.id) - const className = selected ? '' : 'excluded' + const className = selected ? '' : 'unselected' return ( { props.setSelectedOperatives(flipSelection(props.selectedOperatives, op.id)) }} diff --git a/src/components/SettingsDialog.tsx b/src/components/SettingsDialog.tsx index 973a4036..cd9e9e8e 100644 --- a/src/components/SettingsDialog.tsx +++ b/src/components/SettingsDialog.tsx @@ -15,7 +15,17 @@ function SettingsDialog (props: Props) { const showWoundTrack: boolean = target.checked const newSettings = { ...props.settings, - showWoundTrack: showWoundTrack + showWoundTrack + } + props.setSettings(newSettings) + } + + const handlePrintRosterChange = (event: any) => { + const target = event.target + const printRosterList: boolean = target.checked + const newSettings = { + ...props.settings, + printRosterList } props.setSettings(newSettings) } @@ -43,6 +53,13 @@ function SettingsDialog (props: Props) { onChange={handleWoundTrackChange} checked={props.settings.showWoundTrack} /> + diff --git a/src/index.scss b/src/index.scss index b1b0886c..b492a56b 100644 --- a/src/index.scss +++ b/src/index.scss @@ -41,6 +41,16 @@ h1, h2, h3, h4, h5 { } } +.unselected { + opacity: 0.25; +} + +.noprint { + @media print { + display: none; + } +} + .card { margin-bottom: 1em; break-inside: avoid; diff --git a/src/types/Settings.ts b/src/types/Settings.ts index 99e1d7b9..939ec56b 100644 --- a/src/types/Settings.ts +++ b/src/types/Settings.ts @@ -1,3 +1,4 @@ export interface Settings { showWoundTrack: boolean + printRosterList: boolean } From b2e5f99554a7e98cbd45210aed28f898cdf82b8c Mon Sep 17 00:00:00 2001 From: G3rg Date: Tue, 19 Oct 2021 10:06:02 +1000 Subject: [PATCH 10/15] Use better key --- src/components/KillTeam2021/RosterSelection.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/KillTeam2021/RosterSelection.tsx b/src/components/KillTeam2021/RosterSelection.tsx index 1d802e7e..bb3ff4b3 100644 --- a/src/components/KillTeam2021/RosterSelection.tsx +++ b/src/components/KillTeam2021/RosterSelection.tsx @@ -10,7 +10,7 @@ interface Props { const weaponNames = (weapons: Weapon[]): JSX.Element[] => { return weapons.map((weapon, index) => { - return {weapon.name} + return {weapon.name} }) } @@ -52,12 +52,12 @@ export function RosterSelection (props: Props) { - {props.operatives.map((op, index) => { + {props.operatives.map((op) => { const selected = props.selectedOperatives.includes(op.id) const className = selected ? '' : 'unselected' return ( { props.setSelectedOperatives(flipSelection(props.selectedOperatives, op.id)) }} + key={op.id} onClick={(event) => { props.setSelectedOperatives(flipSelection(props.selectedOperatives, op.id)) }} className={className} > From 3eb5a14778d08bffff807f8176171bdde9dde3cf Mon Sep 17 00:00:00 2001 From: G3rg Date: Tue, 19 Oct 2021 20:34:42 +1000 Subject: [PATCH 11/15] Boy scout lint fixes --- src/components/Homepage.tsx | 4 +++- src/components/KillTeam2021/TacOpsList.tsx | 2 +- src/components/SettingsDialog.tsx | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/components/Homepage.tsx b/src/components/Homepage.tsx index 86d5a738..2814a086 100644 --- a/src/components/Homepage.tsx +++ b/src/components/Homepage.tsx @@ -13,6 +13,8 @@ interface Props { setSettings: (settings: Settings) => void } +const GIT_SHA = process.env.REACT_APP_GIT_SHA ?? '' + function fileDropZone (props: Props): JSX.Element { return ( @@ -89,7 +91,7 @@ function Homepage (props: Props): JSX.Element { Icons courtesy of Companion for Kill Team. Released as Open Source, report problems on GitHub. - Version: {process.env.REACT_APP_GIT_SHA} + Version: {GIT_SHA} ) diff --git a/src/components/KillTeam2021/TacOpsList.tsx b/src/components/KillTeam2021/TacOpsList.tsx index f82bb80a..0aab9129 100644 --- a/src/components/KillTeam2021/TacOpsList.tsx +++ b/src/components/KillTeam2021/TacOpsList.tsx @@ -11,7 +11,7 @@ export function TacOpsList (props: Props): JSX.Element { return ( {props.tacOps.map((x: TacOp) => ( - + Tac Op {x.id} diff --git a/src/components/SettingsDialog.tsx b/src/components/SettingsDialog.tsx index eea5c56f..9b560c5f 100644 --- a/src/components/SettingsDialog.tsx +++ b/src/components/SettingsDialog.tsx @@ -20,7 +20,7 @@ function SettingsDialog (props: Props): JSX.Element { props.setSettings(newSettings) } - const handlePrintRosterChange = (event: any) => { + const handlePrintRosterChange = (event: any): void => { const target = event.target const printRosterList: boolean = target.checked const newSettings = { From 648956e990ba8a88683cff5060d059959893c8bc Mon Sep 17 00:00:00 2001 From: G3rg Date: Wed, 20 Oct 2021 07:18:59 +1000 Subject: [PATCH 12/15] Remove console.log --- src/parsers/KillTeam2021/BattlescribeParser.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/parsers/KillTeam2021/BattlescribeParser.ts b/src/parsers/KillTeam2021/BattlescribeParser.ts index c307f76a..bfdf5476 100644 --- a/src/parsers/KillTeam2021/BattlescribeParser.ts +++ b/src/parsers/KillTeam2021/BattlescribeParser.ts @@ -152,7 +152,7 @@ export const parseBattlescribeXML = (doc: Document): Roster => { o.name = o.datacard + ' ' + romanNumerals[counts[o.datacard]++] } } - console.log(`Is Roster? ${isRoster}`) + return { system: 'KillTeam2021', name, From 73df4b703adc7bb7993600de834a9f6eea6bbfbe Mon Sep 17 00:00:00 2001 From: G3rg Date: Fri, 22 Oct 2021 09:23:41 +1000 Subject: [PATCH 13/15] Add setting to turn roster selection view on / off and marked as WIP --- src/App.tsx | 9 +++++---- src/components/KillTeam2021/Roster.tsx | 3 ++- src/components/SettingsDialog.tsx | 17 +++++++++++++++++ src/types/Settings.ts | 1 + 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 5ac69fec..56583cc3 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -14,7 +14,7 @@ import { Settings } from './types/Settings' export function App (): JSX.Element { const [roster, setRoster] = useState(null) - const [settings, setSettings] = useState({ showWoundTrack: true, printRosterList: false }) + const [settings, setSettings] = useState({ showWoundTrack: true, rosterSelection: false, printRosterList: false }) useEffect(() => { setSettings(loadSettingsFromLocalStorage()) @@ -31,9 +31,9 @@ export function App (): JSX.Element { const loadSettingsFromLocalStorage = (): Settings => { try { - return JSON.parse(localStorage.getItem('settings') ?? '{ showWoundTrack: true, printRosterList: false }') + return JSON.parse(localStorage.getItem('settings') ?? '{ showWoundTrack: true, rosterSelection: false, printRosterList: false }') } catch (e) { - return { showWoundTrack: true, printRosterList: false } + return { showWoundTrack: true, rosterSelection: false, printRosterList: false } } } @@ -76,7 +76,8 @@ export function App (): JSX.Element { {roster === null ? : <>} {(roster != null) && isRosterKT18(roster) ? : <>} - {(roster != null) && isRosterKT21(roster) ? : <>} + {(roster != null) && isRosterKT21(roster) ? : <>} diff --git a/src/components/KillTeam2021/Roster.tsx b/src/components/KillTeam2021/Roster.tsx index df1098fd..1c8dac69 100644 --- a/src/components/KillTeam2021/Roster.tsx +++ b/src/components/KillTeam2021/Roster.tsx @@ -20,6 +20,7 @@ interface Props { onClose: (event: MouseEvent) => void isRoster?: boolean showWoundTrack: boolean + rosterSelection: boolean printRosterList: boolean } @@ -66,7 +67,7 @@ export function Roster (props: Props): JSX.Element { - {(props.isRoster ?? false) && ( + {(props.isRoster ?? false) && (props.rosterSelection) && ( Roster diff --git a/src/components/SettingsDialog.tsx b/src/components/SettingsDialog.tsx index 9b560c5f..24e47541 100644 --- a/src/components/SettingsDialog.tsx +++ b/src/components/SettingsDialog.tsx @@ -30,6 +30,16 @@ function SettingsDialog (props: Props): JSX.Element { props.setSettings(newSettings) } + const handleRosterSelectionChange = (event: any): void => { + const target = event.target + const rosterSelection: boolean = target.checked + const newSettings = { + ...props.settings, + rosterSelection + } + props.setSettings(newSettings) + } + return ( + Date: Fri, 22 Oct 2021 09:37:26 +1000 Subject: [PATCH 14/15] Some linting issues, though line is now super long --- src/App.tsx | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/App.tsx b/src/App.tsx index 56583cc3..d15d0f53 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -76,8 +76,7 @@ export function App (): JSX.Element { {roster === null ? : <>} {(roster != null) && isRosterKT18(roster) ? : <>} - {(roster != null) && isRosterKT21(roster) ? : <>} + {(roster != null) && isRosterKT21(roster) ? : <>} From e10d8e3248b032bb8d890dcdc76b218e7ab753ba Mon Sep 17 00:00:00 2001 From: G3rg Date: Fri, 22 Oct 2021 10:17:20 +1000 Subject: [PATCH 15/15] Update key for datasheet, using just datacard name caused problems when removing / adding operatives of the same type --- src/components/KillTeam2021/Roster.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/KillTeam2021/Roster.tsx b/src/components/KillTeam2021/Roster.tsx index 1c8dac69..3814246d 100644 --- a/src/components/KillTeam2021/Roster.tsx +++ b/src/components/KillTeam2021/Roster.tsx @@ -76,7 +76,7 @@ export function Roster (props: Props): JSX.Element { )} {_.orderBy(datacards, ['leader', 'name'], ['desc', 'asc']).map((datacard: Datacard) => ( - + ))} Rules
Operative WeaponsInclude in Kill Team
{operativeName(op)} {weaponNames(op.weapons)} - props.setSelectedOperatives(selectionChanged(props.selectedOperatives, op.id, x.target.value))} - step={0.5} - max={1} - min={0} +
{operativeName(op)}