diff --git a/package-lock.json b/package-lock.json index db62f11..478d92b 100755 --- a/package-lock.json +++ b/package-lock.json @@ -7149,6 +7149,12 @@ } } }, + "tslint-config-prettier": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz", + "integrity": "sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg==", + "dev": true + }, "tslint-react": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/tslint-react/-/tslint-react-4.2.0.tgz", diff --git a/package.json b/package.json index 52c26f2..a9b78a8 100755 --- a/package.json +++ b/package.json @@ -12,6 +12,11 @@ "start": "webpack-dev-server --mode development", "test": "echo \"Error: no test specified\" && exit 1" }, + "prettier": { + "tabWidth": 4, + "bracketSpacing": false, + "printWidth": 100 + }, "devDependencies": { "@babel/cli": "^7.8.4", "@babel/core": "^7.9.6", @@ -34,6 +39,7 @@ "style-loader": "^1.2.1", "ts-loader": "^7.0.3", "tslint": "^6.1.1", + "tslint-config-prettier": "^1.18.0", "tslint-react": "^4.2.0", "typescript": "^3.8.3", "webpack": "^4.43.0", diff --git a/src/Components/CreateRulesetPanel.tsx b/src/Components/CreateRulesetPanel.tsx index be89e25..c5c7a90 100644 --- a/src/Components/CreateRulesetPanel.tsx +++ b/src/Components/CreateRulesetPanel.tsx @@ -1,138 +1,228 @@ import React, {useContext, useState} from "react"; -import {CellDef, RulesetSchemaDto} from "../Services/RulesetSchemaDto"; import { - Button, - Checkbox, - Form, - Header, - Segment, - Table -} from "semantic-ui-react"; + BlockDef, + BonusBlockDef, + CellDef, + NoBonusBlockDef, + RulesetSchemaDto, +} from "../Services/RulesetSchemaDto"; +import {Button, Container, Grid, Header, Segment} from "semantic-ui-react"; import UserContext from "../Contexts/UserContext"; -import RulesetBlockTable from "./RulesetBlockTable"; import RulesetDisplayPanel from "./RulesetDisplayPanel"; +import NewBlockForm from "./NewBlockForm"; +import axios from "axios"; +import {SERVER_BASE_NAME} from "../index"; +import EditableHeader from "./EditableHeader"; interface RulesetDisplayPanelProps { - onSubmitRuleset: (ruleset: RulesetSchemaDto) => any; + onRulesetSave: () => any; + onRulesetChange: () => any; } -const CreateRulesetPanel: React.FunctionComponent = (props) => { - const {onSubmitRuleset} = props; - const {strings: Locale} = useContext(UserContext); - const [currentRulesetBuild, updateCurrentRulesetBuild] = useState({ - id: "", - label: Locale.rulesetsPage.newRuleset, - blocks: {}, - }); - const [newBlockInput, updateNewBlockInput] = useState({ - label: "", - hasBonus: false, - bonusScore: 35, - bonusFor: 63, - cells: {}, - }); +interface RulesetDisplayPanelState { + saving: boolean; + currentRulesetBuild: RulesetSchemaDto; + newBlockInput: { + label: string; + hasBonus: boolean; + bonusFor: number; + bonusScore: number; + }; +} - const handleAddBlock = () => { - if (newBlockInput.label) { - updateCurrentRulesetBuild({ - ...currentRulesetBuild, - blocks: { - ...currentRulesetBuild.blocks, - [newBlockInput.label]: { - ...newBlockInput, - bonusFor: newBlockInput.hasBonus ? newBlockInput.bonusFor : undefined, - bonusScore: newBlockInput.hasBonus ? newBlockInput.bonusScore : undefined, - }, - } +class CreateRulesetPanel extends React.Component< + RulesetDisplayPanelProps, + RulesetDisplayPanelState +> { + constructor(props: RulesetDisplayPanelProps) { + super(props); + this.state = { + saving: false, + currentRulesetBuild: { + id: "", + label: "", + blocks: {}, + }, + newBlockInput: { + label: "", + hasBonus: false, + bonusFor: 0, + bonusScore: 0, + }, + }; + } + + componentDidMount(): void { + if (this.state.currentRulesetBuild.label === "") { + this.setState({ + currentRulesetBuild: { + ...this.state.currentRulesetBuild, + id: this.context.strings.rulesetsPage.newRuleset, + label: this.context.strings.rulesetsPage.newRuleset, + }, }); } - }; + } - const handleAddCell = (cellDef: CellDef, blockId: string) => { - if (cellDef.label) { - updateCurrentRulesetBuild({ - ...currentRulesetBuild, - blocks: { - ...currentRulesetBuild.blocks, - [blockId]: { - ...currentRulesetBuild.blocks[blockId], - cells: { - ...currentRulesetBuild.blocks[blockId].cells, - [cellDef.label]: cellDef - } - } - } - }) + handleAddBlock() { + if (this.state.newBlockInput.label) { + const blockToSave = { + ...this.state.newBlockInput, + cells: {}, + }; + if (!this.state.newBlockInput.hasBonus) { + delete blockToSave.bonusScore; + delete blockToSave.bonusFor; + } + this.state.currentRulesetBuild.blocks[blockToSave.label] = blockToSave; + this.forceUpdate(); } - }; + this.props.onRulesetChange(); + } - return ( - <> -
- {Locale.rulesetsPage.newRuleset} -
- -
- {Locale.rulesetsPage.newBlock} -
- -
- - - updateNewBlockInput({...newBlockInput, label: e.target.value})} - /> - - - updateNewBlockInput({...newBlockInput, hasBonus: c.checked ?? false})} - label={Locale.rulesetsPage.bonus} - /> - - {newBlockInput.hasBonus && ( - <> - - - updateNewBlockInput({...newBlockInput, bonusScore: Number(e.target.value)})} - /> - - - - updateNewBlockInput({...newBlockInput, bonusFor: Number(e.target.value)})} - /> - - - )} - - - -
-
- - - ); -}; + handleAddCell(cellDef: CellDef, blockId: string) { + if (cellDef.label) { + this.state.currentRulesetBuild.blocks[blockId].cells[cellDef.label] = cellDef; + this.forceUpdate(); + } + this.props.onRulesetChange(); + } -export default CreateRulesetPanel; \ No newline at end of file + handleRulesetNameChange(newLabel: string) { + this.setState({ + currentRulesetBuild: { + ...this.state.currentRulesetBuild, + label: newLabel, + id: newLabel, + }, + }); + } + + handleBlockNameChange(newName: string) { + this.setState({ + newBlockInput: { + ...this.state.newBlockInput, + label: newName, + }, + }); + } + + handleToggleBlockBonus(newHasBonus: boolean) { + this.setState({ + newBlockInput: { + ...this.state.newBlockInput, + hasBonus: newHasBonus, + }, + }); + } + + handleBonusScoreChange(newBonusScore: number) { + this.setState({ + newBlockInput: { + ...this.state.newBlockInput, + bonusScore: newBonusScore, + }, + }); + } + + handleBonusForChange(newBonusFor: number) { + this.setState({ + newBlockInput: { + ...this.state.newBlockInput, + bonusFor: newBonusFor, + }, + }); + } + + blocksExistAndAllHaveCells(): boolean { + return ( + Object.values(this.state.currentRulesetBuild.blocks).length > 0 && + Object.values(this.state.currentRulesetBuild.blocks).reduce( + (prev: boolean, blockDef: BlockDef) => + Object.values(blockDef.cells).length > 0 && prev, + true + ) + ); + } + + removeBlock(blockId: string) { + this.props.onRulesetChange(); + delete this.state.currentRulesetBuild.blocks[blockId]; + this.forceUpdate(); + } + + removeCell(cellId: string, blockId: string) { + this.props.onRulesetChange(); + delete this.state.currentRulesetBuild.blocks[blockId].cells[cellId]; + this.forceUpdate(); + } + + async submitNewRuleset() { + this.setState({saving: true}, async () => { + const response = await axios.post( + SERVER_BASE_NAME + "/api/ruleset", + this.state.currentRulesetBuild + ); + console.log(response); + this.setState({saving: false}, () => { + this.props.onRulesetSave(); + }); + }); + } + + render() { + const Locale = this.context.strings; + + return ( + + + + + this.handleRulesetNameChange(t)} + text={this.state.currentRulesetBuild.label} + headerProps={{size: "small"}} + /> + this.removeBlock(id)} + removeCell={(cid, bid) => this.removeCell(cid, bid)} + onAddCell={(c, b) => this.handleAddCell(c, b)} + /> + + + + +
{Locale.rulesetsPage.newBlock}
+ this.handleBlockNameChange(x)} + onBonusToggle={(x) => this.handleToggleBlockBonus(x)} + onBonusScoreChange={(x) => this.handleBonusScoreChange(x)} + onBonusForChange={(x) => this.handleBonusForChange(x)} + onSubmitClick={() => this.handleAddBlock()} + /> +
+
+ + + + + +
+
+ ); + } +} +CreateRulesetPanel.contextType = UserContext; + +export default CreateRulesetPanel; diff --git a/src/Components/EditableHeader.tsx b/src/Components/EditableHeader.tsx new file mode 100644 index 0000000..3701e73 --- /dev/null +++ b/src/Components/EditableHeader.tsx @@ -0,0 +1,39 @@ +import React, {useState, KeyboardEvent} from "react"; +import {Header, Icon, Input, StrictHeaderProps} from "semantic-ui-react"; + +interface EditableHeaderProps { + onTextEdit: (newText: string) => any; + headerProps: StrictHeaderProps; + text: string; +} + +const EditableHeader: React.FunctionComponent = (props) => { + const {text, onTextEdit, headerProps} = props; + const [isEditing, updateIsEditing] = useState(false); + + const handleKeyUp = (e: KeyboardEvent) => { + if (e.key === "Enter") { + onTextEdit(e.currentTarget.value); + updateIsEditing(false); + } + }; + + return isEditing ? ( +
+ updateIsEditing(false)} + autoFocus={true} + onChange={(e) => onTextEdit(e.target.value)} + value={text} + onKeyUp={(e: KeyboardEvent) => handleKeyUp(e)} + /> +
+ ) : ( +
updateIsEditing(true)} {...headerProps}> + {text + " "} + +
+ ); +}; + +export default EditableHeader; diff --git a/src/Components/NewBlockForm.tsx b/src/Components/NewBlockForm.tsx new file mode 100644 index 0000000..0ab95ec --- /dev/null +++ b/src/Components/NewBlockForm.tsx @@ -0,0 +1,69 @@ +import React, {useContext} from "react"; +import UserContext from "../Contexts/UserContext"; +import {Button, Checkbox, Form, Segment} from "semantic-ui-react"; + +function NewBlockForm(props: { + newBlockInput: { + bonusScore: number; + bonusFor: number; + label: string; + hasBonus: boolean; + }; + onNameChange: (newName: string) => void; + onBonusToggle: (newHasBonus: boolean) => void; + onBonusScoreChange: (newBonusScore: number) => void; + onBonusForChange: (newBonusFor: number) => void; + onSubmitClick: () => void; +}) { + const {strings: Locale} = useContext(UserContext); + return ( + +
+ + + props.onNameChange(e.target.value)} + /> + + + props.onBonusToggle(c.checked ?? false)} + label={Locale.rulesetsPage.bonus} + /> + + {props.newBlockInput.hasBonus && ( + <> + + + props.onBonusScoreChange(Number(e.target.value))} + /> + + + + props.onBonusForChange(Number(e.target.value))} + /> + + + )} + + + +
+
+ ); +} + +export default NewBlockForm; diff --git a/src/Components/RulesetBlockTable.tsx b/src/Components/RulesetBlockTable.tsx index f0d8204..67c72f6 100644 --- a/src/Components/RulesetBlockTable.tsx +++ b/src/Components/RulesetBlockTable.tsx @@ -1,7 +1,7 @@ import {BlockDef, CellDef} from "../Services/RulesetSchemaDto"; import React, {useContext, useState} from "react"; import RulesetCellTableRow from "./RulesetCellTableRow"; -import {Button, Dropdown, DropdownItemProps, Grid, Input, Table} from "semantic-ui-react"; +import {Button, Dropdown, DropdownItemProps, Grid, Input, List, Table} from "semantic-ui-react"; import UserContext from "../Contexts/UserContext"; import {FieldType} from "../enums"; @@ -10,32 +10,28 @@ interface RulesetBlockTableProps { blockDef: BlockDef | null; editable?: boolean; onAddCell?: (cellDef: CellDef, blockId: string) => any; + removeBlock?: (blockId: string) => any; + removeCell?: (cellId: string, blockId: string) => any; } const RulesetBlockTable: React.FunctionComponent = (props) => { - const {id, blockDef, editable, onAddCell} = props; + const {id, blockDef, editable, onAddCell, removeCell} = props; const [currentCellInput, updateCurrentCellInput] = useState({ label: "", - maxMultiples: 0, - multiplier: 0, - fieldType: FieldType.number, - score: 0, + maxMultiples: 1, + multiplier: 1, + fieldType: undefined, + score: 25, + maxSuperkadis: 5, }); const {strings: Locale} = useContext(UserContext); if (!blockDef) { return ( - +
- + {Locale.rulesetsPage.noBlocks} @@ -51,151 +47,200 @@ const RulesetBlockTable: React.FunctionComponent = (prop subText += `${Locale.general.yes}, ${Locale.rulesetsPage.bonusScore}: ${blockDef.bonusScore}, ${Locale.rulesetsPage.bonusThreshold}: ${blockDef.bonusFor}`; - } - else { + } else { subText += Locale.general.no; } const fieldTypeOptions: DropdownItemProps[] = [ {value: FieldType.bool, key: FieldType.bool, text: Locale.rulesetsPage[FieldType.bool]}, - {value: FieldType.multiplier, key: FieldType.multiplier, text: Locale.rulesetsPage[FieldType.multiplier]}, - {value: FieldType.number, key: FieldType.number, text: Locale.rulesetsPage[FieldType.number]}, - {value: FieldType.superkadi, key: FieldType.superkadi, text: Locale.rulesetsPage[FieldType.superkadi]}, + { + value: FieldType.multiplier, + key: FieldType.multiplier, + text: Locale.rulesetsPage[FieldType.multiplier], + }, + { + value: FieldType.number, + key: FieldType.number, + text: Locale.rulesetsPage[FieldType.number], + }, + { + value: FieldType.superkadi, + key: FieldType.superkadi, + text: Locale.rulesetsPage[FieldType.superkadi], + }, ]; - const onChangeDropdown = (value: FieldType) => { - const newCell = { - ...currentCellInput, - fieldType: value, - }; - if (value === FieldType.bool) { - newCell.score = 0; - } - else if (value === FieldType.multiplier) { - newCell.multiplier = 0; - newCell.maxMultiples = 5; - } - else if (value === FieldType.superkadi) { - newCell.maxMultiples = 5; - newCell.score = 50; - } + const onChangeFieldTypeDropdown = (newFieldType: FieldType) => { + const newCell: any = Object.assign({}, currentCellInput); + newCell.fieldType = newFieldType; updateCurrentCellInput(newCell); }; + const handleAddCell = () => { + if (onAddCell) { + const newCell: any = Object.assign({}, currentCellInput); + if (newCell.fieldType === FieldType.bool) { + delete newCell.maxMultiples; + delete newCell.maxSuperkadis; + delete newCell.multiplier; + } else if (newCell.fieldType === FieldType.multiplier) { + delete newCell.score; + delete newCell.maxSuperkadis; + } else if (newCell.fieldType === FieldType.superkadi) { + delete newCell.multiplier; + delete newCell.maxMultiples; + } else if (newCell.fieldType === FieldType.number) { + delete newCell.multiplier; + delete newCell.maxMultiples; + delete newCell.maxSuperkadis; + delete newCell.score; + } + onAddCell(newCell, id); + } + }; + return ( -
+
- + {blockDef.label} + {editable && ( + - - + + + updateCurrentCellInput({ + ...currentCellInput, + label: e.target.value, + }) + } + /> + + + onChangeFieldTypeDropdown(c.value as FieldType)} + options={fieldTypeOptions} + button={true} + /> + + + + + {currentCellInput.fieldType === undefined || + currentCellInput.fieldType === FieldType.number ? ( + Locale.rulesetsPage.extraCellSettingsInfo + ) : ( + + {(currentCellInput.fieldType === FieldType.bool || + currentCellInput.fieldType === + FieldType.superkadi) && ( + + + updateCurrentCellInput({ + ...currentCellInput, + score: Number(e.target.value), + }) + } + /> + + )} + {currentCellInput.fieldType === + FieldType.multiplier && ( + + + updateCurrentCellInput({ + ...currentCellInput, + multiplier: Number(e.target.value), + }) + } + /> + + )} + {(currentCellInput.fieldType === FieldType.superkadi || + currentCellInput.fieldType === + FieldType.multiplier) && ( + + + updateCurrentCellInput({ + ...currentCellInput, + maxMultiples: Number( + e.target.value + ), + }) + } + /> + + )} + + )} + + +
+
@@ -39,29 +33,29 @@ const RulesetDisplayPanel: React.FunctionComponent = ( {Locale.rulesetsPage.fieldTypeHeader} - {Locale.rulesetsPage.fieldValueHeader} + {Locale.rulesetsPage.fieldAttributesHeader}
- {Object.entries(ruleset.blocks).length > 0 ? - Object.entries(ruleset.blocks).map(idAndBlock => ( + {Object.entries(ruleset.blocks).length > 0 ? ( + Object.entries(ruleset.blocks).map((idAndBlock) => ( - )) : ( - + )) + ) : ( + )} ); } }; -export default RulesetDisplayPanel; \ No newline at end of file +export default RulesetDisplayPanel; diff --git a/src/Components/RulesetsPage.tsx b/src/Components/RulesetsPage.tsx index 8401b69..19265cb 100755 --- a/src/Components/RulesetsPage.tsx +++ b/src/Components/RulesetsPage.tsx @@ -1,5 +1,5 @@ import React, {ReactElement} from "react"; -import {Container, Grid, Header, List, Segment} from "semantic-ui-react"; +import {Button, Grid, Header, Modal} from "semantic-ui-react"; import UserContext from "../Contexts/UserContext"; import KadiStatsService from "../Services/KadiStatsService"; import RulesetList from "./RulesetList"; @@ -10,10 +10,13 @@ import CreateRulesetPanel from "./CreateRulesetPanel"; interface RulesetsPageProps {} interface RulesetsPageState { + unsavedChanges: boolean; loading: boolean; addingNewRuleset: boolean; rulesets: RulesetSchemaDto[]; selectedRulesetIndex: number; + modalContinueCallback: () => any; + showWarningModal: boolean; } class RulesetsPage extends React.Component { @@ -21,6 +24,9 @@ class RulesetsPage extends React.Component super(props); this.state = { + modalContinueCallback: () => {}, + showWarningModal: false, + unsavedChanges: false, loading: true, addingNewRuleset: false, rulesets: [], @@ -38,28 +44,48 @@ class RulesetsPage extends React.Component } onRulesetSelect(newRulesetId: string | "addNewRuleset") { + if (newRulesetId === "addNewRuleset" || !this.state.unsavedChanges) { + this.selectRuleset(newRulesetId); + } + else if (this.state.unsavedChanges) { + this.warn(() => this.selectRuleset(newRulesetId)); + } + } + + warn(callback: () => any) { + this.setState({showWarningModal: true, modalContinueCallback: callback}); + } + + selectRuleset(newRulesetId: string | "addNewRuleset") { if (newRulesetId === "addNewRuleset") { this.setState({addingNewRuleset: true}); - } - else { + } else { this.setState({ + unsavedChanges: false, addingNewRuleset: false, - selectedRulesetIndex: this.state.rulesets.findIndex(item => item.label === newRulesetId) + selectedRulesetIndex: this.state.rulesets.findIndex( + (item) => item.label === newRulesetId + ), }); } } - submitNewRuleset(ruleset: RulesetSchemaDto) { + onWarningModalActionClick() { + const oldContinueCallback = this.state.modalContinueCallback; + this.setState({showWarningModal: false, modalContinueCallback: () => {}}, () => + oldContinueCallback() + ); + } + onWarningModalClose() { + this.setState({showWarningModal: false, modalContinueCallback: () => {}}); } render(): ReactElement { const Locale = this.context.strings; return ( <> -
- {Locale.rulesetsPage.title} -
+
{Locale.rulesetsPage.title}
@@ -67,13 +93,14 @@ class RulesetsPage extends React.Component onItemChange={(r) => this.onRulesetSelect(r)} selectedItemIndex={this.state.selectedRulesetIndex} creatingRuleset={this.state.addingNewRuleset} - rulesetNames={this.state.rulesets.map(ruleset => ruleset.label)} + rulesetNames={this.state.rulesets.map((ruleset) => ruleset.label)} /> {this.state.addingNewRuleset ? ( this.submitNewRuleset(r)} + onRulesetSave={() => this.setState({unsavedChanges: false})} + onRulesetChange={() => this.setState({unsavedChanges: true})} /> ) : ( + this.onWarningModalClose()} + > + Discard ruleset? + Are you sure you want to discard the current ruleset? Any changes you've made will be lost. + + + + + ); } } RulesetsPage.contextType = UserContext; -export default RulesetsPage; \ No newline at end of file +export default RulesetsPage; diff --git a/src/Components/StatsPage.tsx b/src/Components/StatsPage.tsx index 3eae18a..bc22c88 100755 --- a/src/Components/StatsPage.tsx +++ b/src/Components/StatsPage.tsx @@ -1,20 +1,18 @@ import React, {ReactNode} from "react"; import { - Container, - Dropdown, DropdownItemProps, DropdownMenuProps, + Dropdown, + DropdownItemProps, Grid, GridColumn, GridRow, - Header, Segment, + Header, } from "semantic-ui-react"; import UserContext from "../Contexts/UserContext"; import {StatsTable} from "./StatsTable"; import KadiStatsService from "../Services/KadiStatsService"; import {ServiceError} from "../errors"; import Loading from "./Loading"; -import KadiStatsServiceSingleton from "../Services/KadiStatsService"; import {RulesetSchemaDto} from "../Services/RulesetSchemaDto"; -import {StatsDto} from "../Services/StatsDto"; interface StatsPageProps {} @@ -49,17 +47,14 @@ class StatsPage extends React.Component { this.setState({loadingStats: true}, async () => { try { await this.loadStatsAndRulesetChoices(); - } - catch (e) { + } catch (e) { if (e instanceof ServiceError) { this.setState({error: true}); console.log(e); - } - else { + } else { throw e; } - } - finally { + } finally { this.setState({loadingStats: false}); } }); @@ -70,11 +65,21 @@ class StatsPage extends React.Component { const rulesetIds = Object.keys(stats.pStats[0].stats.statsByRuleset); const schemas: Record = {}; for (const rulesetId of rulesetIds) { - schemas[rulesetId] = await KadiStatsService.getRulesetById(rulesetId); + schemas[rulesetId] = await KadiStatsService.getRulesetById( + rulesetId + ); } - const rulesetChoices = rulesetIds.map(rulesetId => - ({key: rulesetId, value: rulesetId, text: schemas[rulesetId].label})); - this.setState({stats, rulesetChoices, rulesetSchemas: schemas, selectedRulesetId: rulesetIds[0]}); + const rulesetChoices = rulesetIds.map((rulesetId) => ({ + key: rulesetId, + value: rulesetId, + text: schemas[rulesetId].label, + })); + this.setState({ + stats, + rulesetChoices, + rulesetSchemas: schemas, + selectedRulesetId: rulesetIds[0], + }); } handleError(error: any): void { @@ -102,23 +107,33 @@ class StatsPage extends React.Component { loading={this.state.loadingStats} selection={true} options={this.state.rulesetChoices} - defaultValue={this.state.rulesetChoices[0]?.value} - onChange={(e, choice) => this.changeRulesetSelection(choice.value as string)} + defaultValue={ + this.state.rulesetChoices[0]?.value + } + onChange={(e, choice) => + this.changeRulesetSelection( + choice.value as string + ) + } /> - {this.state.error ? -

{Locale.general.databaseError}

: - this.state.loadingStats ? - : ( - - ) - } + {this.state.error ? ( +

{Locale.general.databaseError}

+ ) : this.state.loadingStats ? ( + + ) : ( + + )}
@@ -128,4 +143,4 @@ class StatsPage extends React.Component { } StatsPage.contextType = UserContext; -export default StatsPage; \ No newline at end of file +export default StatsPage; diff --git a/src/Services/KadiPlayerService.ts b/src/Services/KadiPlayerService.ts new file mode 100644 index 0000000..abb2a60 --- /dev/null +++ b/src/Services/KadiPlayerService.ts @@ -0,0 +1,28 @@ +import {RulesetSchemaDto} from "./RulesetSchemaDto"; + +class KadiPlayerService { + private readonly players: PlayerDto[] = []; + constructor() {} + + async getPlayerById(id: string): Promise { + if (!this.rulesets[id]) { + await this.loadRulesetById(id); + } + return this.rulesets[id]; + } + + async refreshStats(): Promise { + await this.loadStats(); + } + + async getAllRulesets(): Promise { + if (!this.allRulesetsLoaded) { + await this.loadAllRulesets(); + } + return Object.values(this.rulesets); + } +} + +const KadiStatsServiceSingleton = new KadiStatsService(); + +export default KadiStatsServiceSingleton; \ No newline at end of file diff --git a/src/Services/KadiStatsService.ts b/src/Services/KadiStatsService.ts index 780e561..8a4c402 100644 --- a/src/Services/KadiStatsService.ts +++ b/src/Services/KadiStatsService.ts @@ -3,10 +3,6 @@ import {SERVER_BASE_NAME} from "../index"; import {StatsDto} from "./StatsDto"; import {RulesetSchemaDto} from "./RulesetSchemaDto"; -const dummyRulesets = [ - {"id":"DEFAULT_RULESET","label":"Standard Kadi Rules (en)","blocks":{"top":{"label":"Upper","hasBonus":true,"bonusScore":35,"bonusFor":63,"cells":{"aces":{"fieldType":"multiplierField","label":"Aces","multiplier":1,"maxMultiples":5},"twos":{"fieldType":"multiplierField","label":"Twos","multiplier":2,"maxMultiples":5},"threes":{"fieldType":"multiplierField","label":"Threes","multiplier":3,"maxMultiples":5},"fours":{"fieldType":"multiplierField","label":"Fours","multiplier":4,"maxMultiples":5},"fives":{"fieldType":"multiplierField","label":"Fives","multiplier":5,"maxMultiples":5},"sixes":{"fieldType":"multiplierField","label":"Sixes","multiplier":6,"maxMultiples":5}}},"bottom":{"label":"Lower","hasBonus":false,"cells":{"threeKind":{"fieldType":"numberField","label":"Three of a Kind"},"fourKind":{"fieldType":"numberField","label":"Four of a Kind"},"fullHouse":{"fieldType":"boolField","label":"Full House","score":25},"smlStraight":{"fieldType":"boolField","label":"Small Straight","score":30},"lgSraight":{"fieldType":"boolField","label":"Large Straight","score":40},"superkadi":{"fieldType":"superkadiField","label":"Super Kadis","score":50,"maxSuperkadis":5},"chance":{"fieldType":"numberField","label":"Chance"}}}}} -]; - class KadiStatsService { private userStats: StatsDto | null = null; private rulesets: Record = {}; @@ -19,6 +15,18 @@ class KadiStatsService { return this.userStats; } + private async loadAllRulesets(): Promise { + const rulesetSchemas = (await axios.get(SERVER_BASE_NAME + "/api/rulesets/")).data.rulesets as RulesetSchemaDto[]; + console.log(rulesetSchemas); + rulesetSchemas.forEach(schema => this.rulesets[schema.id] = schema); + this.allRulesetsLoaded = true; + } + + private async loadRulesetById(id: string): Promise { + const rulesetSchema = (await axios.get(SERVER_BASE_NAME + "/api/ruleset/" + id)).data as RulesetSchemaDto; + this.rulesets[rulesetSchema.id] = rulesetSchema; + } + async getStats(): Promise { if (this.userStats) { return this.userStats; @@ -29,14 +37,10 @@ class KadiStatsService { } async getRulesetById(id: string): Promise { - if (this.rulesets[id]) { - return this.rulesets[id]; - } - else { - const rulesetSchema = (await axios.get(SERVER_BASE_NAME + "/api/ruleset/" + id)).data as RulesetSchemaDto; - this.rulesets[rulesetSchema.id] = rulesetSchema; - return this.rulesets[rulesetSchema.id]; + if (!this.rulesets[id]) { + await this.loadRulesetById(id); } + return this.rulesets[id]; } async refreshStats(): Promise { @@ -44,16 +48,10 @@ class KadiStatsService { } async getAllRulesets(): Promise { - return dummyRulesets as RulesetSchemaDto[]; - if (this.allRulesetsLoaded) { - return Object.values(this.rulesets); - } - else { - const rulesetSchemas = (await axios.get(SERVER_BASE_NAME + "/api/rulesets/")).data as RulesetSchemaDto[]; - rulesetSchemas.forEach(schema => this.rulesets[schema.id] = schema); - this.allRulesetsLoaded = true; - return rulesetSchemas; + if (!this.allRulesetsLoaded) { + await this.loadAllRulesets(); } + return Object.values(this.rulesets); } } diff --git a/src/Services/PlayerDto.ts b/src/Services/PlayerDto.ts new file mode 100644 index 0000000..d00ec9d --- /dev/null +++ b/src/Services/PlayerDto.ts @@ -0,0 +1,6 @@ +interface PlayerMongoData { + id: string; + nick: string; +} + +export default PlayerDto; \ No newline at end of file diff --git a/src/Services/RulesetSchemaDto.ts b/src/Services/RulesetSchemaDto.ts index f388a77..250730c 100644 --- a/src/Services/RulesetSchemaDto.ts +++ b/src/Services/RulesetSchemaDto.ts @@ -1,3 +1,5 @@ +import {FieldType} from "../enums"; + export interface RulesetSchemaDto { id: string; label: string; diff --git a/src/static/strings.ts b/src/static/strings.ts index f2adcdc..64052fa 100755 --- a/src/static/strings.ts +++ b/src/static/strings.ts @@ -66,7 +66,7 @@ export const IntlStrings = { blocksHeader: "Blocks", fieldLabelHeader: "Label", fieldTypeHeader: "Type", - fieldValueHeader: "Value", + fieldAttributesHeader: "Attributes", superkadiField: "Superkadi", multiplierField: "Multiplier Cell", boolField: "Boolean Cell", @@ -84,9 +84,12 @@ export const IntlStrings = { cellNamePlaceholder: "My New Cell", fieldTypePlaceholder: "Select a field type", multiplierPlaceholder: "Multiplier", - maxMultiplesPlaceholder: "Max of kind", + maxMultiplesPlaceholder: "Max Multiples", + maxSuperkadisPlaceholder: "Max Superkadis", valuePlaceholder: "Value", - submit: "Submit", + save: "Save", + extraCellSettingsInfo: "No attributes available", + newCell: "New Cell", }, friendsPage: { title: "Friends", @@ -135,7 +138,7 @@ export const IntlStrings = { blocksHeader: "Blöcke", fieldLabelHeader: "Name", fieldTypeHeader: "Typ", - fieldValueHeader: "Wert", + fieldAttributesHeader: "Eigenschaften", superkadiField: "Superkadi", multiplierField: "Multiplikator-Feld", boolField: "Bool'sches Feld", @@ -155,8 +158,11 @@ export const IntlStrings = { fieldTypePlaceholder: "Feldtyp auswählen", multiplierPlaceholder: "Multiplikator", maxMultiplesPlaceholder: "Max. Anzahl", + maxSuperkadisPlaceholder: "Max. Anzahl", valuePlaceholder: "Wert", - submit: "Fertig", + save: "Speichern", + extraCellSettingsInfo: "Keine Eigenschaften vorhanden", + newCell: "Neues Feld", }, friendsPage: { title: "Freunde", @@ -205,7 +211,7 @@ export const IntlStrings = { blocksHeader: "===TRANSLATE ME===", fieldLabelHeader: "===TRANSLATE ME===", fieldTypeHeader: "===TRANSLATE ME===", - fieldValueHeader: "===TRANSLATE ME===", + fieldAttributesHeader: "===TRANSLATE ME===", superkadiField: "===TRANSLATE ME===", multiplierField: "===TRANSLATE ME===", boolField: "===TRANSLATE ME===", diff --git a/tslint.json b/tslint.json index 902e445..801649c 100755 --- a/tslint.json +++ b/tslint.json @@ -1,7 +1,8 @@ { "defaultSeverity": "error", "extends": [ - "tslint-react" + "tslint-react", + "tslint-config-prettier" ], "jsRules": { },