noot
This commit is contained in:
parent
8c9437c0be
commit
bd20e23b15
7
.biomeignore
Normal file
7
.biomeignore
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
dist
|
||||||
|
**/vendor/**
|
||||||
|
**/locales/**
|
||||||
|
generated.*
|
||||||
|
node_modules
|
||||||
|
*.min.js
|
||||||
|
*.min.css
|
||||||
59
biome.json
Normal file
59
biome.json
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
|
||||||
|
"files": {
|
||||||
|
"ignoreUnknown": true
|
||||||
|
},
|
||||||
|
"linter": {
|
||||||
|
"enabled": true,
|
||||||
|
"rules": {
|
||||||
|
"recommended": true,
|
||||||
|
"style": {
|
||||||
|
"noUselessElse": "error",
|
||||||
|
"useConst": "warn",
|
||||||
|
"useImportType": "off",
|
||||||
|
"useNodejsImportProtocol": "off"
|
||||||
|
},
|
||||||
|
"suspicious": {
|
||||||
|
"noConsole": "error",
|
||||||
|
"noRedeclare": "off",
|
||||||
|
"noDoubleEquals": "warn",
|
||||||
|
"noExplicitAny": "off"
|
||||||
|
},
|
||||||
|
"correctness": {
|
||||||
|
"noUndeclaredVariables": "off",
|
||||||
|
"useExhaustiveDependencies": "off",
|
||||||
|
"noUnusedImports": "warn"
|
||||||
|
},
|
||||||
|
"complexity": {
|
||||||
|
"noExtraBooleanCast": "warn",
|
||||||
|
"noBannedTypes": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"formatter": {
|
||||||
|
"enabled": true,
|
||||||
|
"formatWithErrors": false,
|
||||||
|
"indentStyle": "space",
|
||||||
|
"indentWidth": 2,
|
||||||
|
"lineWidth": 100
|
||||||
|
},
|
||||||
|
"javascript": {
|
||||||
|
"parser": {
|
||||||
|
"unsafeParameterDecoratorsEnabled": true
|
||||||
|
},
|
||||||
|
"formatter": {
|
||||||
|
"quoteStyle": "single",
|
||||||
|
"jsxQuoteStyle": "double",
|
||||||
|
"semicolons": "asNeeded",
|
||||||
|
"trailingCommas": "all",
|
||||||
|
"arrowParentheses": "asNeeded"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"json": {
|
||||||
|
"formatter": {
|
||||||
|
"enabled": true,
|
||||||
|
"indentStyle": "space",
|
||||||
|
"indentWidth": 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,54 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
settings: {
|
|
||||||
react: {
|
|
||||||
version: 'detect',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
root: true,
|
|
||||||
env: { browser: true, es2020: true },
|
|
||||||
extends: [
|
|
||||||
'eslint:recommended',
|
|
||||||
'plugin:@typescript-eslint/recommended',
|
|
||||||
'plugin:react/recommended',
|
|
||||||
'plugin:react-hooks/recommended',
|
|
||||||
'plugin:react/jsx-runtime',
|
|
||||||
],
|
|
||||||
ignorePatterns: ['dist', '.eslintrc.cjs', '**/vendor/**', '**/locales/**', 'generated.*'],
|
|
||||||
parser: '@typescript-eslint/parser',
|
|
||||||
parserOptions: {
|
|
||||||
project: true,
|
|
||||||
tsconfigRootDir: __dirname,
|
|
||||||
ecmaFeatures: {
|
|
||||||
jsx: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
plugins: ['react-refresh', 'react'],
|
|
||||||
rules: {
|
|
||||||
'no-extra-semi': 'off', // this one needs to stay off
|
|
||||||
'@react/no-children-prop': 'off', // tanstack form uses this as a pattern
|
|
||||||
'react/no-children-prop': 'off', // tanstack form uses this as a pattern
|
|
||||||
'no-duplicate-imports': 'warn',
|
|
||||||
'@typescript-eslint/no-extra-semi': 'off',
|
|
||||||
'sort-imports': 'off',
|
|
||||||
'react-hooks/exhaustive-deps': 'off',
|
|
||||||
'react-refresh/only-export-components': 'off',
|
|
||||||
'no-case-declarations': 'off',
|
|
||||||
'no-redeclare': 'off',
|
|
||||||
'no-undef': 'off',
|
|
||||||
'@typescript-eslint/no-explicit-any': 'off',
|
|
||||||
'@typescript-eslint/strict-boolean-expressions': ['error', {
|
|
||||||
"allowString": true,
|
|
||||||
"allowNumber": true,
|
|
||||||
"allowNullableObject": true,
|
|
||||||
"allowNullableBoolean": true,
|
|
||||||
"allowNullableString": true,
|
|
||||||
"allowNullableNumber": false,
|
|
||||||
"allowNullableEnum": true,
|
|
||||||
"allowAny": true
|
|
||||||
}],
|
|
||||||
'react/prop-types': 'off',
|
|
||||||
'no-lonely-if': 2,
|
|
||||||
'no-console': 2,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
15
package.json
15
package.json
@ -2,31 +2,29 @@
|
|||||||
"name": "lifeto-shop",
|
"name": "lifeto-shop",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview",
|
||||||
|
"lint": "biome check .",
|
||||||
|
"lint:fix": "biome check --write .",
|
||||||
|
"format": "biome format --write ."
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@floating-ui/react": "^0.27.8",
|
"@floating-ui/react": "^0.27.8",
|
||||||
"@handsontable/react": "^15.3.0",
|
"@handsontable/react": "^15.3.0",
|
||||||
"@mantine/hooks": "^8.0.0",
|
"@mantine/hooks": "^8.0.0",
|
||||||
|
"@tailwindcss/vite": "^4.1.10",
|
||||||
"@tanstack/react-query": "^5.76.0",
|
"@tanstack/react-query": "^5.76.0",
|
||||||
"@tanstack/react-table": "^8.21.3",
|
"@tanstack/react-table": "^8.21.3",
|
||||||
"@types/qs": "^6.9.18",
|
"@types/qs": "^6.9.18",
|
||||||
"@types/react": "^19.1.4",
|
"@types/react": "^19.1.4",
|
||||||
"@types/react-dom": "^19.1.5",
|
"@types/react-dom": "^19.1.5",
|
||||||
"@types/uuid": "^10.0.0",
|
"@types/uuid": "^10.0.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.32.1",
|
|
||||||
"@typescript-eslint/parser": "^8.32.1",
|
|
||||||
"@vitejs/plugin-react": "^4.4.1",
|
"@vitejs/plugin-react": "^4.4.1",
|
||||||
"arktype": "^2.1.20",
|
"arktype": "^2.1.20",
|
||||||
"axios": "^1.9.0",
|
"axios": "^1.9.0",
|
||||||
"eslint": "^9.26.0",
|
|
||||||
"eslint-config-react-app": "^7.0.1",
|
|
||||||
"eslint-plugin-react": "^7.37.5",
|
|
||||||
"eslint-plugin-react-hooks": "^5.2.0",
|
|
||||||
"eslint-plugin-react-refresh": "^0.4.20",
|
|
||||||
"fuse.js": "^7.1.0",
|
"fuse.js": "^7.1.0",
|
||||||
"handsontable": "^15.3.0",
|
"handsontable": "^15.3.0",
|
||||||
"jotai": "^2.12.4",
|
"jotai": "^2.12.4",
|
||||||
@ -49,6 +47,7 @@
|
|||||||
"uuid": "^11.1.0"
|
"uuid": "^11.1.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@biomejs/biome": "^2.0.0",
|
||||||
"@tailwindcss/postcss": "^4.1.6",
|
"@tailwindcss/postcss": "^4.1.6",
|
||||||
"@types/node": "^22.15.18",
|
"@types/node": "^22.15.18",
|
||||||
"postcss": "^8.5.3",
|
"postcss": "^8.5.3",
|
||||||
|
|||||||
@ -1,5 +0,0 @@
|
|||||||
module.exports = {
|
|
||||||
plugins: {
|
|
||||||
'@tailwindcss/postcss': {},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
12
src/App.tsx
12
src/App.tsx
@ -1,7 +1,7 @@
|
|||||||
import { FC } from "react";
|
import { FC } from 'react'
|
||||||
import { LoginWidget } from "./components/login";
|
import { CharacterRoulette } from './components/characters'
|
||||||
import { CharacterRoulette } from "./components/characters";
|
import { Inventory } from './components/inventory/index'
|
||||||
import { Inventory } from "./components/inventory/index";
|
import { LoginWidget } from './components/login'
|
||||||
|
|
||||||
export const App: FC = () => {
|
export const App: FC = () => {
|
||||||
return (
|
return (
|
||||||
@ -16,8 +16,8 @@ export const App: FC = () => {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
);
|
)
|
||||||
};
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
<div className="flex flex-col p-4 h-full">
|
<div className="flex flex-col p-4 h-full">
|
||||||
|
|||||||
@ -1,87 +1,82 @@
|
|||||||
import { TricksterCharacter } from "../lib/trickster"
|
|
||||||
import Fuse from 'fuse.js'
|
|
||||||
import { useAtom } from "jotai"
|
|
||||||
import { charactersAtom, selectedCharacterAtom } from "../state/atoms"
|
|
||||||
import { useMemo, useState } from "react";
|
|
||||||
import {
|
import {
|
||||||
useFloating,
|
|
||||||
autoUpdate,
|
autoUpdate,
|
||||||
offset,
|
FloatingPortal,
|
||||||
flip,
|
flip,
|
||||||
|
offset,
|
||||||
shift,
|
shift,
|
||||||
useHover,
|
|
||||||
useFocus,
|
|
||||||
useDismiss,
|
useDismiss,
|
||||||
useRole,
|
useFloating,
|
||||||
|
useFocus,
|
||||||
|
useHover,
|
||||||
useInteractions,
|
useInteractions,
|
||||||
FloatingPortal
|
useRole,
|
||||||
} from "@floating-ui/react";
|
} from '@floating-ui/react'
|
||||||
|
import Fuse from 'fuse.js'
|
||||||
|
import { useAtom } from 'jotai'
|
||||||
|
import { useMemo, useState } from 'react'
|
||||||
|
import { TricksterCharacter } from '../lib/trickster'
|
||||||
|
import { charactersAtom, selectedCharacterAtom } from '../state/atoms'
|
||||||
|
|
||||||
export const CharacterCard = ({character}:{
|
export const CharacterCard = ({ character }: { character: TricksterCharacter }) => {
|
||||||
character: TricksterCharacter,
|
const [isOpen, setIsOpen] = useState(false)
|
||||||
})=>{
|
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
|
|
||||||
const { refs, floatingStyles, context } = useFloating({
|
const { refs, floatingStyles, context } = useFloating({
|
||||||
open: isOpen,
|
open: isOpen,
|
||||||
onOpenChange: setIsOpen,
|
onOpenChange: setIsOpen,
|
||||||
placement: "top",
|
placement: 'top',
|
||||||
// Make sure the tooltip stays on the screen
|
// Make sure the tooltip stays on the screen
|
||||||
whileElementsMounted: autoUpdate,
|
whileElementsMounted: autoUpdate,
|
||||||
middleware: [
|
middleware: [
|
||||||
offset(5),
|
offset(5),
|
||||||
flip({
|
flip({
|
||||||
fallbackAxisSideDirection: "start"
|
fallbackAxisSideDirection: 'start',
|
||||||
}),
|
}),
|
||||||
shift()
|
shift(),
|
||||||
]
|
],
|
||||||
});
|
})
|
||||||
|
|
||||||
// Event listeners to change the open state
|
// Event listeners to change the open state
|
||||||
const hover = useHover(context, { move: false });
|
const hover = useHover(context, { move: false })
|
||||||
const focus = useFocus(context);
|
const focus = useFocus(context)
|
||||||
const dismiss = useDismiss(context);
|
const dismiss = useDismiss(context)
|
||||||
// Role props for screen readers
|
// Role props for screen readers
|
||||||
const role = useRole(context, { role: "tooltip" });
|
const role = useRole(context, { role: 'tooltip' })
|
||||||
|
|
||||||
// Merge all the interactions into prop getters
|
// Merge all the interactions into prop getters
|
||||||
const { getReferenceProps, getFloatingProps } = useInteractions([
|
const { getReferenceProps, getFloatingProps } = useInteractions([hover, focus, dismiss, role])
|
||||||
hover,
|
|
||||||
focus,
|
|
||||||
dismiss,
|
|
||||||
role
|
|
||||||
]);
|
|
||||||
const [selectedCharacter, setSelectedCharacter] = useAtom(selectedCharacterAtom)
|
const [selectedCharacter, setSelectedCharacter] = useAtom(selectedCharacterAtom)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
return <>
|
<div
|
||||||
<div onClick={()=>{
|
onClick={() => {
|
||||||
setSelectedCharacter(character)
|
setSelectedCharacter(character)
|
||||||
}}
|
}}
|
||||||
|
ref={refs.setReference}
|
||||||
ref={refs.setReference} {...getReferenceProps()}
|
{...getReferenceProps()}
|
||||||
className={`
|
className={`
|
||||||
flex flex-col border border-black
|
flex flex-col border border-black
|
||||||
hover:cursor-pointer
|
hover:cursor-pointer
|
||||||
hover:bg-blue-100
|
hover:bg-blue-100
|
||||||
p-2 ${character.path === selectedCharacter?.path? `bg-blue-200 hover:bg-blue-100` : ""}`}>
|
p-2 ${character.path === selectedCharacter?.path ? `bg-blue-200 hover:bg-blue-100` : ''}`}
|
||||||
|
>
|
||||||
<div className="flex flex-col justify-between h-full">
|
<div className="flex flex-col justify-between h-full">
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col gap-2">
|
||||||
<div className="flex flex-row justify-center"
|
<div className="flex flex-row justify-center">
|
||||||
>
|
{character.base_job === -8 ? (
|
||||||
{character.base_job === -8 ?
|
<img className="h-8" src="https://beta.lifeto.co/item_img/gel.nri.003.000.png" />
|
||||||
<img
|
) : (
|
||||||
className="h-8"
|
|
||||||
src="https://beta.lifeto.co/item_img/gel.nri.003.000.png"
|
|
||||||
/>
|
|
||||||
:
|
|
||||||
<img
|
<img
|
||||||
className="h-16"
|
className="h-16"
|
||||||
src={`https://knowledge.lifeto.co/animations/character/chr${
|
src={`https://knowledge.lifeto.co/animations/character/chr${(
|
||||||
(character.current_job - character.base_job - 1).toString().padStart(3,"0")
|
character.current_job -
|
||||||
}_13.png`}/>
|
character.base_job -
|
||||||
}
|
1
|
||||||
|
)
|
||||||
|
.toString()
|
||||||
|
.padStart(3, '0')}_13.png`}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<FloatingPortal>
|
<FloatingPortal>
|
||||||
{isOpen && (
|
{isOpen && (
|
||||||
@ -92,32 +87,36 @@ export const CharacterCard = ({character}:{
|
|||||||
{...getFloatingProps()}
|
{...getFloatingProps()}
|
||||||
>
|
>
|
||||||
<div className="flex flex-col gap-1 bg-white">
|
<div className="flex flex-col gap-1 bg-white">
|
||||||
{character.base_job === -8 ? "bank" : character.name}
|
{character.base_job === -8 ? 'bank' : character.name}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</FloatingPortal>
|
</FloatingPortal>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
const PleaseLogin = () => {
|
const PleaseLogin = () => {
|
||||||
return <><div className="align-center">no characters (not logged in?)</div></>
|
return (
|
||||||
|
<>
|
||||||
|
<div className="align-center">no characters (not logged in?)</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const CharacterRoulette = () => {
|
export const CharacterRoulette = () => {
|
||||||
const [{ data: rawCharacters }] = useAtom(charactersAtom)
|
const [{ data: rawCharacters }] = useAtom(charactersAtom)
|
||||||
|
|
||||||
const [search, setSearch] = useState("")
|
const [search, setSearch] = useState('')
|
||||||
|
|
||||||
const { characters, fuse } = useMemo(() => {
|
const { characters, fuse } = useMemo(() => {
|
||||||
if (!rawCharacters) {
|
if (!rawCharacters) {
|
||||||
return {
|
return {
|
||||||
characters: [],
|
characters: [],
|
||||||
fuse: new Fuse([], {})
|
fuse: new Fuse([], {}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// transform characters into pairs between the bank and not bank
|
// transform characters into pairs between the bank and not bank
|
||||||
@ -127,37 +126,40 @@ export const CharacterRoulette = ()=>{
|
|||||||
findAllMatches: true,
|
findAllMatches: true,
|
||||||
threshold: 0.8,
|
threshold: 0.8,
|
||||||
useExtendedSearch: true,
|
useExtendedSearch: true,
|
||||||
keys: ["character.name"],
|
keys: ['character.name'],
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}, [rawCharacters])
|
}, [rawCharacters])
|
||||||
if(!characters || characters.length == 0) {
|
if (!characters || characters.length === 0) {
|
||||||
return <PleaseLogin />
|
return <PleaseLogin />
|
||||||
}
|
}
|
||||||
const searchResults = fuse.search(search || "!-----", {
|
const searchResults = fuse
|
||||||
|
.search(search || '!-----', {
|
||||||
limit: 20,
|
limit: 20,
|
||||||
}).map((x)=>{
|
})
|
||||||
return <div className="flex flex-col" key={`${x.item.character.account_id}`}>
|
.map(x => {
|
||||||
|
return (
|
||||||
|
<div className="flex flex-col" key={`${x.item.character.account_id}`}>
|
||||||
<CharacterCard key={x.item.bank.id} character={x.item.bank} />
|
<CharacterCard key={x.item.bank.id} character={x.item.bank} />
|
||||||
<CharacterCard key={x.item.character.id} character={x.item.character} />
|
<CharacterCard key={x.item.character.id} character={x.item.character} />
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
})
|
})
|
||||||
return <>
|
return (
|
||||||
|
<>
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<input
|
<input
|
||||||
className="border border-black-1 bg-gray-100 placeholder-gray-600 p-1 max-w-[180px]"
|
className="border border-black-1 bg-gray-100 placeholder-gray-600 p-1 max-w-[180px]"
|
||||||
placeholder="search character..."
|
placeholder="search character..."
|
||||||
value={search}
|
value={search}
|
||||||
onChange={(e)=>{
|
onChange={e => {
|
||||||
setSearch(e.target.value)
|
setSearch(e.target.value)
|
||||||
}}
|
}}
|
||||||
></input>
|
></input>
|
||||||
<div className="flex flex-row flex-wrap overflow-x-scroll gap-1 h-full min-h-36 max-w-48">
|
<div className="flex flex-row flex-wrap overflow-x-scroll gap-1 h-full min-h-36 max-w-48">
|
||||||
{searchResults ? searchResults : <>
|
{searchResults ? searchResults : <></>}
|
||||||
</>}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,11 +1,19 @@
|
|||||||
import { clearItemSelectionActionAtom, currentCharacterItemsAtom, filteredCharacterItemsAtom, inventoryFilterAtom, inventoryItemsCurrentPageAtom, inventoryPageRangeAtom, itemSelectionSelectAllFilterActionAtom, itemSelectionSelectAllPageActionAtom, paginateInventoryActionAtom, preferenceInventorySearch, selectedCharacterAtom, setInventoryFilterTabActionAtom} from "@/state/atoms";
|
import { useAtom, useAtomValue, useSetAtom } from 'jotai'
|
||||||
import {useAtom, useAtomValue, useSetAtom } from "jotai";
|
import { FaArrowLeft, FaArrowRight } from 'react-icons/fa'
|
||||||
import { InventoryTargetSelector } from './movetarget';
|
import {
|
||||||
import { InventoryTable } from './table';
|
clearItemSelectionActionAtom,
|
||||||
import { FaArrowLeft, FaArrowRight } from "react-icons/fa";
|
filteredCharacterItemsAtom,
|
||||||
|
inventoryFilterAtom,
|
||||||
|
inventoryPageRangeAtom,
|
||||||
|
itemSelectionSelectAllFilterActionAtom,
|
||||||
|
itemSelectionSelectAllPageActionAtom,
|
||||||
|
paginateInventoryActionAtom,
|
||||||
|
preferenceInventorySearch,
|
||||||
|
selectedCharacterAtom,
|
||||||
|
setInventoryFilterTabActionAtom,
|
||||||
|
} from '@/state/atoms'
|
||||||
|
import { InventoryTargetSelector } from './movetarget'
|
||||||
|
import { InventoryTable } from './table'
|
||||||
|
|
||||||
const sections = [
|
const sections = [
|
||||||
{ name: 'all', value: '' },
|
{ name: 'all', value: '' },
|
||||||
@ -14,7 +22,6 @@ const sections = [
|
|||||||
{ name: 'drill', value: '3' },
|
{ name: 'drill', value: '3' },
|
||||||
{ name: 'pet', value: '4' },
|
{ name: 'pet', value: '4' },
|
||||||
{ name: 'etc', value: '5' },
|
{ name: 'etc', value: '5' },
|
||||||
|
|
||||||
]
|
]
|
||||||
|
|
||||||
const cardSections = [
|
const cardSections = [
|
||||||
@ -27,49 +34,58 @@ const cardSections = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
const InventoryTabs = () => {
|
const InventoryTabs = () => {
|
||||||
|
|
||||||
const inventoryFilter = useAtomValue(inventoryFilterAtom)
|
const inventoryFilter = useAtomValue(inventoryFilterAtom)
|
||||||
const setInventoryFilterTab = useSetAtom(setInventoryFilterTabActionAtom)
|
const setInventoryFilterTab = useSetAtom(setInventoryFilterTabActionAtom)
|
||||||
const inventoryRange = useAtomValue(inventoryPageRangeAtom)
|
const inventoryRange = useAtomValue(inventoryPageRangeAtom)
|
||||||
const items = useAtomValue(filteredCharacterItemsAtom)
|
const items = useAtomValue(filteredCharacterItemsAtom)
|
||||||
console.log("items", items)
|
const sharedStyle = 'hover:cursor-pointer hover:bg-gray-200 px-2 pr-4 border border-gray-200'
|
||||||
const sharedStyle = "hover:cursor-pointer hover:bg-gray-200 px-2 pr-4 border border-gray-200"
|
const selectedStyle = 'bg-gray-200 border-b-2 border-black-1'
|
||||||
const selectedStyle = "bg-gray-200 border-b-2 border-black-1"
|
return (
|
||||||
return <div className="flex flex-row gap-1 justify-between">
|
<div className="flex flex-row gap-1 justify-between">
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<div className="flex flex-row gap-1">
|
<div className="flex flex-row gap-1">
|
||||||
{sections.map(x => {
|
{sections.map(x => {
|
||||||
return <div
|
return (
|
||||||
|
<div
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setInventoryFilterTab(x.value)
|
setInventoryFilterTab(x.value)
|
||||||
}}
|
}}
|
||||||
key={x.name}
|
key={x.name}
|
||||||
className={`${sharedStyle}
|
className={`${sharedStyle}
|
||||||
${inventoryFilter.tab === x.value ? selectedStyle : ""}`}
|
${inventoryFilter.tab === x.value ? selectedStyle : ''}`}
|
||||||
>{x.name}</div>
|
>
|
||||||
|
{x.name}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row gap-1">
|
<div className="flex flex-row gap-1">
|
||||||
{cardSections.map(x => {
|
{cardSections.map(x => {
|
||||||
return <div
|
return (
|
||||||
|
<div
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setInventoryFilterTab(x.value)
|
setInventoryFilterTab(x.value)
|
||||||
}}
|
}}
|
||||||
key={x.name}
|
key={x.name}
|
||||||
className={`${sharedStyle}
|
className={`${sharedStyle}
|
||||||
${inventoryFilter.tab === x.value ? selectedStyle : ""}`}
|
${inventoryFilter.tab === x.value ? selectedStyle : ''}`}
|
||||||
>{x.name}</div>
|
>
|
||||||
|
{x.name}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row gap-1 items-center px-1 bg-yellow-100">
|
<div className="flex flex-row gap-1 items-center px-1 bg-yellow-100">
|
||||||
<div className="whitespace-pre select-none">{inventoryRange.start}..{inventoryRange.end}/{items.length} </div>
|
<div className="whitespace-pre select-none">
|
||||||
|
{inventoryRange.start}..{inventoryRange.end}/{items.length}{' '}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Inventory = () => {
|
export const Inventory = () => {
|
||||||
|
|
||||||
const selectedCharacter = useAtomValue(selectedCharacterAtom)
|
const selectedCharacter = useAtomValue(selectedCharacterAtom)
|
||||||
const clearItemSelection = useSetAtom(clearItemSelectionActionAtom)
|
const clearItemSelection = useSetAtom(clearItemSelectionActionAtom)
|
||||||
|
|
||||||
@ -77,41 +93,51 @@ export const Inventory = () => {
|
|||||||
const addFilterItemSelection = useSetAtom(itemSelectionSelectAllFilterActionAtom)
|
const addFilterItemSelection = useSetAtom(itemSelectionSelectAllFilterActionAtom)
|
||||||
const [search, setSearch] = useAtom(preferenceInventorySearch)
|
const [search, setSearch] = useAtom(preferenceInventorySearch)
|
||||||
|
|
||||||
|
|
||||||
const paginateInventory = useSetAtom(paginateInventoryActionAtom)
|
const paginateInventory = useSetAtom(paginateInventoryActionAtom)
|
||||||
|
|
||||||
if (!selectedCharacter) {
|
if (!selectedCharacter) {
|
||||||
return <div>
|
return <div>select a character</div>
|
||||||
select a character
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
return <div className={`flex flex-col h-full w-full`}>
|
return (
|
||||||
|
<div className={`flex flex-col h-full w-full`}>
|
||||||
<div className="flex flex-col py-2 flex-0 justify-between h-full">
|
<div className="flex flex-col py-2 flex-0 justify-between h-full">
|
||||||
<div className="flex flex-row justify-between">
|
<div className="flex flex-row justify-between">
|
||||||
<div className="flex flex-row gap-2">
|
<div className="flex flex-row gap-2">
|
||||||
<div className="whitespace-pre bg-blue-200 px-2 py-1 rounded-xl hover:cursor-pointer hover:bg-blue-300"
|
<div
|
||||||
|
className="whitespace-pre bg-blue-200 px-2 py-1 rounded-xl hover:cursor-pointer hover:bg-blue-300"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
addPageItemSelection()
|
addPageItemSelection()
|
||||||
}}
|
}}
|
||||||
>select filtered</div>
|
>
|
||||||
<div className="whitespace-pre bg-blue-200 px-2 py-1 rounded-xl hover:cursor-pointer hover:bg-blue-300"
|
select filtered
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="whitespace-pre bg-blue-200 px-2 py-1 rounded-xl hover:cursor-pointer hover:bg-blue-300"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
addFilterItemSelection()
|
addFilterItemSelection()
|
||||||
}}
|
}}
|
||||||
>select page</div>
|
>
|
||||||
<div className="whitespace-pre bg-blue-200 px-2 py-1 rounded-xl hover:cursor-pointer hover:bg-blue-300"
|
select page
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="whitespace-pre bg-blue-200 px-2 py-1 rounded-xl hover:cursor-pointer hover:bg-blue-300"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
clearItemSelection()
|
clearItemSelection()
|
||||||
}}
|
}}
|
||||||
>clear </div>
|
>
|
||||||
|
clear{' '}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row">
|
<div className="flex flex-row">
|
||||||
<InventoryTargetSelector />
|
<InventoryTargetSelector />
|
||||||
<div
|
<div
|
||||||
onClick={(e)=>{
|
onClick={_e => {
|
||||||
// sendOrders()
|
// sendOrders()
|
||||||
}}
|
}}
|
||||||
className="hover:cursor-pointer whitespace-preborder border-black-1 bg-orange-200 hover:bg-orange-300 px-2 py-1">Move Selected</div>
|
className="hover:cursor-pointer whitespace-preborder border-black-1 bg-orange-200 hover:bg-orange-300 px-2 py-1"
|
||||||
|
>
|
||||||
|
Move Selected
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -122,7 +148,7 @@ export const Inventory = () => {
|
|||||||
value={search}
|
value={search}
|
||||||
className="border border-black-1 px-2 py-1"
|
className="border border-black-1 px-2 py-1"
|
||||||
placeholder="search..."
|
placeholder="search..."
|
||||||
onChange={(e)=>{
|
onChange={e => {
|
||||||
setSearch(e.target.value)
|
setSearch(e.target.value)
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@ -131,13 +157,17 @@ export const Inventory = () => {
|
|||||||
onClick={() => {
|
onClick={() => {
|
||||||
paginateInventory(-1)
|
paginateInventory(-1)
|
||||||
}}
|
}}
|
||||||
><FaArrowLeft/></div>
|
>
|
||||||
|
<FaArrowLeft />
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
className="hover:cursor-pointer border border-black-1 bg-green-200 hover:bg-green-300 px-2 py-1 h-full flex items-center"
|
className="hover:cursor-pointer border border-black-1 bg-green-200 hover:bg-green-300 px-2 py-1 h-full flex items-center"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
paginateInventory(1)
|
paginateInventory(1)
|
||||||
}}
|
}}
|
||||||
><FaArrowRight/></div>
|
>
|
||||||
|
<FaArrowRight />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -146,4 +176,5 @@ export const Inventory = () => {
|
|||||||
<InventoryTable />
|
<InventoryTable />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,22 +1,30 @@
|
|||||||
|
import {
|
||||||
import { forwardRef, useId, useMemo, useRef, useState} from "react";
|
autoUpdate,
|
||||||
import { useAtom, useAtomValue } from "jotai";
|
FloatingFocusManager,
|
||||||
import { autoUpdate, flip, FloatingFocusManager, FloatingPortal, size, useDismiss, useFloating, useInteractions, useListNavigation, useRole } from "@floating-ui/react";
|
FloatingPortal,
|
||||||
import Fuse from "fuse.js";
|
flip,
|
||||||
import { charactersAtom, selectedTargetInventoryAtom } from "@/state/atoms";
|
size,
|
||||||
|
useDismiss,
|
||||||
|
useFloating,
|
||||||
|
useInteractions,
|
||||||
|
useListNavigation,
|
||||||
|
useRole,
|
||||||
|
} from '@floating-ui/react'
|
||||||
|
import Fuse from 'fuse.js'
|
||||||
|
import { useAtom, useAtomValue } from 'jotai'
|
||||||
|
import { forwardRef, useId, useMemo, useRef, useState } from 'react'
|
||||||
|
import { charactersAtom, selectedTargetInventoryAtom } from '@/state/atoms'
|
||||||
|
|
||||||
interface AccountInventorySelectorItemProps {
|
interface AccountInventorySelectorItemProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode
|
||||||
active: boolean;
|
active: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const AccountInventorySelectorItem = forwardRef<
|
const AccountInventorySelectorItem = forwardRef<
|
||||||
HTMLDivElement,
|
HTMLDivElement,
|
||||||
AccountInventorySelectorItemProps & React.HTMLProps<HTMLDivElement>
|
AccountInventorySelectorItemProps & React.HTMLProps<HTMLDivElement>
|
||||||
>(({ children, active, ...rest }, ref) => {
|
>(({ children, active, ...rest }, ref) => {
|
||||||
const id = useId();
|
const id = useId()
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
@ -25,22 +33,22 @@ const AccountInventorySelectorItem = forwardRef<
|
|||||||
aria-selected={active}
|
aria-selected={active}
|
||||||
{...rest}
|
{...rest}
|
||||||
style={{
|
style={{
|
||||||
background: active ? "lightblue" : "none",
|
background: active ? 'lightblue' : 'none',
|
||||||
padding: 4,
|
padding: 4,
|
||||||
cursor: "default",
|
cursor: 'default',
|
||||||
...rest.style,
|
...rest.style,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
);
|
)
|
||||||
});
|
})
|
||||||
export const InventoryTargetSelector = () => {
|
export const InventoryTargetSelector = () => {
|
||||||
const [open, setOpen] = useState(false);
|
const [open, setOpen] = useState(false)
|
||||||
const [inputValue, setInputValue] = useState("");
|
const [inputValue, setInputValue] = useState('')
|
||||||
const [activeIndex, setActiveIndex] = useState<number | null>(null);
|
const [activeIndex, setActiveIndex] = useState<number | null>(null)
|
||||||
|
|
||||||
const listRef = useRef<Array<HTMLElement | null>>([]);
|
const listRef = useRef<Array<HTMLElement | null>>([])
|
||||||
|
|
||||||
const { refs, floatingStyles, context } = useFloating<HTMLInputElement>({
|
const { refs, floatingStyles, context } = useFloating<HTMLInputElement>({
|
||||||
whileElementsMounted: autoUpdate,
|
whileElementsMounted: autoUpdate,
|
||||||
@ -53,37 +61,39 @@ export const InventoryTargetSelector = () => {
|
|||||||
Object.assign(elements.floating.style, {
|
Object.assign(elements.floating.style, {
|
||||||
width: `${rects.reference.width}px`,
|
width: `${rects.reference.width}px`,
|
||||||
maxHeight: `${availableHeight}px`,
|
maxHeight: `${availableHeight}px`,
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
padding: 10,
|
padding: 10,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
});
|
})
|
||||||
|
|
||||||
const role = useRole(context, { role: "listbox" });
|
const role = useRole(context, { role: 'listbox' })
|
||||||
const dismiss = useDismiss(context);
|
const dismiss = useDismiss(context)
|
||||||
const listNav = useListNavigation(context, {
|
const listNav = useListNavigation(context, {
|
||||||
listRef,
|
listRef,
|
||||||
activeIndex,
|
activeIndex,
|
||||||
onNavigate: setActiveIndex,
|
onNavigate: setActiveIndex,
|
||||||
virtual: true,
|
virtual: true,
|
||||||
loop: true,
|
loop: true,
|
||||||
});
|
})
|
||||||
|
|
||||||
const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions(
|
const { getReferenceProps, getFloatingProps, getItemProps } = useInteractions([
|
||||||
[role, dismiss, listNav]
|
role,
|
||||||
);
|
dismiss,
|
||||||
|
listNav,
|
||||||
|
])
|
||||||
|
|
||||||
function onChange(event: React.ChangeEvent<HTMLInputElement>) {
|
function onChange(event: React.ChangeEvent<HTMLInputElement>) {
|
||||||
const value = event.target.value;
|
const value = event.target.value
|
||||||
setInputValue(value);
|
setInputValue(value)
|
||||||
setSelectedTargetInventory(undefined)
|
setSelectedTargetInventory(undefined)
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
setOpen(true);
|
setOpen(true)
|
||||||
setActiveIndex(0);
|
setActiveIndex(0)
|
||||||
} else {
|
} else {
|
||||||
setOpen(false);
|
setOpen(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const { data: subaccounts } = useAtomValue(charactersAtom)
|
const { data: subaccounts } = useAtomValue(charactersAtom)
|
||||||
@ -91,18 +101,15 @@ export const InventoryTargetSelector = () => {
|
|||||||
const [selectedTargetInventory, setSelectedTargetInventory] = useAtom(selectedTargetInventoryAtom)
|
const [selectedTargetInventory, setSelectedTargetInventory] = useAtom(selectedTargetInventoryAtom)
|
||||||
|
|
||||||
const searcher = useMemo(() => {
|
const searcher = useMemo(() => {
|
||||||
return new Fuse(subaccounts?.flatMap(x=>[
|
return new Fuse(subaccounts?.flatMap(x => [x.bank, x.character]) || [], {
|
||||||
x.bank,
|
keys: ['path', 'name'],
|
||||||
x.character,
|
|
||||||
])||[], {
|
|
||||||
keys:["path","name"],
|
|
||||||
findAllMatches: true,
|
findAllMatches: true,
|
||||||
threshold: 0.8,
|
threshold: 0.8,
|
||||||
useExtendedSearch: true,
|
useExtendedSearch: true,
|
||||||
})
|
})
|
||||||
}, [subaccounts])
|
}, [subaccounts])
|
||||||
|
|
||||||
const items = searcher.search(inputValue || "!-", {limit: 10}).map(x=>x.item)
|
const items = searcher.search(inputValue || '!-', { limit: 10 }).map(x => x.item)
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<input
|
<input
|
||||||
@ -111,40 +118,32 @@ export const InventoryTargetSelector = () => {
|
|||||||
ref: refs.setReference,
|
ref: refs.setReference,
|
||||||
onChange,
|
onChange,
|
||||||
value: selectedTargetInventory !== undefined ? selectedTargetInventory.name : inputValue,
|
value: selectedTargetInventory !== undefined ? selectedTargetInventory.name : inputValue,
|
||||||
placeholder: "Target Inventory",
|
placeholder: 'Target Inventory',
|
||||||
"aria-autocomplete": "list",
|
'aria-autocomplete': 'list',
|
||||||
onFocus() {
|
onFocus() {
|
||||||
setOpen(true);
|
setOpen(true)
|
||||||
},
|
},
|
||||||
onKeyDown(event) {
|
onKeyDown(event) {
|
||||||
if (
|
if (event.key === 'Enter' && activeIndex != null && items[activeIndex]) {
|
||||||
event.key === "Enter" &&
|
|
||||||
activeIndex != null &&
|
|
||||||
items[activeIndex]
|
|
||||||
) {
|
|
||||||
setSelectedTargetInventory(items[activeIndex])
|
setSelectedTargetInventory(items[activeIndex])
|
||||||
setInputValue(items[activeIndex].name);
|
setInputValue(items[activeIndex].name)
|
||||||
setActiveIndex(null);
|
setActiveIndex(null)
|
||||||
setOpen(false);
|
setOpen(false)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
{open && (
|
{open && (
|
||||||
<FloatingPortal>
|
<FloatingPortal>
|
||||||
<FloatingFocusManager
|
<FloatingFocusManager context={context} initialFocus={-1} visuallyHiddenDismiss>
|
||||||
context={context}
|
|
||||||
initialFocus={-1}
|
|
||||||
visuallyHiddenDismiss
|
|
||||||
>
|
|
||||||
<div
|
<div
|
||||||
{...getFloatingProps({
|
{...getFloatingProps({
|
||||||
ref: refs.setFloating,
|
ref: refs.setFloating,
|
||||||
style: {
|
style: {
|
||||||
...floatingStyles,
|
...floatingStyles,
|
||||||
background: "#eee",
|
background: '#eee',
|
||||||
color: "black",
|
color: 'black',
|
||||||
overflowY: "auto",
|
overflowY: 'auto',
|
||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
@ -153,13 +152,13 @@ export const InventoryTargetSelector = () => {
|
|||||||
{...getItemProps({
|
{...getItemProps({
|
||||||
key: item.path,
|
key: item.path,
|
||||||
ref(node) {
|
ref(node) {
|
||||||
listRef.current[index] = node;
|
listRef.current[index] = node
|
||||||
},
|
},
|
||||||
onClick() {
|
onClick() {
|
||||||
setInputValue(item.name);
|
setInputValue(item.name)
|
||||||
setSelectedTargetInventory(item);
|
setSelectedTargetInventory(item)
|
||||||
setOpen(false);
|
setOpen(false)
|
||||||
refs.domReference.current?.focus();
|
refs.domReference.current?.focus()
|
||||||
},
|
},
|
||||||
})}
|
})}
|
||||||
active={activeIndex === index}
|
active={activeIndex === index}
|
||||||
@ -172,5 +171,5 @@ export const InventoryTargetSelector = () => {
|
|||||||
</FloatingPortal>
|
</FloatingPortal>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,35 +1,26 @@
|
|||||||
import { StatsColumns } from "@/lib/columns"
|
import { flexRender, getCoreRowModel, useReactTable } from '@tanstack/react-table'
|
||||||
import { ItemWithSelection } from "@/lib/table/defs"
|
import { atom, useAtomValue } from 'jotai'
|
||||||
import { InventoryColumns } from "@/lib/table/tanstack"
|
import { useMemo } from 'react'
|
||||||
import { inventoryItemsCurrentPageAtom, preferenceInventoryTab } from "@/state/atoms"
|
import { StatsColumns } from '@/lib/columns'
|
||||||
import { flexRender, getCoreRowModel, useReactTable } from "@tanstack/react-table"
|
import { ItemWithSelection } from '@/lib/table/defs'
|
||||||
import { atom, useAtom, useAtomValue } from "jotai"
|
import { InventoryColumns } from '@/lib/table/tanstack'
|
||||||
import { useMemo } from "react"
|
import { inventoryItemsCurrentPageAtom, preferenceInventoryTab } from '@/state/atoms'
|
||||||
|
|
||||||
|
const columnVisibilityAtom = atom(get => {
|
||||||
const columnVisibilityAtom = atom((get)=>{
|
|
||||||
const itemTab = get(preferenceInventoryTab)
|
const itemTab = get(preferenceInventoryTab)
|
||||||
if(!["2","4"].includes(itemTab)) {
|
if (!['2', '4'].includes(itemTab)) {
|
||||||
return Object.fromEntries([
|
return Object.fromEntries([...StatsColumns.map(x => [`stats.${x}`, false]), ['slots', false]])
|
||||||
...StatsColumns.map(x=>["stats."+x,false]),
|
|
||||||
["slots",false]
|
|
||||||
])
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
}
|
}
|
||||||
|
return {}
|
||||||
})
|
})
|
||||||
export const InventoryTable = () => {
|
export const InventoryTable = () => {
|
||||||
|
|
||||||
const items = useAtomValue(inventoryItemsCurrentPageAtom)
|
const items = useAtomValue(inventoryItemsCurrentPageAtom)
|
||||||
|
|
||||||
const columns = useMemo(() => {
|
const columns = useMemo(() => {
|
||||||
return [
|
return [...Object.values(InventoryColumns)]
|
||||||
...Object.values(InventoryColumns)
|
|
||||||
]
|
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const columnVisibility = useAtomValue(columnVisibilityAtom)
|
const columnVisibility = useAtomValue(columnVisibilityAtom)
|
||||||
console.log(columnVisibility)
|
|
||||||
|
|
||||||
const table = useReactTable<ItemWithSelection>({
|
const table = useReactTable<ItemWithSelection>({
|
||||||
getRowId: row => row.item.unique_id.toString(),
|
getRowId: row => row.item.unique_id.toString(),
|
||||||
@ -44,27 +35,20 @@ export const InventoryTable = () => {
|
|||||||
return (
|
return (
|
||||||
<div className="overflow-y-auto h-full mb-32">
|
<div className="overflow-y-auto h-full mb-32">
|
||||||
<table
|
<table
|
||||||
onContextMenu={(e)=>{
|
onContextMenu={e => {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
return
|
return
|
||||||
}}
|
}}
|
||||||
className="border-spacing-x-2 border-separate">
|
className="border-spacing-x-2 border-separate"
|
||||||
|
>
|
||||||
<thead className="sticky top-0 z-10 select-none bg-white">
|
<thead className="sticky top-0 z-10 select-none bg-white">
|
||||||
{table.getHeaderGroups().map(headerGroup => (
|
{table.getHeaderGroups().map(headerGroup => (
|
||||||
<tr
|
<tr className="" key={headerGroup.id}>
|
||||||
className=""
|
|
||||||
key={headerGroup.id}>
|
|
||||||
{headerGroup.headers.map(header => (
|
{headerGroup.headers.map(header => (
|
||||||
<th
|
<th key={header.id} className="text-left">
|
||||||
key={header.id}
|
|
||||||
className="text-left"
|
|
||||||
>
|
|
||||||
{header.isPlaceholder
|
{header.isPlaceholder
|
||||||
? null
|
? null
|
||||||
: flexRender(
|
: flexRender(header.column.columnDef.header, header.getContext())}
|
||||||
header.column.columnDef.header,
|
|
||||||
header.getContext()
|
|
||||||
)}
|
|
||||||
</th>
|
</th>
|
||||||
))}
|
))}
|
||||||
</tr>
|
</tr>
|
||||||
@ -72,14 +56,9 @@ export const InventoryTable = () => {
|
|||||||
</thead>
|
</thead>
|
||||||
<tbody className="divide-y divide-gray-200">
|
<tbody className="divide-y divide-gray-200">
|
||||||
{table.getRowModel().rows.map(row => (
|
{table.getRowModel().rows.map(row => (
|
||||||
<tr
|
<tr key={row.id} className={''}>
|
||||||
key={row.id}
|
|
||||||
className={""}
|
|
||||||
>
|
|
||||||
{row.getVisibleCells().map(cell => (
|
{row.getVisibleCells().map(cell => (
|
||||||
<td key={cell.id}>
|
<td key={cell.id}>{flexRender(cell.column.columnDef.cell, cell.getContext())}</td>
|
||||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
|
||||||
</td>
|
|
||||||
))}
|
))}
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -1,23 +1,22 @@
|
|||||||
import { useState } from "react"
|
import { useAtom } from 'jotai'
|
||||||
import useLocalStorage from "use-local-storage"
|
import { useState } from 'react'
|
||||||
import { useAtom } from "jotai"
|
import useLocalStorage from 'use-local-storage'
|
||||||
import { loginStatusAtom } from "../state/atoms"
|
import { LoginHelper } from '../lib/session'
|
||||||
import { LoginHelper } from "../lib/session"
|
import { loginStatusAtom } from '../state/atoms'
|
||||||
|
|
||||||
export const LoginWidget = () => {
|
export const LoginWidget = () => {
|
||||||
const [username, setUsername] = useLocalStorage("input_username","", {syncData: false})
|
const [username, setUsername] = useLocalStorage('input_username', '', { syncData: false })
|
||||||
const [password, setPassword] = useState("")
|
const [password, setPassword] = useState('')
|
||||||
|
|
||||||
const [{ data: loginState, refetch: refetchLoginState }] = useAtom(loginStatusAtom)
|
const [{ data: loginState, refetch: refetchLoginState }] = useAtom(loginStatusAtom)
|
||||||
|
|
||||||
const [loginError, setLoginError] = useState("")
|
const [loginError, setLoginError] = useState('')
|
||||||
|
|
||||||
if (loginState?.logged_in) {
|
if (loginState?.logged_in) {
|
||||||
return <>
|
return (
|
||||||
|
<>
|
||||||
<div className="flex flex-row justify-between px-2">
|
<div className="flex flex-row justify-between px-2">
|
||||||
<div>
|
<div>{loginState.community_name}</div>
|
||||||
{loginState.community_name}
|
|
||||||
</div>
|
|
||||||
<div className="flex flex-row gap-2">
|
<div className="flex flex-row gap-2">
|
||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@ -26,55 +25,63 @@ export const LoginWidget = () => {
|
|||||||
})
|
})
|
||||||
return
|
return
|
||||||
}}
|
}}
|
||||||
className="text-blue-400 text-xs hover:cursor-pointer hover:text-blue-600">
|
className="text-blue-400 text-xs hover:cursor-pointer hover:text-blue-600"
|
||||||
|
>
|
||||||
logout
|
logout
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</>
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return <>
|
return (
|
||||||
|
<>
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<form action={
|
<form
|
||||||
()=>{
|
action={() => {
|
||||||
LoginHelper.login(username,password).catch((e)=>{
|
LoginHelper.login(username, password)
|
||||||
|
.catch(e => {
|
||||||
setLoginError(e.message)
|
setLoginError(e.message)
|
||||||
}).finally(()=>{
|
})
|
||||||
|
.finally(() => {
|
||||||
refetchLoginState()
|
refetchLoginState()
|
||||||
refetchLoginState()
|
refetchLoginState()
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
className="flex flex-col gap-1 p-2 justify-left">
|
className="flex flex-col gap-1 p-2 justify-left"
|
||||||
{ loginError ? (<div className="text-red-500 text-xs">
|
>
|
||||||
{loginError}
|
{loginError ? <div className="text-red-500 text-xs">{loginError}</div> : null}
|
||||||
</div>) : null}
|
|
||||||
<div>
|
<div>
|
||||||
<input
|
<input
|
||||||
onChange={(e)=>{
|
onChange={e => {
|
||||||
setUsername(e.target.value)
|
setUsername(e.target.value)
|
||||||
}}
|
}}
|
||||||
value={username}
|
value={username}
|
||||||
id="username"
|
id="username"
|
||||||
placeholder="username" className="w-32 pl-2 pb-1 border-b border-gray-600 placeholder-gray-500"/>
|
placeholder="username"
|
||||||
|
className="w-32 pl-2 pb-1 border-b border-gray-600 placeholder-gray-500"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<input
|
<input
|
||||||
onChange={(e)=>{
|
onChange={e => {
|
||||||
setPassword(e.target.value)
|
setPassword(e.target.value)
|
||||||
}}
|
}}
|
||||||
value={password}
|
value={password}
|
||||||
type="password" placeholder="password" className="w-32 pl-2 pb-1 border-b border-gray-600 placeholder-gray-500"/>
|
type="password"
|
||||||
|
placeholder="password"
|
||||||
|
className="w-32 pl-2 pb-1 border-b border-gray-600 placeholder-gray-500"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
className="border-b border-gray-600 px-2 py-1 hover:text-gray-600 hover:cursor-pointer">
|
className="border-b border-gray-600 px-2 py-1 hover:text-gray-600 hover:cursor-pointer"
|
||||||
|
>
|
||||||
login
|
login
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,14 @@
|
|||||||
import { SessionContextProvider } from "./SessionContext";
|
import { SessionContextProvider } from './SessionContext'
|
||||||
|
|
||||||
interface IContext {
|
interface IContext {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode
|
||||||
}
|
}
|
||||||
|
|
||||||
function AppContext(props: IContext): any {
|
function AppContext(props: IContext): any {
|
||||||
const { children } = props;
|
const { children } = props
|
||||||
const providers = [
|
const providers = [SessionContextProvider]
|
||||||
SessionContextProvider,
|
const res = providers.reduceRight((acc, CurrVal) => <CurrVal>{acc as any}</CurrVal>, children)
|
||||||
];
|
return res as any
|
||||||
const res = providers.reduceRight(
|
|
||||||
(acc, CurrVal) => <CurrVal>{acc as any}</CurrVal>,
|
|
||||||
children,
|
|
||||||
);
|
|
||||||
return res as any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default AppContext;
|
export default AppContext
|
||||||
|
|||||||
@ -1,21 +1,22 @@
|
|||||||
import { createContext, Dispatch, SetStateAction, useContext, useState } from "react";
|
import { createContext, useContext, useState } from 'react'
|
||||||
|
|
||||||
type Setter<T> = React.Dispatch<React.SetStateAction<T | undefined>>;
|
type Setter<T> = React.Dispatch<React.SetStateAction<T | undefined>>
|
||||||
type MustSetter<T> = React.Dispatch<React.SetStateAction<T>>;
|
type MustSetter<T> = React.Dispatch<React.SetStateAction<T>>
|
||||||
import useLocalStorage from "use-local-storage";
|
|
||||||
import { OrderTracker } from "../lib/lifeto/order_manager";
|
import useLocalStorage from 'use-local-storage'
|
||||||
import { ColumnSet } from "../lib/table";
|
import { BasicColumns, ColumnInfo, ColumnName, DetailsColumns, MoveColumns } from '../lib/columns'
|
||||||
import { StoreAccounts, StoreChars, StoreColSet, StoreStr } from "../lib/storage";
|
import { OrderTracker } from '../lib/lifeto/order_manager'
|
||||||
import { BasicColumns, ColumnInfo, ColumnName, Columns, DetailsColumns, MoveColumns } from '../lib/columns'
|
import { StoreColSet } from '../lib/storage'
|
||||||
|
import { ColumnSet } from '../lib/table'
|
||||||
|
|
||||||
interface SessionContextProps {
|
interface SessionContextProps {
|
||||||
orders: OrderTracker;
|
orders: OrderTracker
|
||||||
activeTable: string;
|
activeTable: string
|
||||||
screen: string;
|
screen: string
|
||||||
columns: ColumnSet;
|
columns: ColumnSet
|
||||||
tags: ColumnSet;
|
tags: ColumnSet
|
||||||
dirty: number;
|
dirty: number
|
||||||
currentSearch: string;
|
currentSearch: string
|
||||||
|
|
||||||
setActiveTable: Setter<string>
|
setActiveTable: Setter<string>
|
||||||
setScreen: Setter<string>
|
setScreen: Setter<string>
|
||||||
@ -23,49 +24,57 @@ interface SessionContextProps {
|
|||||||
setCurrentSearch: MustSetter<string>
|
setCurrentSearch: MustSetter<string>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const _defaultColumn: (ColumnInfo | ColumnName)[] = [
|
const _defaultColumn: (ColumnInfo | ColumnName)[] = [
|
||||||
...BasicColumns,
|
...BasicColumns,
|
||||||
...MoveColumns,
|
...MoveColumns,
|
||||||
...DetailsColumns,
|
...DetailsColumns,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
const SessionContext = createContext({} as SessionContextProps)
|
||||||
const SessionContext = createContext({} as SessionContextProps);
|
|
||||||
|
|
||||||
const dotry = (x: any, d: any) => {
|
const dotry = (x: any, d: any) => {
|
||||||
try {
|
try {
|
||||||
return x()
|
return x()
|
||||||
} catch {
|
} catch {
|
||||||
return d
|
return d
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const SessionContextProvider = ({ children }: { children: any }) => {
|
export const SessionContextProvider = ({ children }: { children: any }) => {
|
||||||
const [activeTable, setActiveTable] = useLocalStorage<string>("activeTable","")
|
const [activeTable, setActiveTable] = useLocalStorage<string>('activeTable', '')
|
||||||
const [screen, setScreen] = useLocalStorage<string>("screen","")
|
const [screen, setScreen] = useLocalStorage<string>('screen', '')
|
||||||
const [columns ] = useState<ColumnSet>(new ColumnSet(_defaultColumn));
|
const [columns] = useState<ColumnSet>(new ColumnSet(_defaultColumn))
|
||||||
const [tags ] = useState<ColumnSet>(dotry(()=>StoreColSet.Revive("tags"), new ColumnSet()));
|
const [tags] = useState<ColumnSet>(dotry(() => StoreColSet.Revive('tags'), new ColumnSet()))
|
||||||
|
|
||||||
const [orders ] = useState<OrderTracker>(new OrderTracker());
|
const [orders] = useState<OrderTracker>(new OrderTracker())
|
||||||
const [dirty, setDirty] = useState<number>(0);
|
const [dirty, setDirty] = useState<number>(0)
|
||||||
const [currentSearch, setCurrentSearch] = useState<string>("");
|
const [currentSearch, setCurrentSearch] = useState<string>('')
|
||||||
return (
|
return (
|
||||||
<SessionContext.Provider value={{
|
<SessionContext.Provider
|
||||||
orders, activeTable, screen, columns, tags, dirty, currentSearch,
|
value={{
|
||||||
setActiveTable, setScreen, setDirty, setCurrentSearch,
|
orders,
|
||||||
}}>{children}</SessionContext.Provider>
|
activeTable,
|
||||||
);
|
screen,
|
||||||
};
|
columns,
|
||||||
|
tags,
|
||||||
export const useSessionContext = (): SessionContextProps => {
|
dirty,
|
||||||
const context = useContext<SessionContextProps>(SessionContext);
|
currentSearch,
|
||||||
if (context === null) {
|
setActiveTable,
|
||||||
throw new Error(
|
setScreen,
|
||||||
'"useSessionContext" should be used inside a "SessionContextProvider"',
|
setDirty,
|
||||||
);
|
setCurrentSearch,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</SessionContext.Provider>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return context;
|
export const useSessionContext = (): SessionContextProps => {
|
||||||
};
|
const context = useContext<SessionContextProps>(SessionContext)
|
||||||
|
if (context === null) {
|
||||||
|
throw new Error('"useSessionContext" should be used inside a "SessionContextProvider"')
|
||||||
|
}
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
@import 'tailwindcss';
|
@import "tailwindcss";
|
||||||
|
|
||||||
html {
|
html {
|
||||||
cursor: url(/public/cursor.png), auto !important;
|
cursor: url(/assets/cursor.png), auto !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@theme {
|
@theme {
|
||||||
--cursor-default: url(/public/cursor.png), auto !important;
|
--cursor-default: url(/assets/cursor.png), auto !important;
|
||||||
--cursor-pointer: url(/public/cursor.png), pointer !important;
|
--cursor-pointer: url(/assets/cursor.png), pointer !important;
|
||||||
--cursor-text: url(/public/cursor.png), pointer !important;
|
--cursor-text: url(/assets/cursor.png), pointer !important;
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
The default border color has changed to `currentcolor` in Tailwind CSS v4,
|
The default border color has changed to `currentcolor` in Tailwind CSS v4,
|
||||||
|
|||||||
@ -1,16 +1,16 @@
|
|||||||
import React from "react";
|
import React from 'react'
|
||||||
import ReactDOM from "react-dom/client";
|
import ReactDOM from 'react-dom/client'
|
||||||
import { App } from "./App";
|
import { App } from './App'
|
||||||
import AppContext from "./context/AppContext";
|
import AppContext from './context/AppContext'
|
||||||
|
|
||||||
|
import './lib/superjson'
|
||||||
|
import './index.css'
|
||||||
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
|
||||||
|
import { Provider } from 'jotai'
|
||||||
|
|
||||||
import "./lib/superjson";
|
|
||||||
import "./index.css";
|
|
||||||
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
||||||
import { Provider } from "jotai";
|
|
||||||
const queryClient = new QueryClient()
|
const queryClient = new QueryClient()
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById("app") as HTMLElement).render(
|
ReactDOM.createRoot(document.getElementById('app') as HTMLElement).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<Provider>
|
<Provider>
|
||||||
<QueryClientProvider client={queryClient}>
|
<QueryClientProvider client={queryClient}>
|
||||||
@ -20,4 +20,4 @@ ReactDOM.createRoot(document.getElementById("app") as HTMLElement).render(
|
|||||||
</QueryClientProvider>
|
</QueryClientProvider>
|
||||||
</Provider>
|
</Provider>
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
);
|
)
|
||||||
|
|||||||
@ -1,34 +1,33 @@
|
|||||||
import { TricksterItem } from "../trickster"
|
import { TricksterItem } from '../trickster'
|
||||||
|
|
||||||
export const BasicColumns = [
|
export const BasicColumns = ['uid', 'Image', 'Name', 'Count'] as const
|
||||||
"uid","Image","Name","Count",
|
|
||||||
] as const
|
|
||||||
|
|
||||||
export const DetailsColumns = [
|
export const DetailsColumns = ['Desc', 'Use'] as const
|
||||||
"Desc","Use",
|
|
||||||
] as const
|
|
||||||
|
|
||||||
export const MoveColumns = [
|
export const MoveColumns = ['MoveCount', 'Move'] as const
|
||||||
"MoveCount","Move",
|
|
||||||
] as const
|
|
||||||
|
|
||||||
export const TagColumns = [
|
export const TagColumns = ['All', 'Equip', 'Drill', 'Card', 'Quest', 'Consume', 'Compound'] as const
|
||||||
"All","Equip","Drill","Card","Quest","Consume", "Compound"
|
|
||||||
] as const
|
|
||||||
|
|
||||||
export const EquipmentColumns = [
|
export const EquipmentColumns = ['MinLvl', 'Slots', 'RefineNumber', 'RefineState'] as const
|
||||||
"MinLvl","Slots","RefineNumber","RefineState",
|
|
||||||
] as const
|
|
||||||
|
|
||||||
export const StatsColumns = [
|
export const StatsColumns = [
|
||||||
"HV","AC","LK","WT","HP","MA","DP","DX","MP","AP","MD","DA","GunAP"
|
'HV',
|
||||||
|
'AC',
|
||||||
|
'LK',
|
||||||
|
'WT',
|
||||||
|
'HP',
|
||||||
|
'MA',
|
||||||
|
'DP',
|
||||||
|
'DX',
|
||||||
|
'MP',
|
||||||
|
'AP',
|
||||||
|
'MD',
|
||||||
|
'DA',
|
||||||
|
'GunAP',
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
|
export const DebugColumns = []
|
||||||
export const DebugColumns = [
|
export const HackColumns = [] as const
|
||||||
]
|
|
||||||
export const HackColumns = [
|
|
||||||
] as const
|
|
||||||
|
|
||||||
export const ColumnNames = [
|
export const ColumnNames = [
|
||||||
...BasicColumns,
|
...BasicColumns,
|
||||||
@ -40,22 +39,22 @@ export const ColumnNames = [
|
|||||||
...HackColumns,
|
...HackColumns,
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
export type ColumnName = typeof ColumnNames[number]
|
export type ColumnName = (typeof ColumnNames)[number]
|
||||||
|
|
||||||
const c = (a: ColumnName | ColumnInfo): ColumnName => {
|
const c = (a: ColumnName | ColumnInfo): ColumnName => {
|
||||||
switch (typeof a) {
|
switch (typeof a) {
|
||||||
case "string":
|
case 'string':
|
||||||
return a
|
return a
|
||||||
case "object":
|
case 'object':
|
||||||
return a.name
|
return a.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const LazyColumn = c;
|
export const LazyColumn = c
|
||||||
|
|
||||||
export const ColumnSorter = (a: ColumnName | ColumnInfo, b: ColumnName | ColumnInfo): number => {
|
export const ColumnSorter = (a: ColumnName | ColumnInfo, b: ColumnName | ColumnInfo): number => {
|
||||||
let n1 = ColumnNames.indexOf(c(a))
|
const n1 = ColumnNames.indexOf(c(a))
|
||||||
let n2 = ColumnNames.indexOf(c(b))
|
const n2 = ColumnNames.indexOf(c(b))
|
||||||
if(n1 == n2) {
|
if (n1 === n2) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return n1 > n2 ? 1 : -1
|
return n1 > n2 ? 1 : -1
|
||||||
@ -69,6 +68,5 @@ export interface ColumnInfo {
|
|||||||
renderer?: any
|
renderer?: any
|
||||||
filtering?: boolean
|
filtering?: boolean
|
||||||
writable?: boolean
|
writable?: boolean
|
||||||
getter(item:TricksterItem):(string | number)
|
getter(item: TricksterItem): string | number
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import Handsontable from "handsontable"
|
import Handsontable from 'handsontable'
|
||||||
import Core from "handsontable/core"
|
import Core from 'handsontable/core'
|
||||||
import { textRenderer } from "handsontable/renderers"
|
import { textRenderer } from 'handsontable/renderers'
|
||||||
import numbro from "numbro"
|
import numbro from 'numbro'
|
||||||
import { TricksterItem } from "../trickster"
|
import { TricksterItem } from '../trickster'
|
||||||
import {ColumnName, ColumnInfo} from "./column"
|
import { ColumnInfo, ColumnName } from './column'
|
||||||
|
|
||||||
export const ColumnByNames = (...n: ColumnName[]) => {
|
export const ColumnByNames = (...n: ColumnName[]) => {
|
||||||
return n.map(ColumnByName)
|
return n.map(ColumnByName)
|
||||||
@ -14,416 +14,464 @@ export const ColumnByName = (n:ColumnName) => {
|
|||||||
|
|
||||||
class Image implements ColumnInfo {
|
class Image implements ColumnInfo {
|
||||||
name: ColumnName = 'Image'
|
name: ColumnName = 'Image'
|
||||||
displayName = " "
|
displayName = ' '
|
||||||
renderer = coverRenderer
|
renderer = coverRenderer
|
||||||
getter(item:TricksterItem):(string|number) {
|
getter(item: TricksterItem): string | number {
|
||||||
return item.item_image ? item.item_image : ""
|
return item.item_image ? item.item_image : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function coverRenderer(instance:any, td:any, row:any, col:any, prop:any, value:any, cellProperties:any) {
|
function coverRenderer(
|
||||||
const stringifiedValue = Handsontable.helper.stringify(value);
|
_instance: any,
|
||||||
|
td: any,
|
||||||
|
_row: any,
|
||||||
|
_col: any,
|
||||||
|
_prop: any,
|
||||||
|
value: any,
|
||||||
|
_cellProperties: any,
|
||||||
|
) {
|
||||||
|
const stringifiedValue = Handsontable.helper.stringify(value)
|
||||||
if (stringifiedValue.startsWith('http')) {
|
if (stringifiedValue.startsWith('http')) {
|
||||||
const img:any = document.createElement('IMG');
|
const img: any = document.createElement('IMG')
|
||||||
img.src = value;
|
img.src = value
|
||||||
Handsontable.dom.addEvent(img, 'mousedown', event => {
|
Handsontable.dom.addEvent(img, 'mousedown', event => {
|
||||||
event!.preventDefault();
|
event?.preventDefault()
|
||||||
});
|
})
|
||||||
Handsontable.dom.empty(td);
|
Handsontable.dom.empty(td)
|
||||||
td.appendChild(img);
|
td.appendChild(img)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Name implements ColumnInfo {
|
class Name implements ColumnInfo {
|
||||||
name:ColumnName = "Name"
|
name: ColumnName = 'Name'
|
||||||
displayName = "Name"
|
displayName = 'Name'
|
||||||
filtering = true
|
filtering = true
|
||||||
renderer = nameRenderer
|
renderer = nameRenderer
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.item_name
|
return item.item_name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function nameRenderer(instance:any, td:any, row:any, col:any, prop:any, value:any, cellProperties:any) {
|
function nameRenderer(
|
||||||
const stringifiedValue = Handsontable.helper.stringify(value);
|
_instance: any,
|
||||||
let showText = stringifiedValue;
|
td: any,
|
||||||
const div= document.createElement('div');
|
_row: any,
|
||||||
|
_col: any,
|
||||||
|
_prop: any,
|
||||||
|
value: any,
|
||||||
|
_cellProperties: any,
|
||||||
|
) {
|
||||||
|
const stringifiedValue = Handsontable.helper.stringify(value)
|
||||||
|
const showText = stringifiedValue
|
||||||
|
const div = document.createElement('div')
|
||||||
div.innerHTML = showText
|
div.innerHTML = showText
|
||||||
div.title = showText
|
div.title = showText
|
||||||
div.style.maxWidth = "20ch"
|
div.style.maxWidth = '20ch'
|
||||||
div.style.textOverflow = "ellipsis"
|
div.style.textOverflow = 'ellipsis'
|
||||||
div.style.overflow= "hidden"
|
div.style.overflow = 'hidden'
|
||||||
div.style.whiteSpace= "nowrap"
|
div.style.whiteSpace = 'nowrap'
|
||||||
Handsontable.dom.addEvent(div, 'mousedown', event => {
|
Handsontable.dom.addEvent(div, 'mousedown', event => {
|
||||||
event!.preventDefault();
|
event?.preventDefault()
|
||||||
});
|
})
|
||||||
Handsontable.dom.empty(td);
|
Handsontable.dom.empty(td)
|
||||||
td.appendChild(div);
|
td.appendChild(div)
|
||||||
td.classList.add("htLeft")
|
td.classList.add('htLeft')
|
||||||
}
|
}
|
||||||
|
|
||||||
class Count implements ColumnInfo {
|
class Count implements ColumnInfo {
|
||||||
name:ColumnName = "Count"
|
name: ColumnName = 'Count'
|
||||||
displayName = "Count"
|
displayName = 'Count'
|
||||||
renderer = "numeric"
|
renderer = 'numeric'
|
||||||
filtering = true
|
filtering = true
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.item_count
|
return item.item_count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const spacer = "-----------"
|
const spacer = '-----------'
|
||||||
class Move implements ColumnInfo {
|
class Move implements ColumnInfo {
|
||||||
name:ColumnName = "Move"
|
name: ColumnName = 'Move'
|
||||||
displayName = "Target"
|
displayName = 'Target'
|
||||||
writable = true
|
writable = true
|
||||||
options = getMoveTargets
|
options = getMoveTargets
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(_item: TricksterItem): string | number {
|
||||||
return spacer
|
return spacer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getMoveTargets = (invs: string[]): string[] => {
|
const getMoveTargets = (invs: string[]): string[] => {
|
||||||
let out:string[] = [];
|
const out: string[] = []
|
||||||
out.push(spacer)
|
out.push(spacer)
|
||||||
for (const k of invs) {
|
for (const k of invs) {
|
||||||
out.push(k)
|
out.push(k)
|
||||||
}
|
}
|
||||||
out.push("")
|
out.push('')
|
||||||
out.push("")
|
out.push('')
|
||||||
out.push("TRASH")
|
out.push('TRASH')
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
class MoveCount implements ColumnInfo {
|
class MoveCount implements ColumnInfo {
|
||||||
name:ColumnName = "MoveCount"
|
name: ColumnName = 'MoveCount'
|
||||||
displayName = "Move #"
|
displayName = 'Move #'
|
||||||
renderer = moveCountRenderer
|
renderer = moveCountRenderer
|
||||||
writable = true
|
writable = true
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(_item: TricksterItem): string | number {
|
||||||
return ""
|
return ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveCountRenderer(instance:Core, td:any, row:number, col:number, prop:any, value:any, cellProperties:any) {
|
function moveCountRenderer(
|
||||||
let newValue = value;
|
instance: Core,
|
||||||
|
td: any,
|
||||||
|
row: number,
|
||||||
|
col: number,
|
||||||
|
prop: any,
|
||||||
|
value: any,
|
||||||
|
cellProperties: any,
|
||||||
|
) {
|
||||||
|
let newValue = value
|
||||||
|
|
||||||
if (Handsontable.helper.isNumeric(newValue)) {
|
if (Handsontable.helper.isNumeric(newValue)) {
|
||||||
const numericFormat = cellProperties.numericFormat;
|
const numericFormat = cellProperties.numericFormat
|
||||||
const cellCulture = numericFormat && numericFormat.culture || '-';
|
const cellCulture = numericFormat?.culture || '-'
|
||||||
const cellFormatPattern = numericFormat && numericFormat.pattern;
|
const cellFormatPattern = numericFormat?.pattern
|
||||||
const className = cellProperties.className || '';
|
const className = cellProperties.className || ''
|
||||||
const classArr = className.length ? className.split(' ') : [];
|
const classArr = className.length ? className.split(' ') : []
|
||||||
if (typeof cellCulture !== 'undefined' && !numbro.languages()[cellCulture]) {
|
if (typeof cellCulture !== 'undefined' && !numbro.languages()[cellCulture]) {
|
||||||
const shortTag:any = cellCulture.replace('-', '');
|
const shortTag: any = cellCulture.replace('-', '')
|
||||||
const langData = (numbro as any)[shortTag];
|
const langData = (numbro as any)[shortTag]
|
||||||
|
|
||||||
if (langData) {
|
if (langData) {
|
||||||
numbro.registerLanguage(langData);
|
numbro.registerLanguage(langData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const totalCount = Number(instance.getCell(row, col - 1)?.innerHTML)
|
const totalCount = Number(instance.getCell(row, col - 1)?.innerHTML)
|
||||||
numbro.setLanguage(cellCulture);
|
numbro.setLanguage(cellCulture)
|
||||||
const num = numbro(newValue)
|
const num = numbro(newValue)
|
||||||
if (totalCount < num.value()) {
|
if (totalCount < num.value()) {
|
||||||
const newNum = numbro(totalCount)
|
const newNum = numbro(totalCount)
|
||||||
newValue = newNum.format(cellFormatPattern || '0');
|
newValue = newNum.format(cellFormatPattern || '0')
|
||||||
} else {
|
} else {
|
||||||
newValue = num.format(cellFormatPattern || '0');
|
newValue = num.format(cellFormatPattern || '0')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (classArr.indexOf('htLeft') < 0 && classArr.indexOf('htCenter') < 0 &&
|
if (
|
||||||
classArr.indexOf('htRight') < 0 && classArr.indexOf('htJustify') < 0) {
|
classArr.indexOf('htLeft') < 0 &&
|
||||||
classArr.push('htRight');
|
classArr.indexOf('htCenter') < 0 &&
|
||||||
|
classArr.indexOf('htRight') < 0 &&
|
||||||
|
classArr.indexOf('htJustify') < 0
|
||||||
|
) {
|
||||||
|
classArr.push('htRight')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (classArr.indexOf('htNumeric') < 0) {
|
if (classArr.indexOf('htNumeric') < 0) {
|
||||||
classArr.push('htNumeric');
|
classArr.push('htNumeric')
|
||||||
}
|
}
|
||||||
cellProperties.className = classArr.join(' ');
|
cellProperties.className = classArr.join(' ')
|
||||||
|
|
||||||
td.dir = 'ltr';
|
td.dir = 'ltr'
|
||||||
newValue = newValue + "x"
|
newValue = `${newValue}x`
|
||||||
} else {
|
} else {
|
||||||
newValue = ""
|
newValue = ''
|
||||||
}
|
}
|
||||||
textRenderer(instance, td, row, col, prop, newValue, cellProperties);
|
textRenderer(instance, td, row, col, prop, newValue, cellProperties)
|
||||||
}
|
}
|
||||||
|
|
||||||
class Equip implements ColumnInfo {
|
class Equip implements ColumnInfo {
|
||||||
name:ColumnName = "Equip"
|
name: ColumnName = 'Equip'
|
||||||
displayName = "equip"
|
displayName = 'equip'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.is_equip ? 1 : 0
|
return item.is_equip ? 1 : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Drill implements ColumnInfo {
|
class Drill implements ColumnInfo {
|
||||||
name:ColumnName = "Drill"
|
name: ColumnName = 'Drill'
|
||||||
displayName = "drill"
|
displayName = 'drill'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.is_drill ? 1 : 0
|
return item.is_drill ? 1 : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class All implements ColumnInfo {
|
class All implements ColumnInfo {
|
||||||
name:ColumnName = "All"
|
name: ColumnName = 'All'
|
||||||
displayName = "swap"
|
displayName = 'swap'
|
||||||
getter(_:TricksterItem):(string|number){
|
getter(_: TricksterItem): string | number {
|
||||||
return -10000
|
return -10000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class uid implements ColumnInfo {
|
class uid implements ColumnInfo {
|
||||||
name:ColumnName = "uid"
|
name: ColumnName = 'uid'
|
||||||
displayName = "id"
|
displayName = 'id'
|
||||||
renderer = invisibleRenderer
|
renderer = invisibleRenderer
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.unique_id
|
return item.unique_id
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function invisibleRenderer(instance:Core, td:any, row:number, col:number, prop:any, value:any, cellProperties:any) {
|
function invisibleRenderer(
|
||||||
Handsontable.dom.empty(td);
|
_instance: Core,
|
||||||
|
td: any,
|
||||||
|
_row: number,
|
||||||
|
_col: number,
|
||||||
|
_prop: any,
|
||||||
|
_value: any,
|
||||||
|
_cellProperties: any,
|
||||||
|
) {
|
||||||
|
Handsontable.dom.empty(td)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Card implements ColumnInfo {
|
class Card implements ColumnInfo {
|
||||||
name:ColumnName = "Card"
|
name: ColumnName = 'Card'
|
||||||
displayName = "card"
|
displayName = 'card'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return cardFilter(item) ? 1 : 0
|
return cardFilter(item) ? 1 : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const cardFilter = (item: TricksterItem): boolean => {
|
const cardFilter = (item: TricksterItem): boolean => {
|
||||||
return (item.item_name.endsWith(" Card") || item.item_name.startsWith("Star Card"))
|
return item.item_name.endsWith(' Card') || item.item_name.startsWith('Star Card')
|
||||||
}
|
}
|
||||||
class Compound implements ColumnInfo {
|
class Compound implements ColumnInfo {
|
||||||
name:ColumnName = "Compound"
|
name: ColumnName = 'Compound'
|
||||||
displayName = "comp"
|
displayName = 'comp'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return compFilter(item) ? 1 : 0
|
return compFilter(item) ? 1 : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const compFilter = (item: TricksterItem): boolean => {
|
const compFilter = (item: TricksterItem): boolean => {
|
||||||
return (item.item_comment.toLowerCase().includes("compound item"))
|
return item.item_comment.toLowerCase().includes('compound item')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Quest implements ColumnInfo {
|
class Quest implements ColumnInfo {
|
||||||
name:ColumnName = "Quest"
|
name: ColumnName = 'Quest'
|
||||||
displayName = "quest"
|
displayName = 'quest'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return questFilter(item) ? 1 : 0
|
return questFilter(item) ? 1 : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const questFilter= (item:TricksterItem): boolean => {
|
const questFilter = (_item: TricksterItem): boolean => {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
class Consume implements ColumnInfo {
|
class Consume implements ColumnInfo {
|
||||||
name:ColumnName = "Consume"
|
name: ColumnName = 'Consume'
|
||||||
displayName = "eat"
|
displayName = 'eat'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return consumeFilter(item) ? 1 : 0
|
return consumeFilter(item) ? 1 : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const consumeFilter = (item: TricksterItem): boolean => {
|
const consumeFilter = (item: TricksterItem): boolean => {
|
||||||
const tl = item.item_use.toLowerCase()
|
const tl = item.item_use.toLowerCase()
|
||||||
return tl.includes("recover") || tl.includes("restores")
|
return tl.includes('recover') || tl.includes('restores')
|
||||||
}
|
}
|
||||||
|
|
||||||
class AP implements ColumnInfo {
|
class AP implements ColumnInfo {
|
||||||
name:ColumnName = "AP"
|
name: ColumnName = 'AP'
|
||||||
displayName = "AP"
|
displayName = 'AP'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["AP"] : ""
|
return item.stats ? item.stats.AP : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GunAP implements ColumnInfo {
|
class GunAP implements ColumnInfo {
|
||||||
name:ColumnName = "GunAP"
|
name: ColumnName = 'GunAP'
|
||||||
displayName = "Gun AP"
|
displayName = 'Gun AP'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["Gun AP"] : ""
|
return item.stats ? item.stats['Gun AP'] : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AC implements ColumnInfo {
|
class AC implements ColumnInfo {
|
||||||
name:ColumnName = "AC"
|
name: ColumnName = 'AC'
|
||||||
displayName = "AC"
|
displayName = 'AC'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["AC"] : ""
|
return item.stats ? item.stats.AC : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DX implements ColumnInfo {
|
class DX implements ColumnInfo {
|
||||||
name:ColumnName = "DX"
|
name: ColumnName = 'DX'
|
||||||
displayName = "DX"
|
displayName = 'DX'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["DX"] : ""
|
return item.stats ? item.stats.DX : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MP implements ColumnInfo {
|
class MP implements ColumnInfo {
|
||||||
name:ColumnName = "MP"
|
name: ColumnName = 'MP'
|
||||||
displayName = "MP"
|
displayName = 'MP'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["MP"] : ""
|
return item.stats ? item.stats.MP : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MA implements ColumnInfo {
|
class MA implements ColumnInfo {
|
||||||
name:ColumnName = "MA"
|
name: ColumnName = 'MA'
|
||||||
displayName = "MA"
|
displayName = 'MA'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["MA"] : ""
|
return item.stats ? item.stats.MA : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MD implements ColumnInfo {
|
class MD implements ColumnInfo {
|
||||||
name:ColumnName = "MD"
|
name: ColumnName = 'MD'
|
||||||
displayName = "MD"
|
displayName = 'MD'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["MD"] : ""
|
return item.stats ? item.stats.MD : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class WT implements ColumnInfo {
|
class WT implements ColumnInfo {
|
||||||
name:ColumnName = "WT"
|
name: ColumnName = 'WT'
|
||||||
displayName = "WT"
|
displayName = 'WT'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["WT"] : ""
|
return item.stats ? item.stats.WT : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DA implements ColumnInfo {
|
class DA implements ColumnInfo {
|
||||||
name:ColumnName = "DA"
|
name: ColumnName = 'DA'
|
||||||
displayName = "DA"
|
displayName = 'DA'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["DA"] : ""
|
return item.stats ? item.stats.DA : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LK implements ColumnInfo {
|
class LK implements ColumnInfo {
|
||||||
name:ColumnName = "LK"
|
name: ColumnName = 'LK'
|
||||||
displayName = "LK"
|
displayName = 'LK'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["LK"] : ""
|
return item.stats ? item.stats.LK : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HP implements ColumnInfo {
|
class HP implements ColumnInfo {
|
||||||
name:ColumnName = "HP"
|
name: ColumnName = 'HP'
|
||||||
displayName = "HP"
|
displayName = 'HP'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["HP"] : ""
|
return item.stats ? item.stats.HP : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DP implements ColumnInfo {
|
class DP implements ColumnInfo {
|
||||||
name:ColumnName = "DP"
|
name: ColumnName = 'DP'
|
||||||
displayName = "DP"
|
displayName = 'DP'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["DP"] : ""
|
return item.stats ? item.stats.DP : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class HV implements ColumnInfo {
|
class HV implements ColumnInfo {
|
||||||
name:ColumnName = "HV"
|
name: ColumnName = 'HV'
|
||||||
displayName = "HV"
|
displayName = 'HV'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["HV"] : ""
|
return item.stats ? item.stats.HV : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MinLvl implements ColumnInfo {
|
class MinLvl implements ColumnInfo {
|
||||||
name:ColumnName = "MinLvl"
|
name: ColumnName = 'MinLvl'
|
||||||
displayName = "lvl"
|
displayName = 'lvl'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
//TODO:
|
//TODO:
|
||||||
return item.item_min_level? item.item_min_level:""
|
return item.item_min_level ? item.item_min_level : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Slots implements ColumnInfo {
|
class Slots implements ColumnInfo {
|
||||||
name:ColumnName = "Slots"
|
name: ColumnName = 'Slots'
|
||||||
displayName = "slots"
|
displayName = 'slots'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
//TODO:
|
//TODO:
|
||||||
return item.item_slots ? item.item_slots : ""
|
return item.item_slots ? item.item_slots : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RefineNumber implements ColumnInfo {
|
class RefineNumber implements ColumnInfo {
|
||||||
name:ColumnName = "RefineNumber"
|
name: ColumnName = 'RefineNumber'
|
||||||
displayName = "refine"
|
displayName = 'refine'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.refine_level ? item.refine_level : 0
|
return item.refine_level ? item.refine_level : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RefineState implements ColumnInfo {
|
class RefineState implements ColumnInfo {
|
||||||
name:ColumnName = "RefineState"
|
name: ColumnName = 'RefineState'
|
||||||
displayName = "bork"
|
displayName = 'bork'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.refine_state ? item.refine_state : 0
|
return item.refine_state ? item.refine_state : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Desc implements ColumnInfo {
|
class Desc implements ColumnInfo {
|
||||||
name:ColumnName = "Desc"
|
name: ColumnName = 'Desc'
|
||||||
displayName = "desc"
|
displayName = 'desc'
|
||||||
renderer = descRenderer
|
renderer = descRenderer
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.item_comment
|
return item.item_comment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function descRenderer(instance:any, td:any, row:any, col:any, prop:any, value:any, cellProperties:any) {
|
function descRenderer(
|
||||||
const stringifiedValue = Handsontable.helper.stringify(value);
|
_instance: any,
|
||||||
let showText = stringifiedValue;
|
td: any,
|
||||||
const div= document.createElement('div');
|
_row: any,
|
||||||
|
_col: any,
|
||||||
|
_prop: any,
|
||||||
|
value: any,
|
||||||
|
_cellProperties: any,
|
||||||
|
) {
|
||||||
|
const stringifiedValue = Handsontable.helper.stringify(value)
|
||||||
|
const showText = stringifiedValue
|
||||||
|
const div = document.createElement('div')
|
||||||
div.innerHTML = showText
|
div.innerHTML = showText
|
||||||
div.title = showText
|
div.title = showText
|
||||||
div.style.maxWidth = "30ch"
|
div.style.maxWidth = '30ch'
|
||||||
div.style.textOverflow = "ellipsis"
|
div.style.textOverflow = 'ellipsis'
|
||||||
div.style.overflow= "hidden"
|
div.style.overflow = 'hidden'
|
||||||
div.style.whiteSpace= "nowrap"
|
div.style.whiteSpace = 'nowrap'
|
||||||
Handsontable.dom.addEvent(div, 'mousedown', event => {
|
Handsontable.dom.addEvent(div, 'mousedown', event => {
|
||||||
event!.preventDefault();
|
event?.preventDefault()
|
||||||
});
|
})
|
||||||
Handsontable.dom.empty(td);
|
Handsontable.dom.empty(td)
|
||||||
td.appendChild(div);
|
td.appendChild(div)
|
||||||
td.classList.add("htLeft")
|
td.classList.add('htLeft')
|
||||||
}
|
}
|
||||||
|
|
||||||
class Use implements ColumnInfo {
|
class Use implements ColumnInfo {
|
||||||
name:ColumnName = "Use"
|
name: ColumnName = 'Use'
|
||||||
displayName = "use"
|
displayName = 'use'
|
||||||
renderer= useRenderer;
|
renderer = useRenderer
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.item_use
|
return item.item_use
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function useRenderer(instance:any, td:any, row:any, col:any, prop:any, value:any, cellProperties:any) {
|
function useRenderer(
|
||||||
const stringifiedValue = Handsontable.helper.stringify(value);
|
_instance: any,
|
||||||
let showText = stringifiedValue;
|
td: any,
|
||||||
const div= document.createElement('div');
|
_row: any,
|
||||||
|
_col: any,
|
||||||
|
_prop: any,
|
||||||
|
value: any,
|
||||||
|
_cellProperties: any,
|
||||||
|
) {
|
||||||
|
const stringifiedValue = Handsontable.helper.stringify(value)
|
||||||
|
const showText = stringifiedValue
|
||||||
|
const div = document.createElement('div')
|
||||||
div.title = showText
|
div.title = showText
|
||||||
div.innerHTML = showText
|
div.innerHTML = showText
|
||||||
div.style.maxWidth = "30ch"
|
div.style.maxWidth = '30ch'
|
||||||
div.style.textOverflow = "ellipsis"
|
div.style.textOverflow = 'ellipsis'
|
||||||
div.style.overflow= "hidden"
|
div.style.overflow = 'hidden'
|
||||||
div.style.whiteSpace= "nowrap"
|
div.style.whiteSpace = 'nowrap'
|
||||||
Handsontable.dom.addEvent(div, 'mousedown', event => {
|
Handsontable.dom.addEvent(div, 'mousedown', event => {
|
||||||
event!.preventDefault();
|
event?.preventDefault()
|
||||||
});
|
})
|
||||||
Handsontable.dom.empty(td);
|
Handsontable.dom.empty(td)
|
||||||
td.appendChild(div);
|
td.appendChild(div)
|
||||||
td.classList.add("htLeft")
|
td.classList.add('htLeft')
|
||||||
}
|
}
|
||||||
|
|
||||||
export const Columns: { [Property in ColumnName]: ColumnInfo } = {
|
export const Columns: { [Property in ColumnName]: ColumnInfo } = {
|
||||||
@ -460,5 +508,3 @@ export const Columns:{[Property in ColumnName]:ColumnInfo}= {
|
|||||||
Compound: new Compound(),
|
Compound: new Compound(),
|
||||||
uid: new uid(),
|
uid: new uid(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,2 @@
|
|||||||
export * from "./column"
|
export * from './column'
|
||||||
export * from "./column_impl"
|
export * from './column_impl'
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,13 @@
|
|||||||
import { TricksterAccount, TricksterInventory } from "../trickster"
|
import { TricksterAccount, TricksterInventory } from '../trickster'
|
||||||
|
|
||||||
export const BankEndpoints = ["internal-xfer-item", "bank-item", "sell-item","buy-from-order","cancel-order"] as const
|
export const BankEndpoints = [
|
||||||
export type BankEndpoint = typeof BankEndpoints[number]
|
'internal-xfer-item',
|
||||||
|
'bank-item',
|
||||||
|
'sell-item',
|
||||||
|
'buy-from-order',
|
||||||
|
'cancel-order',
|
||||||
|
] as const
|
||||||
|
export type BankEndpoint = (typeof BankEndpoints)[number]
|
||||||
|
|
||||||
export interface LTOApi {
|
export interface LTOApi {
|
||||||
GetInventory: (path: string) => Promise<TricksterInventory>
|
GetInventory: (path: string) => Promise<TricksterInventory>
|
||||||
|
|||||||
@ -1,3 +1,3 @@
|
|||||||
export * from "./lifeto"
|
export * from './api'
|
||||||
export * from "./api"
|
export * from './lifeto'
|
||||||
export * from "./stateful"
|
export * from './stateful'
|
||||||
|
|||||||
@ -1,25 +1,25 @@
|
|||||||
import { Axios, AxiosResponse, Method } from "axios"
|
import { AxiosResponse, Method } from 'axios'
|
||||||
import log from "loglevel"
|
import log from 'loglevel'
|
||||||
import { bank_endpoint, EndpointCreator, market_endpoint, Session } from "../session"
|
import { bank_endpoint, EndpointCreator, market_endpoint, Session } from '../session'
|
||||||
import { TricksterAccount, TricksterAccountInfo, TricksterInventory, TricksterItem} from "../trickster"
|
import { TricksterAccount, TricksterInventory, TricksterItem } from '../trickster'
|
||||||
import { BankEndpoint, LTOApi } from "./api"
|
import { BankEndpoint, LTOApi } from './api'
|
||||||
|
|
||||||
export const pathIsBank = (path: string): boolean => {
|
export const pathIsBank = (path: string): boolean => {
|
||||||
if(path.includes("/")) {
|
if (path.includes('/')) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
export const splitPath = (path: string): [string, string] => {
|
export const splitPath = (path: string): [string, string] => {
|
||||||
const spl = path.split("/")
|
const spl = path.split('/')
|
||||||
switch (spl.length) {
|
switch (spl.length) {
|
||||||
case 1:
|
case 1:
|
||||||
return [spl[0], ""]
|
return [spl[0], '']
|
||||||
case 2:
|
case 2:
|
||||||
return [spl[0], spl[1]]
|
return [spl[0], spl[1]]
|
||||||
}
|
}
|
||||||
return ["",""]
|
return ['', '']
|
||||||
}
|
}
|
||||||
export class LTOApiv0 implements LTOApi {
|
export class LTOApiv0 implements LTOApi {
|
||||||
s: Session
|
s: Session
|
||||||
@ -28,88 +28,104 @@ export class LTOApiv0 implements LTOApi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BankAction = async <T, D>(e: BankEndpoint, t: T): Promise<D> => {
|
BankAction = async <T, D>(e: BankEndpoint, t: T): Promise<D> => {
|
||||||
let VERB:Method | "POSTFORM" = "POST"
|
let VERB: Method | 'POSTFORM' = 'POST'
|
||||||
let endpoint: EndpointCreator = bank_endpoint
|
let endpoint: EndpointCreator = bank_endpoint
|
||||||
switch (e) {
|
switch (e) {
|
||||||
case "buy-from-order":
|
case 'buy-from-order':
|
||||||
case "cancel-order":
|
case 'cancel-order':
|
||||||
endpoint = market_endpoint
|
endpoint = market_endpoint
|
||||||
case "sell-item":
|
case 'sell-item':
|
||||||
VERB = "POSTFORM"
|
VERB = 'POSTFORM'
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
return this.s.request(VERB as any,e,t,endpoint).then((x)=>{
|
return this.s.request(VERB as any, e, t, endpoint).then(x => {
|
||||||
return x.data
|
return x.data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
GetInventory = async (char_path: string): Promise<TricksterInventory> => {
|
GetInventory = async (char_path: string): Promise<TricksterInventory> => {
|
||||||
if(char_path.startsWith(":")) {
|
if (char_path.startsWith(':')) {
|
||||||
char_path = char_path.replace(":","")
|
char_path = char_path.replace(':', '')
|
||||||
}
|
}
|
||||||
let type = char_path.includes("/") ? "char" : "account"
|
const type = char_path.includes('/') ? 'char' : 'account'
|
||||||
return this.s.request("GET", `v3/item-manager/items/${type}/${char_path}`,undefined).then((ans:AxiosResponse)=>{
|
return this.s
|
||||||
|
.request('GET', `v3/item-manager/items/${type}/${char_path}`, undefined)
|
||||||
|
.then((ans: AxiosResponse) => {
|
||||||
const o = ans.data
|
const o = ans.data
|
||||||
log.debug("GetInventory", o)
|
log.debug('GetInventory', o)
|
||||||
let name = "bank"
|
let name = 'bank'
|
||||||
let id = 0
|
let id = 0
|
||||||
let galders = 0
|
let galders = 0
|
||||||
if (pathIsBank(char_path)) {
|
if (pathIsBank(char_path)) {
|
||||||
let [char, val] = Object.entries(o.characters)[0] as [string,any]
|
const [char, val] = Object.entries(o.characters)[0] as [string, any]
|
||||||
name = val.name
|
name = val.name
|
||||||
id = Number(char)
|
id = Number(char)
|
||||||
galders = 0
|
galders = 0
|
||||||
} else {
|
} else {
|
||||||
let [char, val] = Object.entries(o.characters)[0] as [string,any]
|
const [char, val] = Object.entries(o.characters)[0] as [string, any]
|
||||||
name = val.name
|
name = val.name
|
||||||
id = Number(char)
|
id = Number(char)
|
||||||
galders = val.galders
|
galders = val.galders
|
||||||
}
|
}
|
||||||
let out:TricksterInventory = {
|
const out: TricksterInventory = {
|
||||||
account_name: o.account.account_gid,
|
account_name: o.account.account_gid,
|
||||||
account_id: o.account.account_code,
|
account_id: o.account.account_code,
|
||||||
name,
|
name,
|
||||||
id,
|
id,
|
||||||
path: char_path,
|
path: char_path,
|
||||||
galders,
|
galders,
|
||||||
items: new Map((Object.entries(o.items) as any).map(([k, v]: [string, TricksterItem]):[string, TricksterItem]=>{
|
items: new Map(
|
||||||
|
(Object.entries(o.items) as any).map(
|
||||||
|
([k, v]: [string, TricksterItem]): [string, TricksterItem] => {
|
||||||
v.unique_id = Number(k)
|
v.unique_id = Number(k)
|
||||||
v.id = k
|
v.id = k
|
||||||
return [k, v]
|
return [k, v]
|
||||||
})),
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
GetAccounts = async (): Promise<TricksterAccount[]> => {
|
GetAccounts = async (): Promise<TricksterAccount[]> => {
|
||||||
return this.s.request("GET", "characters/list",undefined).then((ans:AxiosResponse)=>{
|
return this.s.request('GET', 'characters/list', undefined).then((ans: AxiosResponse) => {
|
||||||
log.debug("GetAccounts", ans.data)
|
log.debug('GetAccounts', ans.data)
|
||||||
return ans.data.map((x: any): TricksterAccount => {
|
return ans.data.map((x: any): TricksterAccount => {
|
||||||
return {
|
return {
|
||||||
name: x.name,
|
name: x.name,
|
||||||
characters: [
|
characters: [
|
||||||
{account_name:x.name, id: x.id,account_id:x.id, path:x.name, name: x.name+'/bank', class:-8, base_job: -8, current_job: -8},
|
{
|
||||||
|
account_name: x.name,
|
||||||
|
id: x.id,
|
||||||
|
account_id: x.id,
|
||||||
|
path: x.name,
|
||||||
|
name: `${x.name}/bank`,
|
||||||
|
class: -8,
|
||||||
|
base_job: -8,
|
||||||
|
current_job: -8,
|
||||||
|
},
|
||||||
...Object.values(x.characters).map((z: any) => {
|
...Object.values(x.characters).map((z: any) => {
|
||||||
return {
|
return {
|
||||||
account_name: x.name,
|
account_name: x.name,
|
||||||
account_id: x.id,
|
account_id: x.id,
|
||||||
id: z.id,
|
id: z.id,
|
||||||
name: z.name,
|
name: z.name,
|
||||||
path: x.name+"/"+z.name,
|
path: `${x.name}/${z.name}`,
|
||||||
class: z.class,
|
class: z.class,
|
||||||
base_job: z.base_job,
|
base_job: z.base_job,
|
||||||
current_job: z.current_job,
|
current_job: z.current_job,
|
||||||
}
|
}
|
||||||
})],
|
}),
|
||||||
|
],
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
GetLoggedin = async (): Promise<boolean> => {
|
GetLoggedin = async (): Promise<boolean> => {
|
||||||
return this.s.request("POST", "accounts/list",undefined).then((ans:AxiosResponse)=>{
|
return this.s.request('POST', 'accounts/list', undefined).then((ans: AxiosResponse) => {
|
||||||
if(ans.status == 401) {
|
if (ans.status === 401) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if(ans.status == 200) {
|
if (ans.status === 200) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
import { LTOApi } from "./api"
|
import { debug } from 'loglevel'
|
||||||
import { v4 as uuidv4 } from 'uuid';
|
import { v4 as uuidv4 } from 'uuid'
|
||||||
import { RefStore } from "../../state/state";
|
import { RefStore } from '../../state/state'
|
||||||
import { debug } from "loglevel";
|
import { LTOApi } from './api'
|
||||||
|
|
||||||
export const TxnStates = ["PENDING","INFLIGHT","WORKING","ERROR","SUCCESS"] as const
|
export const TxnStates = ['PENDING', 'INFLIGHT', 'WORKING', 'ERROR', 'SUCCESS'] as const
|
||||||
|
|
||||||
export type TxnState = typeof TxnStates[number]
|
export type TxnState = (typeof TxnStates)[number]
|
||||||
|
|
||||||
export interface TxnDetails {
|
export interface TxnDetails {
|
||||||
item_uid: string | "galders"
|
item_uid: string | 'galders'
|
||||||
count: number
|
count: number
|
||||||
origin: string
|
origin: string
|
||||||
target: string
|
target: string
|
||||||
@ -26,17 +26,16 @@ export interface Envelope<REQ,RESP> {
|
|||||||
state: TxnState
|
state: TxnState
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export abstract class Order {
|
export abstract class Order {
|
||||||
action_id: string
|
action_id: string
|
||||||
details?: TxnDetails
|
details?: TxnDetails
|
||||||
created: Date
|
created: Date
|
||||||
state: TxnState
|
state: TxnState
|
||||||
constructor(details?: TxnDetails) {
|
constructor(details?: TxnDetails) {
|
||||||
this.state = "PENDING"
|
this.state = 'PENDING'
|
||||||
this.details = details
|
this.details = details
|
||||||
this.created = new Date()
|
this.created = new Date()
|
||||||
this.action_id = uuidv4();
|
this.action_id = uuidv4()
|
||||||
}
|
}
|
||||||
|
|
||||||
mark(t: TxnState) {
|
mark(t: TxnState) {
|
||||||
@ -74,7 +73,7 @@ export abstract class BasicOrder extends Order {
|
|||||||
return this.state
|
return this.state
|
||||||
}
|
}
|
||||||
error(): string {
|
error(): string {
|
||||||
return this.err ? this.err : ""
|
return this.err ? this.err : ''
|
||||||
}
|
}
|
||||||
parse(i: any): BasicOrder {
|
parse(i: any): BasicOrder {
|
||||||
this.stage = i.stage
|
this.stage = i.stage
|
||||||
@ -85,20 +84,27 @@ export abstract class BasicOrder extends Order {
|
|||||||
}
|
}
|
||||||
/// start user defined
|
/// start user defined
|
||||||
|
|
||||||
export const OrderTypes = ["InvalidOrder","BankItem","InternalXfer", "PrivateMarket","MarketMove", "MarketMoveToChar"]
|
export const OrderTypes = [
|
||||||
export type OrderType = typeof OrderTypes[number]
|
'InvalidOrder',
|
||||||
|
'BankItem',
|
||||||
|
'InternalXfer',
|
||||||
|
'PrivateMarket',
|
||||||
|
'MarketMove',
|
||||||
|
'MarketMoveToChar',
|
||||||
|
]
|
||||||
|
export type OrderType = (typeof OrderTypes)[number]
|
||||||
|
|
||||||
export class InvalidOrder extends Order {
|
export class InvalidOrder extends Order {
|
||||||
order_type = "InvalidOrder"
|
order_type = 'InvalidOrder'
|
||||||
|
|
||||||
msg: string
|
msg: string
|
||||||
constructor(msg: string) {
|
constructor(msg: string) {
|
||||||
super(undefined)
|
super(undefined)
|
||||||
this.msg = msg
|
this.msg = msg
|
||||||
this.mark("ERROR")
|
this.mark('ERROR')
|
||||||
}
|
}
|
||||||
status(): string {
|
status(): string {
|
||||||
return "ERROR"
|
return 'ERROR'
|
||||||
}
|
}
|
||||||
progress(): [number, number] {
|
progress(): [number, number] {
|
||||||
return [0, 0]
|
return [0, 0]
|
||||||
@ -106,7 +112,7 @@ export class InvalidOrder extends Order{
|
|||||||
error(): string {
|
error(): string {
|
||||||
return this.msg
|
return this.msg
|
||||||
}
|
}
|
||||||
async tick(r:RefStore, api:LTOApi):Promise<void> {
|
async tick(_r: RefStore, _api: LTOApi): Promise<void> {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
parse(i: any): InvalidOrder {
|
parse(i: any): InvalidOrder {
|
||||||
@ -122,7 +128,6 @@ export interface BasicResponse {
|
|||||||
message?: string
|
message?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface InternalXferRequest {
|
export interface InternalXferRequest {
|
||||||
item_uid: string
|
item_uid: string
|
||||||
qty: string
|
qty: string
|
||||||
@ -133,7 +138,7 @@ export interface InternalXferRequest {
|
|||||||
export interface InternalXferResponse extends BasicResponse {}
|
export interface InternalXferResponse extends BasicResponse {}
|
||||||
|
|
||||||
export class InternalXfer extends BasicOrder {
|
export class InternalXfer extends BasicOrder {
|
||||||
order_type = "InternalXfer"
|
order_type = 'InternalXfer'
|
||||||
|
|
||||||
originalRequest: InternalXferRequest
|
originalRequest: InternalXferRequest
|
||||||
originalResponse?: InternalXferResponse
|
originalResponse?: InternalXferResponse
|
||||||
@ -147,27 +152,33 @@ export class InternalXfer extends BasicOrder{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
async tick(r: RefStore, api: LTOApi): Promise<void> {
|
async tick(r: RefStore, api: LTOApi): Promise<void> {
|
||||||
if(this.state !== "PENDING") {
|
if (this.state !== 'PENDING') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.mark("WORKING")
|
this.mark('WORKING')
|
||||||
return api.BankAction<InternalXferRequest, InternalXferResponse>("internal-xfer-item",this.originalRequest)
|
return api
|
||||||
|
.BankAction<InternalXferRequest, InternalXferResponse>(
|
||||||
|
'internal-xfer-item',
|
||||||
|
this.originalRequest,
|
||||||
|
)
|
||||||
.then((x: InternalXferResponse) => {
|
.then((x: InternalXferResponse) => {
|
||||||
if (x.status === 'success') {
|
if (x.status === 'success') {
|
||||||
this.originalResponse = x
|
this.originalResponse = x
|
||||||
this.stage = 1
|
this.stage = 1
|
||||||
this.mark("SUCCESS")
|
this.mark('SUCCESS')
|
||||||
const origin_item = r.invs.value.get(this.details?.origin_path!)!.items[this.details?.item_uid!]!
|
const origin_item = r.invs.value.get(this.details?.origin_path!)?.items[
|
||||||
|
this.details?.item_uid!
|
||||||
|
]!
|
||||||
origin_item.item_count = origin_item.item_count - this.details?.count!
|
origin_item.item_count = origin_item.item_count - this.details?.count!
|
||||||
} else {
|
} else {
|
||||||
throw x.message
|
throw x.message
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((e)=>{
|
.catch(e => {
|
||||||
debug("InternalXfer",e)
|
debug('InternalXfer', e)
|
||||||
this.stage = 1
|
this.stage = 1
|
||||||
this.err = e
|
this.err = e
|
||||||
this.mark("ERROR")
|
this.mark('ERROR')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
parse(i: any): InternalXfer {
|
parse(i: any): InternalXfer {
|
||||||
@ -187,7 +198,7 @@ export interface BankItemRequest {
|
|||||||
export interface BankItemResponse extends BasicResponse {}
|
export interface BankItemResponse extends BasicResponse {}
|
||||||
|
|
||||||
export class BankItem extends BasicOrder {
|
export class BankItem extends BasicOrder {
|
||||||
order_type = "BankItem";
|
order_type = 'BankItem'
|
||||||
|
|
||||||
originalRequest: BankItemRequest
|
originalRequest: BankItemRequest
|
||||||
originalResponse?: BankItemResponse
|
originalResponse?: BankItemResponse
|
||||||
@ -200,27 +211,30 @@ export class BankItem extends BasicOrder{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
async tick(r: RefStore, api: LTOApi): Promise<void> {
|
async tick(r: RefStore, api: LTOApi): Promise<void> {
|
||||||
if(this.state !== "PENDING" ){
|
if (this.state !== 'PENDING') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.mark("WORKING")
|
this.mark('WORKING')
|
||||||
return api.BankAction<BankItemRequest, BankItemResponse>("bank-item",this.originalRequest)
|
return api
|
||||||
.then((x)=>{
|
.BankAction<BankItemRequest, BankItemResponse>('bank-item', this.originalRequest)
|
||||||
debug("BankItem",x)
|
.then(x => {
|
||||||
|
debug('BankItem', x)
|
||||||
if (x.status === 'success') {
|
if (x.status === 'success') {
|
||||||
this.stage = 1
|
this.stage = 1
|
||||||
this.originalResponse = x
|
this.originalResponse = x
|
||||||
this.mark("SUCCESS")
|
this.mark('SUCCESS')
|
||||||
const origin_item = r.invs.value.get(this.details?.origin_path!)!.items[this.details?.item_uid!]!
|
const origin_item = r.invs.value.get(this.details?.origin_path!)?.items[
|
||||||
|
this.details?.item_uid!
|
||||||
|
]!
|
||||||
origin_item.item_count = origin_item.item_count - this.details?.count!
|
origin_item.item_count = origin_item.item_count - this.details?.count!
|
||||||
} else {
|
} else {
|
||||||
throw x.message ? x.message : "unknown error"
|
throw x.message ? x.message : 'unknown error'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((e)=>{
|
.catch(e => {
|
||||||
this.stage = 1
|
this.stage = 1
|
||||||
this.err = e
|
this.err = e
|
||||||
this.mark("ERROR")
|
this.mark('ERROR')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -232,7 +246,6 @@ export class BankItem extends BasicOrder{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface PrivateMarketRequest {
|
export interface PrivateMarketRequest {
|
||||||
item_uid: string
|
item_uid: string
|
||||||
qty: string
|
qty: string
|
||||||
@ -245,7 +258,7 @@ export interface PrivateMarketRequest {
|
|||||||
export interface PrivateMarketResponse extends BasicResponse {}
|
export interface PrivateMarketResponse extends BasicResponse {}
|
||||||
|
|
||||||
export class PrivateMarket extends BasicOrder {
|
export class PrivateMarket extends BasicOrder {
|
||||||
order_type = "PrivateMarket";
|
order_type = 'PrivateMarket'
|
||||||
|
|
||||||
originalRequest: PrivateMarketRequest
|
originalRequest: PrivateMarketRequest
|
||||||
originalResponse?: PrivateMarketResponse
|
originalResponse?: PrivateMarketResponse
|
||||||
@ -260,37 +273,39 @@ export class PrivateMarket extends BasicOrder{
|
|||||||
qty: details.count.toString(),
|
qty: details.count.toString(),
|
||||||
account: details.origin_account,
|
account: details.origin_account,
|
||||||
private: 1,
|
private: 1,
|
||||||
currency: "0",
|
currency: '0',
|
||||||
price: 1,
|
price: 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async tick(r: RefStore, api: LTOApi): Promise<void> {
|
async tick(r: RefStore, api: LTOApi): Promise<void> {
|
||||||
if(this.state !== "PENDING" ){
|
if (this.state !== 'PENDING') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.mark("WORKING")
|
this.mark('WORKING')
|
||||||
return api.BankAction<PrivateMarketRequest, PrivateMarketResponse>("sell-item",this.originalRequest)
|
return api
|
||||||
.then((x)=>{
|
.BankAction<PrivateMarketRequest, PrivateMarketResponse>('sell-item', this.originalRequest)
|
||||||
debug("PrivateMarket",x)
|
.then(x => {
|
||||||
|
debug('PrivateMarket', x)
|
||||||
if (x.status === 'success') {
|
if (x.status === 'success') {
|
||||||
this.stage = 1
|
this.stage = 1
|
||||||
this.originalResponse = x
|
this.originalResponse = x
|
||||||
this.mark("SUCCESS")
|
this.mark('SUCCESS')
|
||||||
this.listingId = x.data["listing_id"]
|
this.listingId = x.data.listing_id
|
||||||
this.listingHash = x.data["hash"]
|
this.listingHash = x.data.hash
|
||||||
try {
|
try {
|
||||||
const origin_item = r.invs.value.get(this.details?.origin_path!)!.items[this.details?.item_uid!]!
|
const origin_item = r.invs.value.get(this.details?.origin_path!)?.items[
|
||||||
|
this.details?.item_uid!
|
||||||
|
]!
|
||||||
origin_item.item_count = origin_item.item_count - this.details?.count!
|
origin_item.item_count = origin_item.item_count - this.details?.count!
|
||||||
}catch(e){
|
} catch (_e) {}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
throw x.message ? x.message : "unknown error"
|
throw x.message ? x.message : 'unknown error'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((e)=>{
|
.catch(e => {
|
||||||
this.stage = 1
|
this.stage = 1
|
||||||
this.err = e
|
this.err = e
|
||||||
this.mark("ERROR")
|
this.mark('ERROR')
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,7 +319,6 @@ export class PrivateMarket extends BasicOrder{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export interface MarketMoveRequest {
|
export interface MarketMoveRequest {
|
||||||
listing_id?: string
|
listing_id?: string
|
||||||
qty: string
|
qty: string
|
||||||
@ -316,9 +330,8 @@ export interface MarketMoveResponse extends BasicResponse {
|
|||||||
item_uid: string
|
item_uid: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class MarketMove extends PrivateMarket {
|
export class MarketMove extends PrivateMarket {
|
||||||
order_type = "MarketMove";
|
order_type = 'MarketMove'
|
||||||
|
|
||||||
moveRequest: MarketMoveRequest
|
moveRequest: MarketMoveRequest
|
||||||
moveResponse?: MarketMoveResponse
|
moveResponse?: MarketMoveResponse
|
||||||
@ -331,51 +344,52 @@ export class MarketMove extends PrivateMarket {
|
|||||||
constructor(details: TxnDetails) {
|
constructor(details: TxnDetails) {
|
||||||
super(details)
|
super(details)
|
||||||
this.moveStage = 0
|
this.moveStage = 0
|
||||||
this.moveState = "PENDING"
|
this.moveState = 'PENDING'
|
||||||
this.newUid = ""
|
this.newUid = ''
|
||||||
this.moveRequest = {
|
this.moveRequest = {
|
||||||
qty: details.count.toString(),
|
qty: details.count.toString(),
|
||||||
account: details.target_account,
|
account: details.target_account,
|
||||||
character: (details.target_path.includes("/")) ? details.target : "0" ,
|
character: details.target_path.includes('/') ? details.target : '0',
|
||||||
listing_id: "", // not initially populated
|
listing_id: '', // not initially populated
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async tick(r: RefStore, api: LTOApi): Promise<void> {
|
async tick(r: RefStore, api: LTOApi): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await super.tick(r, api)
|
await super.tick(r, api)
|
||||||
}catch(e){
|
} catch (_e) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch (super.status()) {
|
switch (super.status()) {
|
||||||
case "SUCCESS":
|
case 'SUCCESS':
|
||||||
break;
|
break
|
||||||
case "ERROR":
|
case 'ERROR':
|
||||||
this.moveState = "ERROR"
|
this.moveState = 'ERROR'
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if(this.moveState !== "PENDING" ){
|
if (this.moveState !== 'PENDING') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.moveRequest.listing_id = `${this.listingId}-${this.listingHash}`
|
this.moveRequest.listing_id = `${this.listingId}-${this.listingHash}`
|
||||||
this.moveState = "WORKING"
|
this.moveState = 'WORKING'
|
||||||
return api.BankAction<MarketMoveRequest, MarketMoveResponse>("buy-from-order",this.moveRequest)
|
return api
|
||||||
.then((x)=>{
|
.BankAction<MarketMoveRequest, MarketMoveResponse>('buy-from-order', this.moveRequest)
|
||||||
debug("MarketMove",x)
|
.then(x => {
|
||||||
|
debug('MarketMove', x)
|
||||||
this.moveResponse = x
|
this.moveResponse = x
|
||||||
if (x.status === 'success') {
|
if (x.status === 'success') {
|
||||||
this.moveStage = 1
|
this.moveStage = 1
|
||||||
this.moveState = "SUCCESS"
|
this.moveState = 'SUCCESS'
|
||||||
this.newUid = x.item_uid
|
this.newUid = x.item_uid
|
||||||
} else {
|
} else {
|
||||||
throw x ? x : "unknown error"
|
throw x ? x : 'unknown error'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((e)=>{
|
.catch(e => {
|
||||||
this.moveStage = 1
|
this.moveStage = 1
|
||||||
this.err = e
|
this.err = e
|
||||||
this.moveState = "ERROR"
|
this.moveState = 'ERROR'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -397,7 +411,7 @@ export class MarketMove extends PrivateMarket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class MarketMoveToChar extends MarketMove {
|
export class MarketMoveToChar extends MarketMove {
|
||||||
order_type = "MarketMoveToChar";
|
order_type = 'MarketMoveToChar'
|
||||||
|
|
||||||
charRequest: InternalXferRequest
|
charRequest: InternalXferRequest
|
||||||
charResponse?: InternalXferResponse
|
charResponse?: InternalXferResponse
|
||||||
@ -408,9 +422,9 @@ export class MarketMoveToChar extends MarketMove {
|
|||||||
constructor(details: TxnDetails) {
|
constructor(details: TxnDetails) {
|
||||||
super(details)
|
super(details)
|
||||||
this.charStage = 0
|
this.charStage = 0
|
||||||
this.charState = "PENDING"
|
this.charState = 'PENDING'
|
||||||
this.charRequest = {
|
this.charRequest = {
|
||||||
item_uid: "",
|
item_uid: '',
|
||||||
qty: details.count.toString(),
|
qty: details.count.toString(),
|
||||||
new_char: details.target,
|
new_char: details.target,
|
||||||
account: details.target_account,
|
account: details.target_account,
|
||||||
@ -419,38 +433,39 @@ export class MarketMoveToChar extends MarketMove {
|
|||||||
async tick(r: RefStore, api: LTOApi): Promise<void> {
|
async tick(r: RefStore, api: LTOApi): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await super.tick(r, api)
|
await super.tick(r, api)
|
||||||
}catch(e){
|
} catch (_e) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
switch (super.status()) {
|
switch (super.status()) {
|
||||||
case "SUCCESS":
|
case 'SUCCESS':
|
||||||
break;
|
break
|
||||||
case "ERROR":
|
case 'ERROR':
|
||||||
this.charState = "ERROR"
|
this.charState = 'ERROR'
|
||||||
return
|
return
|
||||||
default:
|
default:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if(this.charState !== "PENDING" ){
|
if (this.charState !== 'PENDING') {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.charState = "WORKING"
|
this.charState = 'WORKING'
|
||||||
this.charRequest.item_uid = this.newUid
|
this.charRequest.item_uid = this.newUid
|
||||||
return api.BankAction<InternalXferRequest, InternalXferResponse>("internal-xfer-item",this.charRequest)
|
return api
|
||||||
.then((x)=>{
|
.BankAction<InternalXferRequest, InternalXferResponse>('internal-xfer-item', this.charRequest)
|
||||||
debug("MarketMoveToChar",x)
|
.then(x => {
|
||||||
|
debug('MarketMoveToChar', x)
|
||||||
this.charResponse = x
|
this.charResponse = x
|
||||||
if (x.status === 'success') {
|
if (x.status === 'success') {
|
||||||
this.charStage = 1
|
this.charStage = 1
|
||||||
this.charState = "SUCCESS"
|
this.charState = 'SUCCESS'
|
||||||
} else {
|
} else {
|
||||||
throw x ? x : "unknown error"
|
throw x ? x : 'unknown error'
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((e)=>{
|
.catch(e => {
|
||||||
this.charStage = 1
|
this.charStage = 1
|
||||||
this.err = e
|
this.err = e
|
||||||
this.charState = "ERROR"
|
this.charState = 'ERROR'
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,29 +1,35 @@
|
|||||||
import { RefStore } from "../../state/state";
|
import { RefStore } from '../../state/state'
|
||||||
import { Serializable } from "../storage";
|
import { Serializable } from '../storage'
|
||||||
import { TricksterCharacter } from "../trickster";
|
import { TricksterCharacter } from '../trickster'
|
||||||
import { LTOApi } from "./api";
|
import { LTOApi } from './api'
|
||||||
import { pathIsBank, splitPath } from "./lifeto";
|
import { pathIsBank, splitPath } from './lifeto'
|
||||||
import { BankItem, InternalXfer, InvalidOrder, MarketMove, Order,MarketMoveToChar, TxnDetails } from "./order";
|
import {
|
||||||
|
BankItem,
|
||||||
|
InternalXfer,
|
||||||
|
InvalidOrder,
|
||||||
|
MarketMove,
|
||||||
|
MarketMoveToChar,
|
||||||
|
Order,
|
||||||
|
TxnDetails,
|
||||||
|
} from './order'
|
||||||
|
|
||||||
export interface OrderDetails {
|
export interface OrderDetails {
|
||||||
item_uid: string | "galders"
|
item_uid: string | 'galders'
|
||||||
count: number
|
count: number
|
||||||
origin_path: string
|
origin_path: string
|
||||||
target_path: string
|
target_path: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const notSupported = new InvalidOrder("not supported yet")
|
const notSupported = new InvalidOrder('not supported yet')
|
||||||
const notFound = new InvalidOrder("character not found")
|
const notFound = new InvalidOrder('character not found')
|
||||||
|
|
||||||
export class OrderTracker implements Serializable<OrderTracker> {
|
export class OrderTracker implements Serializable<OrderTracker> {
|
||||||
orders: { [key: string]: Order } = {}
|
orders: { [key: string]: Order } = {}
|
||||||
|
|
||||||
async tick(r: RefStore, api: LTOApi): Promise<any> {
|
async tick(r: RefStore, api: LTOApi): Promise<any> {
|
||||||
let hasDirty = false
|
let hasDirty = false
|
||||||
console.log("ticking")
|
|
||||||
for (const [id, order] of Object.entries(this.orders)) {
|
for (const [id, order] of Object.entries(this.orders)) {
|
||||||
if(order.status() == "SUCCESS" || order.status() == "ERROR") {
|
if (order.status() === 'SUCCESS' || order.status() === 'ERROR') {
|
||||||
console.log("finished order", order)
|
|
||||||
hasDirty = true
|
hasDirty = true
|
||||||
delete this.orders[id]
|
delete this.orders[id]
|
||||||
}
|
}
|
||||||
@ -36,36 +42,35 @@ export class OrderTracker implements Serializable<OrderTracker> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
parse(s: any): OrderTracker {
|
parse(s: any): OrderTracker {
|
||||||
if(s == undefined) {
|
if (s === undefined) {
|
||||||
return new OrderTracker()
|
return new OrderTracker()
|
||||||
}
|
}
|
||||||
if(s.orders == undefined) {
|
if (s.orders === undefined) {
|
||||||
return new OrderTracker()
|
return new OrderTracker()
|
||||||
}
|
}
|
||||||
this.orders = {}
|
this.orders = {}
|
||||||
const raw: Order[] = Object.values(s.orders)
|
const raw: Order[] = Object.values(s.orders)
|
||||||
for (const o of raw) {
|
for (const o of raw) {
|
||||||
let newOrder:Order | undefined = undefined
|
let newOrder: Order | undefined
|
||||||
console.log("loading", o)
|
|
||||||
if (o.details) {
|
if (o.details) {
|
||||||
if(o.status() == "SUCCESS" || o.status() == "ERROR") {
|
if (o.status() === 'SUCCESS' || o.status() === 'ERROR') {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
switch (o.order_type) {
|
switch (o.order_type) {
|
||||||
case "InternalXfer":
|
case 'InternalXfer':
|
||||||
newOrder = new InternalXfer(o.details).parse(o)
|
newOrder = new InternalXfer(o.details).parse(o)
|
||||||
break;
|
break
|
||||||
case "BankItem":
|
case 'BankItem':
|
||||||
newOrder = new BankItem(o.details).parse(o)
|
newOrder = new BankItem(o.details).parse(o)
|
||||||
break;
|
break
|
||||||
case "MarketMove":
|
case 'MarketMove':
|
||||||
newOrder = new MarketMove(o.details).parse(o)
|
newOrder = new MarketMove(o.details).parse(o)
|
||||||
case "MarketMoveToChar":
|
case 'MarketMoveToChar':
|
||||||
newOrder = new MarketMoveToChar(o.details).parse(o)
|
newOrder = new MarketMoveToChar(o.details).parse(o)
|
||||||
break;
|
break
|
||||||
case "InvalidOrder":
|
case 'InvalidOrder':
|
||||||
newOrder = new InvalidOrder("").parse(o)
|
newOrder = new InvalidOrder('').parse(o)
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
if (newOrder) {
|
if (newOrder) {
|
||||||
this.orders[newOrder.action_id] = newOrder
|
this.orders[newOrder.action_id] = newOrder
|
||||||
@ -80,8 +85,7 @@ export class OrderSender {
|
|||||||
constructor(
|
constructor(
|
||||||
private orders: OrderTracker,
|
private orders: OrderTracker,
|
||||||
private chars: Map<string, TricksterCharacter>,
|
private chars: Map<string, TricksterCharacter>,
|
||||||
) {
|
) {}
|
||||||
}
|
|
||||||
|
|
||||||
send(o: OrderDetails): Order {
|
send(o: OrderDetails): Order {
|
||||||
const formed = this.form(o)
|
const formed = this.form(o)
|
||||||
@ -123,7 +127,7 @@ export class OrderSender {
|
|||||||
if (!(origin && target)) {
|
if (!(origin && target)) {
|
||||||
return notFound
|
return notFound
|
||||||
}
|
}
|
||||||
const [account, name] = splitPath(target.path)
|
const [_account, _name] = splitPath(target.path)
|
||||||
/*if(account != origin.path) {
|
/*if(account != origin.path) {
|
||||||
return new MarketMoveToChar(this.transformInternalOrder(o))
|
return new MarketMoveToChar(this.transformInternalOrder(o))
|
||||||
}*/
|
}*/
|
||||||
@ -135,7 +139,7 @@ export class OrderSender {
|
|||||||
if (!(origin && target)) {
|
if (!(origin && target)) {
|
||||||
return notFound
|
return notFound
|
||||||
}
|
}
|
||||||
const [account, name] = splitPath(origin.path)
|
const [_account, _name] = splitPath(origin.path)
|
||||||
/*if(account != target.path) {
|
/*if(account != target.path) {
|
||||||
return new MarketMove(this.transformInternalOrder(o))
|
return new MarketMove(this.transformInternalOrder(o))
|
||||||
}*/
|
}*/
|
||||||
@ -166,4 +170,3 @@ export class OrderSender {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,13 +1,17 @@
|
|||||||
import { RefStore } from "../../state/state";
|
import { RefStore } from '../../state/state'
|
||||||
import { bank_endpoint, Session } from "../session";
|
import { Session } from '../session'
|
||||||
import { TricksterAccount, TricksterInventory } from "../trickster";
|
import { TricksterAccount, TricksterInventory } from '../trickster'
|
||||||
import { BankEndpoint, LTOApi } from "./api";
|
import { BankEndpoint, LTOApi } from './api'
|
||||||
|
|
||||||
export interface SessionBinding {
|
export interface SessionBinding {
|
||||||
new (s: Session): LTOApi
|
new (s: Session): LTOApi
|
||||||
}
|
}
|
||||||
export const getLTOState = <A extends LTOApi>(c: new (s:Session) => A,s:Session, r:RefStore): LTOApi => {
|
export const getLTOState = <A extends LTOApi>(
|
||||||
return new StatefulLTOApi(new c(s),r);
|
c: new (s: Session) => A,
|
||||||
|
s: Session,
|
||||||
|
r: RefStore,
|
||||||
|
): LTOApi => {
|
||||||
|
return new StatefulLTOApi(new c(s), r)
|
||||||
}
|
}
|
||||||
|
|
||||||
export class StatefulLTOApi implements LTOApi {
|
export class StatefulLTOApi implements LTOApi {
|
||||||
@ -35,8 +39,8 @@ export class StatefulLTOApi implements LTOApi {
|
|||||||
}
|
}
|
||||||
GetAccounts = async (): Promise<TricksterAccount[]> => {
|
GetAccounts = async (): Promise<TricksterAccount[]> => {
|
||||||
const xs = await this.u.GetAccounts()
|
const xs = await this.u.GetAccounts()
|
||||||
xs.forEach((x)=>{
|
xs.forEach(x => {
|
||||||
x.characters.forEach((ch)=>{
|
x.characters.forEach(ch => {
|
||||||
this.r.chars.value.set(ch.path, ch)
|
this.r.chars.value.set(ch.path, ch)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -46,4 +50,3 @@ export class StatefulLTOApi implements LTOApi {
|
|||||||
return this.u.GetLoggedin()
|
return this.u.GetLoggedin()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
493
src/lib/old.ts
493
src/lib/old.ts
@ -1,37 +1,36 @@
|
|||||||
import Handsontable from "handsontable"
|
import Handsontable from 'handsontable'
|
||||||
import numbro from 'numbro';
|
import Core from 'handsontable/core'
|
||||||
import { textRenderer } from "handsontable/renderers"
|
import { textRenderer } from 'handsontable/renderers'
|
||||||
import { TricksterInventory, TricksterItem } from "./trickster"
|
import numbro from 'numbro'
|
||||||
import Core from "handsontable/core";
|
import { TricksterItem } from './trickster'
|
||||||
import { RefStore } from "../state/state";
|
|
||||||
|
|
||||||
|
export const BasicColumns = ['Image', 'Name', 'Count'] as const
|
||||||
|
|
||||||
export const BasicColumns = [
|
export const DetailsColumns = ['Desc', 'Use'] as const
|
||||||
"Image","Name","Count",
|
|
||||||
] as const
|
|
||||||
|
|
||||||
export const DetailsColumns = [
|
export const MoveColumns = ['MoveCount', 'Move'] as const
|
||||||
"Desc","Use",
|
|
||||||
] as const
|
|
||||||
|
|
||||||
export const MoveColumns = [
|
export const TagColumns = ['All', 'Equip', 'Drill', 'Card', 'Quest', 'Consume', 'Compound'] as const
|
||||||
"MoveCount","Move",
|
|
||||||
] as const
|
|
||||||
|
|
||||||
export const TagColumns = [
|
export const EquipmentColumns = ['MinLvl', 'Slots', 'RefineNumber', 'RefineState'] as const
|
||||||
"All","Equip","Drill","Card","Quest","Consume", "Compound"
|
|
||||||
] as const
|
|
||||||
|
|
||||||
export const EquipmentColumns = [
|
|
||||||
"MinLvl","Slots","RefineNumber","RefineState",
|
|
||||||
] as const
|
|
||||||
|
|
||||||
export const StatsColumns = [
|
export const StatsColumns = [
|
||||||
"AP","GunAP","AC","DX","MP","MA","MD","WT","DA","LK","HP","DP","HV",
|
'AP',
|
||||||
|
'GunAP',
|
||||||
|
'AC',
|
||||||
|
'DX',
|
||||||
|
'MP',
|
||||||
|
'MA',
|
||||||
|
'MD',
|
||||||
|
'WT',
|
||||||
|
'DA',
|
||||||
|
'LK',
|
||||||
|
'HP',
|
||||||
|
'DP',
|
||||||
|
'HV',
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
export const HackColumns = [
|
export const HackColumns = [] as const
|
||||||
] as const
|
|
||||||
|
|
||||||
export const ColumnNames = [
|
export const ColumnNames = [
|
||||||
...BasicColumns,
|
...BasicColumns,
|
||||||
@ -43,22 +42,22 @@ export const ColumnNames = [
|
|||||||
...HackColumns,
|
...HackColumns,
|
||||||
] as const
|
] as const
|
||||||
|
|
||||||
export type ColumnName = typeof ColumnNames[number]
|
export type ColumnName = (typeof ColumnNames)[number]
|
||||||
|
|
||||||
const c = (a: ColumnName | ColumnInfo): ColumnName => {
|
const c = (a: ColumnName | ColumnInfo): ColumnName => {
|
||||||
switch (typeof a) {
|
switch (typeof a) {
|
||||||
case "string":
|
case 'string':
|
||||||
return a
|
return a
|
||||||
case "object":
|
case 'object':
|
||||||
return a.name
|
return a.name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const LazyColumn = c;
|
export const LazyColumn = c
|
||||||
|
|
||||||
export const ColumnSorter = (a: ColumnName | ColumnInfo, b: ColumnName | ColumnInfo): number => {
|
export const ColumnSorter = (a: ColumnName | ColumnInfo, b: ColumnName | ColumnInfo): number => {
|
||||||
let n1 = ColumnNames.indexOf(c(a))
|
const n1 = ColumnNames.indexOf(c(a))
|
||||||
let n2 = ColumnNames.indexOf(c(b))
|
const n2 = ColumnNames.indexOf(c(b))
|
||||||
if(n1 == n2) {
|
if (n1 === n2) {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return n1 > n2 ? 1 : -1
|
return n1 > n2 ? 1 : -1
|
||||||
@ -72,406 +71,448 @@ export interface ColumnInfo {
|
|||||||
renderer?: any
|
renderer?: any
|
||||||
filtering?: boolean
|
filtering?: boolean
|
||||||
writable?: boolean
|
writable?: boolean
|
||||||
getter(item:TricksterItem):(string | number)
|
getter(item: TricksterItem): string | number
|
||||||
}
|
}
|
||||||
|
|
||||||
class Image implements ColumnInfo {
|
class Image implements ColumnInfo {
|
||||||
name: ColumnName = 'Image'
|
name: ColumnName = 'Image'
|
||||||
displayName = " "
|
displayName = ' '
|
||||||
renderer = coverRenderer
|
renderer = coverRenderer
|
||||||
getter(item:TricksterItem):(string|number) {
|
getter(item: TricksterItem): string | number {
|
||||||
return item.item_image ? item.item_image : ""
|
return item.item_image ? item.item_image : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function coverRenderer(instance:any, td:any, row:any, col:any, prop:any, value:any, cellProperties:any) {
|
function coverRenderer(
|
||||||
const stringifiedValue = Handsontable.helper.stringify(value);
|
_instance: any,
|
||||||
|
td: any,
|
||||||
|
_row: any,
|
||||||
|
_col: any,
|
||||||
|
_prop: any,
|
||||||
|
value: any,
|
||||||
|
_cellProperties: any,
|
||||||
|
) {
|
||||||
|
const stringifiedValue = Handsontable.helper.stringify(value)
|
||||||
if (stringifiedValue.startsWith('http')) {
|
if (stringifiedValue.startsWith('http')) {
|
||||||
const img:any = document.createElement('IMG');
|
const img: any = document.createElement('IMG')
|
||||||
img.src = value;
|
img.src = value
|
||||||
Handsontable.dom.addEvent(img, 'mousedown', event => {
|
Handsontable.dom.addEvent(img, 'mousedown', event => {
|
||||||
event!.preventDefault();
|
event?.preventDefault()
|
||||||
});
|
})
|
||||||
Handsontable.dom.empty(td);
|
Handsontable.dom.empty(td)
|
||||||
td.appendChild(img);
|
td.appendChild(img)
|
||||||
} else {
|
} else {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Name implements ColumnInfo {
|
class Name implements ColumnInfo {
|
||||||
name:ColumnName = "Name"
|
name: ColumnName = 'Name'
|
||||||
displayName = "Name"
|
displayName = 'Name'
|
||||||
filtering = true
|
filtering = true
|
||||||
renderer = nameRenderer
|
renderer = nameRenderer
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.item_name
|
return item.item_name
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function nameRenderer(instance:any, td:any, row:any, col:any, prop:any, value:any, cellProperties:any) {
|
function nameRenderer(
|
||||||
const stringifiedValue = Handsontable.helper.stringify(value);
|
_instance: any,
|
||||||
let showText = stringifiedValue;
|
td: any,
|
||||||
const div= document.createElement('div');
|
_row: any,
|
||||||
|
_col: any,
|
||||||
|
_prop: any,
|
||||||
|
value: any,
|
||||||
|
_cellProperties: any,
|
||||||
|
) {
|
||||||
|
const stringifiedValue = Handsontable.helper.stringify(value)
|
||||||
|
const showText = stringifiedValue
|
||||||
|
const div = document.createElement('div')
|
||||||
div.innerHTML = showText
|
div.innerHTML = showText
|
||||||
div.title = showText
|
div.title = showText
|
||||||
div.style.maxWidth = "20ch"
|
div.style.maxWidth = '20ch'
|
||||||
div.style.textOverflow = "ellipsis"
|
div.style.textOverflow = 'ellipsis'
|
||||||
div.style.overflow= "hidden"
|
div.style.overflow = 'hidden'
|
||||||
div.style.whiteSpace= "nowrap"
|
div.style.whiteSpace = 'nowrap'
|
||||||
Handsontable.dom.addEvent(div, 'mousedown', event => {
|
Handsontable.dom.addEvent(div, 'mousedown', event => {
|
||||||
event!.preventDefault();
|
event?.preventDefault()
|
||||||
});
|
})
|
||||||
Handsontable.dom.empty(td);
|
Handsontable.dom.empty(td)
|
||||||
td.appendChild(div);
|
td.appendChild(div)
|
||||||
td.classList.add("htLeft")
|
td.classList.add('htLeft')
|
||||||
}
|
}
|
||||||
|
|
||||||
class Count implements ColumnInfo {
|
class Count implements ColumnInfo {
|
||||||
name:ColumnName = "Count"
|
name: ColumnName = 'Count'
|
||||||
displayName = "Count"
|
displayName = 'Count'
|
||||||
renderer = "numeric"
|
renderer = 'numeric'
|
||||||
filtering = true
|
filtering = true
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.item_count
|
return item.item_count
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Move implements ColumnInfo {
|
class Move implements ColumnInfo {
|
||||||
name:ColumnName = "Move"
|
name: ColumnName = 'Move'
|
||||||
displayName = "Target"
|
displayName = 'Target'
|
||||||
writable = true
|
writable = true
|
||||||
options = getMoveTargets
|
options = getMoveTargets
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(_item: TricksterItem): string | number {
|
||||||
return "---------------------------------------------"
|
return '---------------------------------------------'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const getMoveTargets = (invs: string[]): string[] => {
|
const getMoveTargets = (invs: string[]): string[] => {
|
||||||
let out:string[] = [];
|
const out: string[] = []
|
||||||
for (const k of invs) {
|
for (const k of invs) {
|
||||||
out.push(k)
|
out.push(k)
|
||||||
}
|
}
|
||||||
out.push("")
|
out.push('')
|
||||||
out.push("")
|
out.push('')
|
||||||
out.push("!TRASH")
|
out.push('!TRASH')
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|
||||||
class MoveCount implements ColumnInfo {
|
class MoveCount implements ColumnInfo {
|
||||||
name:ColumnName = "MoveCount"
|
name: ColumnName = 'MoveCount'
|
||||||
displayName = "Move #"
|
displayName = 'Move #'
|
||||||
renderer = moveCountRenderer
|
renderer = moveCountRenderer
|
||||||
writable = true
|
writable = true
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(_item: TricksterItem): string | number {
|
||||||
return ""
|
return ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function moveCountRenderer(instance:Core, td:any, row:number, col:number, prop:any, value:any, cellProperties:any) {
|
function moveCountRenderer(
|
||||||
let newValue = value;
|
instance: Core,
|
||||||
|
td: any,
|
||||||
|
row: number,
|
||||||
|
col: number,
|
||||||
|
prop: any,
|
||||||
|
value: any,
|
||||||
|
cellProperties: any,
|
||||||
|
) {
|
||||||
|
let newValue = value
|
||||||
|
|
||||||
if (Handsontable.helper.isNumeric(newValue)) {
|
if (Handsontable.helper.isNumeric(newValue)) {
|
||||||
const numericFormat = cellProperties.numericFormat;
|
const numericFormat = cellProperties.numericFormat
|
||||||
const cellCulture = numericFormat && numericFormat.culture || '-';
|
const cellCulture = numericFormat?.culture || '-'
|
||||||
const cellFormatPattern = numericFormat && numericFormat.pattern;
|
const cellFormatPattern = numericFormat?.pattern
|
||||||
const className = cellProperties.className || '';
|
const className = cellProperties.className || ''
|
||||||
const classArr = className.length ? className.split(' ') : [];
|
const classArr = className.length ? className.split(' ') : []
|
||||||
if (typeof cellCulture !== 'undefined' && !numbro.languages()[cellCulture]) {
|
if (typeof cellCulture !== 'undefined' && !numbro.languages()[cellCulture]) {
|
||||||
const shortTag:any = cellCulture.replace('-', '');
|
const shortTag: any = cellCulture.replace('-', '')
|
||||||
const langData = (numbro as any)[shortTag];
|
const langData = (numbro as any)[shortTag]
|
||||||
|
|
||||||
if (langData) {
|
if (langData) {
|
||||||
numbro.registerLanguage(langData);
|
numbro.registerLanguage(langData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const totalCount = Number(instance.getCell(row, col - 1)?.innerHTML)
|
const totalCount = Number(instance.getCell(row, col - 1)?.innerHTML)
|
||||||
numbro.setLanguage(cellCulture);
|
numbro.setLanguage(cellCulture)
|
||||||
const num = numbro(newValue)
|
const num = numbro(newValue)
|
||||||
if (totalCount < num.value()) {
|
if (totalCount < num.value()) {
|
||||||
const newNum = numbro(totalCount)
|
const newNum = numbro(totalCount)
|
||||||
newValue = newNum.format(cellFormatPattern || '0');
|
newValue = newNum.format(cellFormatPattern || '0')
|
||||||
} else {
|
} else {
|
||||||
newValue = num.format(cellFormatPattern || '0');
|
newValue = num.format(cellFormatPattern || '0')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (classArr.indexOf('htLeft') < 0 && classArr.indexOf('htCenter') < 0 &&
|
if (
|
||||||
classArr.indexOf('htRight') < 0 && classArr.indexOf('htJustify') < 0) {
|
classArr.indexOf('htLeft') < 0 &&
|
||||||
classArr.push('htRight');
|
classArr.indexOf('htCenter') < 0 &&
|
||||||
|
classArr.indexOf('htRight') < 0 &&
|
||||||
|
classArr.indexOf('htJustify') < 0
|
||||||
|
) {
|
||||||
|
classArr.push('htRight')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (classArr.indexOf('htNumeric') < 0) {
|
if (classArr.indexOf('htNumeric') < 0) {
|
||||||
classArr.push('htNumeric');
|
classArr.push('htNumeric')
|
||||||
}
|
}
|
||||||
cellProperties.className = classArr.join(' ');
|
cellProperties.className = classArr.join(' ')
|
||||||
|
|
||||||
td.dir = 'ltr';
|
td.dir = 'ltr'
|
||||||
newValue = newValue + "x"
|
newValue = `${newValue}x`
|
||||||
} else {
|
} else {
|
||||||
newValue = ""
|
newValue = ''
|
||||||
}
|
}
|
||||||
textRenderer(instance, td, row, col, prop, newValue, cellProperties);
|
textRenderer(instance, td, row, col, prop, newValue, cellProperties)
|
||||||
}
|
}
|
||||||
|
|
||||||
class Equip implements ColumnInfo {
|
class Equip implements ColumnInfo {
|
||||||
name:ColumnName = "Equip"
|
name: ColumnName = 'Equip'
|
||||||
displayName = "equip"
|
displayName = 'equip'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.is_equip ? 1 : 0
|
return item.is_equip ? 1 : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Drill implements ColumnInfo {
|
class Drill implements ColumnInfo {
|
||||||
name:ColumnName = "Drill"
|
name: ColumnName = 'Drill'
|
||||||
displayName = "drill"
|
displayName = 'drill'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.is_drill ? 1 : 0
|
return item.is_drill ? 1 : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class All implements ColumnInfo {
|
class All implements ColumnInfo {
|
||||||
name:ColumnName = "All"
|
name: ColumnName = 'All'
|
||||||
displayName = "swap"
|
displayName = 'swap'
|
||||||
getter(_:TricksterItem):(string|number){
|
getter(_: TricksterItem): string | number {
|
||||||
return -10000
|
return -10000
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Card implements ColumnInfo {
|
class Card implements ColumnInfo {
|
||||||
name:ColumnName = "Card"
|
name: ColumnName = 'Card'
|
||||||
displayName = "card"
|
displayName = 'card'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return cardFilter(item) ? 1 : 0
|
return cardFilter(item) ? 1 : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const cardFilter = (item: TricksterItem): boolean => {
|
const cardFilter = (item: TricksterItem): boolean => {
|
||||||
return (item.item_name.endsWith(" Card") || item.item_name.startsWith("Star Card"))
|
return item.item_name.endsWith(' Card') || item.item_name.startsWith('Star Card')
|
||||||
}
|
}
|
||||||
class Compound implements ColumnInfo {
|
class Compound implements ColumnInfo {
|
||||||
name:ColumnName = "Compound"
|
name: ColumnName = 'Compound'
|
||||||
displayName = "comp"
|
displayName = 'comp'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return compFilter(item) ? 1 : 0
|
return compFilter(item) ? 1 : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const compFilter = (item: TricksterItem): boolean => {
|
const compFilter = (item: TricksterItem): boolean => {
|
||||||
return (item.item_comment.toLowerCase().includes("compound item"))
|
return item.item_comment.toLowerCase().includes('compound item')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Quest implements ColumnInfo {
|
class Quest implements ColumnInfo {
|
||||||
name:ColumnName = "Quest"
|
name: ColumnName = 'Quest'
|
||||||
displayName = "quest"
|
displayName = 'quest'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return questFilter(item) ? 1 : 0
|
return questFilter(item) ? 1 : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const questFilter= (item:TricksterItem): boolean => {
|
const questFilter = (_item: TricksterItem): boolean => {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
class Consume implements ColumnInfo {
|
class Consume implements ColumnInfo {
|
||||||
name:ColumnName = "Consume"
|
name: ColumnName = 'Consume'
|
||||||
displayName = "eat"
|
displayName = 'eat'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return consumeFilter(item) ? 1 : 0
|
return consumeFilter(item) ? 1 : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const consumeFilter = (item: TricksterItem): boolean => {
|
const consumeFilter = (item: TricksterItem): boolean => {
|
||||||
const tl = item.item_use.toLowerCase()
|
const tl = item.item_use.toLowerCase()
|
||||||
return tl.includes("recover") || tl.includes("restores")
|
return tl.includes('recover') || tl.includes('restores')
|
||||||
}
|
}
|
||||||
|
|
||||||
class AP implements ColumnInfo {
|
class AP implements ColumnInfo {
|
||||||
name:ColumnName = "AP"
|
name: ColumnName = 'AP'
|
||||||
displayName = "AP"
|
displayName = 'AP'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["AP"] : ""
|
return item.stats ? item.stats.AP : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class GunAP implements ColumnInfo {
|
class GunAP implements ColumnInfo {
|
||||||
name:ColumnName = "GunAP"
|
name: ColumnName = 'GunAP'
|
||||||
displayName = "Gun AP"
|
displayName = 'Gun AP'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["Gun AP"] : ""
|
return item.stats ? item.stats['Gun AP'] : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class AC implements ColumnInfo {
|
class AC implements ColumnInfo {
|
||||||
name:ColumnName = "AC"
|
name: ColumnName = 'AC'
|
||||||
displayName = "AC"
|
displayName = 'AC'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["AC"] : ""
|
return item.stats ? item.stats.AC : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DX implements ColumnInfo {
|
class DX implements ColumnInfo {
|
||||||
name:ColumnName = "DX"
|
name: ColumnName = 'DX'
|
||||||
displayName = "DX"
|
displayName = 'DX'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["DX"] : ""
|
return item.stats ? item.stats.DX : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MP implements ColumnInfo {
|
class MP implements ColumnInfo {
|
||||||
name:ColumnName = "MP"
|
name: ColumnName = 'MP'
|
||||||
displayName = "MP"
|
displayName = 'MP'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["MP"] : ""
|
return item.stats ? item.stats.MP : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MA implements ColumnInfo {
|
class MA implements ColumnInfo {
|
||||||
name:ColumnName = "MA"
|
name: ColumnName = 'MA'
|
||||||
displayName = "MA"
|
displayName = 'MA'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["MA"] : ""
|
return item.stats ? item.stats.MA : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MD implements ColumnInfo {
|
class MD implements ColumnInfo {
|
||||||
name:ColumnName = "MD"
|
name: ColumnName = 'MD'
|
||||||
displayName = "MD"
|
displayName = 'MD'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["MD"] : ""
|
return item.stats ? item.stats.MD : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class WT implements ColumnInfo {
|
class WT implements ColumnInfo {
|
||||||
name:ColumnName = "WT"
|
name: ColumnName = 'WT'
|
||||||
displayName = "WT"
|
displayName = 'WT'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["WT"] : ""
|
return item.stats ? item.stats.WT : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DA implements ColumnInfo {
|
class DA implements ColumnInfo {
|
||||||
name:ColumnName = "DA"
|
name: ColumnName = 'DA'
|
||||||
displayName = "DA"
|
displayName = 'DA'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["DA"] : ""
|
return item.stats ? item.stats.DA : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class LK implements ColumnInfo {
|
class LK implements ColumnInfo {
|
||||||
name:ColumnName = "LK"
|
name: ColumnName = 'LK'
|
||||||
displayName = "LK"
|
displayName = 'LK'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["LK"] : ""
|
return item.stats ? item.stats.LK : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HP implements ColumnInfo {
|
class HP implements ColumnInfo {
|
||||||
name:ColumnName = "HP"
|
name: ColumnName = 'HP'
|
||||||
displayName = "HP"
|
displayName = 'HP'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["HP"] : ""
|
return item.stats ? item.stats.HP : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DP implements ColumnInfo {
|
class DP implements ColumnInfo {
|
||||||
name:ColumnName = "DP"
|
name: ColumnName = 'DP'
|
||||||
displayName = "DP"
|
displayName = 'DP'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["DP"] : ""
|
return item.stats ? item.stats.DP : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
class HV implements ColumnInfo {
|
class HV implements ColumnInfo {
|
||||||
name:ColumnName = "HV"
|
name: ColumnName = 'HV'
|
||||||
displayName = "HV"
|
displayName = 'HV'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.stats ? item.stats["HV"] : ""
|
return item.stats ? item.stats.HV : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MinLvl implements ColumnInfo {
|
class MinLvl implements ColumnInfo {
|
||||||
name:ColumnName = "MinLvl"
|
name: ColumnName = 'MinLvl'
|
||||||
displayName = "lvl"
|
displayName = 'lvl'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
//TODO:
|
//TODO:
|
||||||
return item.item_min_level? item.item_min_level:""
|
return item.item_min_level ? item.item_min_level : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Slots implements ColumnInfo {
|
class Slots implements ColumnInfo {
|
||||||
name:ColumnName = "Slots"
|
name: ColumnName = 'Slots'
|
||||||
displayName = "slots"
|
displayName = 'slots'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
//TODO:
|
//TODO:
|
||||||
return item.item_slots ? item.item_slots : ""
|
return item.item_slots ? item.item_slots : ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RefineNumber implements ColumnInfo {
|
class RefineNumber implements ColumnInfo {
|
||||||
name:ColumnName = "RefineNumber"
|
name: ColumnName = 'RefineNumber'
|
||||||
displayName = "refine"
|
displayName = 'refine'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.refine_level ? item.refine_level : 0
|
return item.refine_level ? item.refine_level : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class RefineState implements ColumnInfo {
|
class RefineState implements ColumnInfo {
|
||||||
name:ColumnName = "RefineState"
|
name: ColumnName = 'RefineState'
|
||||||
displayName = "bork"
|
displayName = 'bork'
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.refine_state ? item.refine_state : 0
|
return item.refine_state ? item.refine_state : 0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Desc implements ColumnInfo {
|
class Desc implements ColumnInfo {
|
||||||
name:ColumnName = "Desc"
|
name: ColumnName = 'Desc'
|
||||||
displayName = "desc"
|
displayName = 'desc'
|
||||||
renderer = descRenderer
|
renderer = descRenderer
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.item_comment
|
return item.item_comment
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function descRenderer(instance:any, td:any, row:any, col:any, prop:any, value:any, cellProperties:any) {
|
function descRenderer(
|
||||||
const stringifiedValue = Handsontable.helper.stringify(value);
|
_instance: any,
|
||||||
let showText = stringifiedValue;
|
td: any,
|
||||||
const div= document.createElement('div');
|
_row: any,
|
||||||
|
_col: any,
|
||||||
|
_prop: any,
|
||||||
|
value: any,
|
||||||
|
_cellProperties: any,
|
||||||
|
) {
|
||||||
|
const stringifiedValue = Handsontable.helper.stringify(value)
|
||||||
|
const showText = stringifiedValue
|
||||||
|
const div = document.createElement('div')
|
||||||
div.innerHTML = showText
|
div.innerHTML = showText
|
||||||
div.title = showText
|
div.title = showText
|
||||||
div.style.maxWidth = "30ch"
|
div.style.maxWidth = '30ch'
|
||||||
div.style.textOverflow = "ellipsis"
|
div.style.textOverflow = 'ellipsis'
|
||||||
div.style.overflow= "hidden"
|
div.style.overflow = 'hidden'
|
||||||
div.style.whiteSpace= "nowrap"
|
div.style.whiteSpace = 'nowrap'
|
||||||
Handsontable.dom.addEvent(div, 'mousedown', event => {
|
Handsontable.dom.addEvent(div, 'mousedown', event => {
|
||||||
event!.preventDefault();
|
event?.preventDefault()
|
||||||
});
|
})
|
||||||
Handsontable.dom.empty(td);
|
Handsontable.dom.empty(td)
|
||||||
td.appendChild(div);
|
td.appendChild(div)
|
||||||
td.classList.add("htLeft")
|
td.classList.add('htLeft')
|
||||||
}
|
}
|
||||||
|
|
||||||
class Use implements ColumnInfo {
|
class Use implements ColumnInfo {
|
||||||
name:ColumnName = "Use"
|
name: ColumnName = 'Use'
|
||||||
displayName = "use"
|
displayName = 'use'
|
||||||
renderer= useRenderer;
|
renderer = useRenderer
|
||||||
getter(item:TricksterItem):(string|number){
|
getter(item: TricksterItem): string | number {
|
||||||
return item.item_use
|
return item.item_use
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
function useRenderer(instance:any, td:any, row:any, col:any, prop:any, value:any, cellProperties:any) {
|
function useRenderer(
|
||||||
const stringifiedValue = Handsontable.helper.stringify(value);
|
_instance: any,
|
||||||
let showText = stringifiedValue;
|
td: any,
|
||||||
const div= document.createElement('div');
|
_row: any,
|
||||||
|
_col: any,
|
||||||
|
_prop: any,
|
||||||
|
value: any,
|
||||||
|
_cellProperties: any,
|
||||||
|
) {
|
||||||
|
const stringifiedValue = Handsontable.helper.stringify(value)
|
||||||
|
const showText = stringifiedValue
|
||||||
|
const div = document.createElement('div')
|
||||||
div.title = showText
|
div.title = showText
|
||||||
div.innerHTML = showText
|
div.innerHTML = showText
|
||||||
div.style.maxWidth = "30ch"
|
div.style.maxWidth = '30ch'
|
||||||
div.style.textOverflow = "ellipsis"
|
div.style.textOverflow = 'ellipsis'
|
||||||
div.style.overflow= "hidden"
|
div.style.overflow = 'hidden'
|
||||||
div.style.whiteSpace= "nowrap"
|
div.style.whiteSpace = 'nowrap'
|
||||||
Handsontable.dom.addEvent(div, 'mousedown', event => {
|
Handsontable.dom.addEvent(div, 'mousedown', event => {
|
||||||
event!.preventDefault();
|
event?.preventDefault()
|
||||||
});
|
})
|
||||||
Handsontable.dom.empty(td);
|
Handsontable.dom.empty(td)
|
||||||
td.appendChild(div);
|
td.appendChild(div)
|
||||||
td.classList.add("htLeft")
|
td.classList.add('htLeft')
|
||||||
}
|
}
|
||||||
export const ColumnByNames = (...n: ColumnName[]) => {
|
export const ColumnByNames = (...n: ColumnName[]) => {
|
||||||
return n.map(ColumnByName)
|
return n.map(ColumnByName)
|
||||||
@ -480,8 +521,8 @@ export const ColumnByNames = (...n:ColumnName[]) => {
|
|||||||
export const ColumnByName = (n: ColumnName) => {
|
export const ColumnByName = (n: ColumnName) => {
|
||||||
return Columns[n]
|
return Columns[n]
|
||||||
}
|
}
|
||||||
export const test = <T extends ColumnInfo>(n:(new ()=>T)):[string,T] => {
|
export const test = <T extends ColumnInfo>(n: new () => T): [string, T] => {
|
||||||
let nn = new n()
|
const nn = new n()
|
||||||
return [nn.name, nn]
|
return [nn.name, nn]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -1,21 +1,18 @@
|
|||||||
import axios, { AxiosError, AxiosResponse, Method } from "axios";
|
import axios, { AxiosError, AxiosResponse, Method } from 'axios'
|
||||||
import qs from "qs";
|
import qs from 'qs'
|
||||||
import { getCookie, removeCookie } from "typescript-cookie";
|
import { TricksterAccountInfo } from './trickster'
|
||||||
import { TricksterAccountInfo } from "./trickster";
|
|
||||||
|
|
||||||
|
export const SITE_ROOT = '/lifeto/'
|
||||||
|
|
||||||
export const SITE_ROOT = "/lifeto/"
|
export const API_ROOT = 'api/lifeto/'
|
||||||
|
export const BANK_ROOT = 'v2/item-manager/'
|
||||||
export const API_ROOT = "api/lifeto/"
|
export const MARKET_ROOT = 'marketplace-api/'
|
||||||
export const BANK_ROOT = "v2/item-manager/"
|
|
||||||
export const MARKET_ROOT = "marketplace-api/"
|
|
||||||
|
|
||||||
|
|
||||||
const raw_endpoint = (name: string): string => {
|
const raw_endpoint = (name: string): string => {
|
||||||
return SITE_ROOT + name
|
return SITE_ROOT + name
|
||||||
}
|
}
|
||||||
const login_endpoint = (name: string) => {
|
const login_endpoint = (name: string) => {
|
||||||
return SITE_ROOT + name + "?canonical=1"
|
return `${SITE_ROOT + name}?canonical=1`
|
||||||
}
|
}
|
||||||
export const api_endpoint = (name: string): string => {
|
export const api_endpoint = (name: string): string => {
|
||||||
return SITE_ROOT + API_ROOT + name
|
return SITE_ROOT + API_ROOT + name
|
||||||
@ -28,43 +25,44 @@ export const market_endpoint = (name:string):string =>{
|
|||||||
return SITE_ROOT + MARKET_ROOT + name
|
return SITE_ROOT + MARKET_ROOT + name
|
||||||
}
|
}
|
||||||
|
|
||||||
export const EndpointCreators = [
|
export const EndpointCreators = [api_endpoint, bank_endpoint, market_endpoint]
|
||||||
api_endpoint,
|
|
||||||
bank_endpoint,
|
|
||||||
market_endpoint,
|
|
||||||
]
|
|
||||||
|
|
||||||
export type EndpointCreator = typeof EndpointCreators[number]
|
export type EndpointCreator = (typeof EndpointCreators)[number]
|
||||||
|
|
||||||
export interface Session {
|
export interface Session {
|
||||||
request: (verb: Method, url: string, data: any, c?: EndpointCreator) => Promise<any>
|
request: (verb: Method, url: string, data: any, c?: EndpointCreator) => Promise<any>
|
||||||
}
|
}
|
||||||
|
|
||||||
export class LoginHelper {
|
export class LoginHelper {
|
||||||
constructor(){
|
|
||||||
}
|
|
||||||
static login = async (user: string, pass: string): Promise<TokenSession> => {
|
static login = async (user: string, pass: string): Promise<TokenSession> => {
|
||||||
return axios.get(login_endpoint("login"),{
|
return axios
|
||||||
|
.get(login_endpoint('login'), {
|
||||||
withCredentials: false,
|
withCredentials: false,
|
||||||
maxRedirects: 0,
|
maxRedirects: 0,
|
||||||
xsrfCookieName: "XSRF-TOKEN",
|
xsrfCookieName: 'XSRF-TOKEN',
|
||||||
})
|
})
|
||||||
.then(async () => {
|
.then(async () => {
|
||||||
return axios.post(login_endpoint("login"),{
|
return axios.post(
|
||||||
|
login_endpoint('login'),
|
||||||
|
{
|
||||||
login: user,
|
login: user,
|
||||||
password: pass,
|
password: pass,
|
||||||
redirectTo:"lifeto"
|
redirectTo: 'lifeto',
|
||||||
},{
|
},
|
||||||
|
{
|
||||||
withCredentials: false,
|
withCredentials: false,
|
||||||
maxRedirects: 0,
|
maxRedirects: 0,
|
||||||
xsrfCookieName: "XSRF-TOKEN",
|
xsrfCookieName: 'XSRF-TOKEN',
|
||||||
|
},
|
||||||
|
)
|
||||||
})
|
})
|
||||||
}).then(async ()=>{
|
.then(async () => {
|
||||||
return new TokenSession()
|
return new TokenSession()
|
||||||
}).catch((e)=>{
|
})
|
||||||
|
.catch(e => {
|
||||||
if (e instanceof AxiosError) {
|
if (e instanceof AxiosError) {
|
||||||
if(e.code == "ERR_BAD_REQUEST") {
|
if (e.code === 'ERR_BAD_REQUEST') {
|
||||||
throw "invalid username/password"
|
throw 'invalid username/password'
|
||||||
}
|
}
|
||||||
throw e.message
|
throw e.message
|
||||||
}
|
}
|
||||||
@ -72,34 +70,40 @@ export class LoginHelper {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
static info = async (): Promise<TricksterAccountInfo> => {
|
static info = async (): Promise<TricksterAccountInfo> => {
|
||||||
return axios.get(raw_endpoint("settings/info"),{withCredentials:false}).then((ans:AxiosResponse)=>{
|
return axios
|
||||||
|
.get(raw_endpoint('settings/info'), { withCredentials: false })
|
||||||
|
.then((ans: AxiosResponse) => {
|
||||||
return ans.data
|
return ans.data
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
static logout = async (): Promise<void> => {
|
static logout = async (): Promise<void> => {
|
||||||
return axios.get(login_endpoint("logout"),{withCredentials:false}).catch(()=>{}).then(()=>{})
|
return axios
|
||||||
|
.get(login_endpoint('logout'), { withCredentials: false })
|
||||||
|
.catch(() => {})
|
||||||
|
.then(() => {})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export class TokenSession implements Session {
|
export class TokenSession implements Session {
|
||||||
constructor(){
|
request = async (
|
||||||
}
|
verb: string,
|
||||||
|
url: string,
|
||||||
request = async (verb:string,url:string,data:any, c:EndpointCreator = api_endpoint):Promise<AxiosResponse> => {
|
data: any,
|
||||||
|
c: EndpointCreator = api_endpoint,
|
||||||
|
): Promise<AxiosResponse> => {
|
||||||
let promise
|
let promise
|
||||||
switch (verb.toLowerCase()) {
|
switch (verb.toLowerCase()) {
|
||||||
case "post":
|
case 'post':
|
||||||
promise = axios.post(c(url), data, this.genHeaders())
|
promise = axios.post(c(url), data, this.genHeaders())
|
||||||
break;
|
break
|
||||||
case "postform":
|
case 'postform':
|
||||||
promise = axios.postForm(c(url), data)
|
promise = axios.postForm(c(url), data)
|
||||||
break;
|
break
|
||||||
case "postraw":
|
case 'postraw': {
|
||||||
const querystring = qs.stringify(data)
|
const querystring = qs.stringify(data)
|
||||||
promise = axios.post(c(url), querystring, this.genHeaders())
|
promise = axios.post(c(url), querystring, this.genHeaders())
|
||||||
break;
|
break
|
||||||
case "get":
|
}
|
||||||
default:
|
default:
|
||||||
promise = axios.get(c(url), this.genHeaders())
|
promise = axios.get(c(url), this.genHeaders())
|
||||||
}
|
}
|
||||||
@ -108,10 +112,10 @@ export class TokenSession implements Session {
|
|||||||
genHeaders = () => {
|
genHeaders = () => {
|
||||||
const out = {
|
const out = {
|
||||||
headers: {
|
headers: {
|
||||||
Accept: "application/json",
|
Accept: 'application/json',
|
||||||
"Update-Insecure-Requests": 1,
|
'Update-Insecure-Requests': 1,
|
||||||
},
|
},
|
||||||
withCredentials:true
|
withCredentials: true,
|
||||||
}
|
}
|
||||||
return out
|
return out
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,76 +0,0 @@
|
|||||||
//class helper {
|
|
||||||
// Revive<T>(t:string, _type:string):string {
|
|
||||||
// return t
|
|
||||||
// }
|
|
||||||
// Revive<T>(t:string, _type:string[]):string[]{
|
|
||||||
// return t.split(",")
|
|
||||||
// }
|
|
||||||
// Revive<T>(t:string, _type:number):number {
|
|
||||||
// return Number(t)
|
|
||||||
// }
|
|
||||||
// Revive<T>(t:string, _type:number[]):number[]{
|
|
||||||
// return t.split(",").map(Number)
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
import { ColumnSet } from "./table"
|
|
||||||
import { TricksterAccount, TricksterCharacter, TricksterInventory } from "./trickster"
|
|
||||||
|
|
||||||
export const ARRAY_SEPERATOR = ","
|
|
||||||
|
|
||||||
let as = ARRAY_SEPERATOR
|
|
||||||
|
|
||||||
export interface Reviver<T> {
|
|
||||||
Murder(t:T):string
|
|
||||||
Revive(s:string):T
|
|
||||||
}
|
|
||||||
|
|
||||||
export const StoreStr= {
|
|
||||||
Murder: (s:string):string=>s,
|
|
||||||
Revive: (s:string):string=>s
|
|
||||||
}
|
|
||||||
|
|
||||||
export const StoreNum = {
|
|
||||||
Murder: (s:number):string=>s.toString(),
|
|
||||||
Revive: (s:string):number=>Number(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
export const StoreStrSet = {
|
|
||||||
Murder: (s:Set<string>):string=>Array.from(s).join(as),
|
|
||||||
Revive: (s:string):Set<string>=>new Set(s.split(as))
|
|
||||||
}
|
|
||||||
|
|
||||||
export const StoreColSet = {
|
|
||||||
Murder: (s:ColumnSet):string=>Array.from(s.s.values()).join(as),
|
|
||||||
Revive: (s:string):ColumnSet=>new ColumnSet(s.split(as) as any)
|
|
||||||
}
|
|
||||||
export const StoreChars = {
|
|
||||||
Murder: (s:Map<string,TricksterCharacter>):string=>{
|
|
||||||
let o = JSON.stringify(Array.from(s.entries()))
|
|
||||||
return o
|
|
||||||
},
|
|
||||||
Revive: (s:string):Map<string,TricksterCharacter>=>new Map(JSON.parse(s)),
|
|
||||||
}
|
|
||||||
export const StoreAccounts = {
|
|
||||||
Murder: (s:Map<string,TricksterAccount>):string=>{
|
|
||||||
let o = JSON.stringify(Array.from(s.entries()))
|
|
||||||
return o
|
|
||||||
},
|
|
||||||
Revive: (s:string):Map<string,TricksterAccount>=>new Map(JSON.parse(s)),
|
|
||||||
}
|
|
||||||
|
|
||||||
export const StoreJsonable = {
|
|
||||||
Murder: <T extends object>(s:T):string=>JSON.stringify(Object.entries(s)),
|
|
||||||
Revive: <T>(s:string):T=>JSON.parse(s),
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface Serializable<T> {
|
|
||||||
parse(s:any):T
|
|
||||||
}
|
|
||||||
|
|
||||||
export const StoreSerializable = <T extends Serializable<T>>(n:(new ()=>T))=>{
|
|
||||||
return {
|
|
||||||
Murder: (s:T):string=>JSON.stringify(s),
|
|
||||||
Revive: (s:string):T=>new n().parse(JSON.parse(s))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1 +0,0 @@
|
|||||||
import SuperJSON from "superjson";
|
|
||||||
@ -1,8 +1,6 @@
|
|||||||
import { TricksterInventory } from "./trickster"
|
import { HotTableProps } from '@handsontable/react'
|
||||||
import {ColumnInfo, ColumnName, Columns, ColumnSorter, LazyColumn} from "./columns"
|
import { ColumnInfo, ColumnName, ColumnSorter, Columns, LazyColumn } from './columns'
|
||||||
import { HotTableProps } from "@handsontable/react"
|
import { TricksterInventory } from './trickster'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export interface InventoryTableOptions {
|
export interface InventoryTableOptions {
|
||||||
columns: ColumnSet
|
columns: ColumnSet
|
||||||
@ -12,11 +10,11 @@ export interface InventoryTableOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Mappable<T> {
|
export interface Mappable<T> {
|
||||||
map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[];
|
map<U>(callbackfn: (value: T, index: number, array: T[]) => U, thisArg?: any): U[]
|
||||||
}
|
}
|
||||||
export class ColumnSet implements Mappable<ColumnInfo> {
|
export class ColumnSet implements Mappable<ColumnInfo> {
|
||||||
s: Set<ColumnName> = new Set()
|
s: Set<ColumnName> = new Set()
|
||||||
size: number;
|
size: number
|
||||||
dirty = 0
|
dirty = 0
|
||||||
constructor(i?: Iterable<ColumnInfo | ColumnName>) {
|
constructor(i?: Iterable<ColumnInfo | ColumnName>) {
|
||||||
if (i) {
|
if (i) {
|
||||||
@ -29,30 +27,43 @@ export class ColumnSet implements Mappable<ColumnInfo>{
|
|||||||
this.size = 0
|
this.size = 0
|
||||||
this.mark()
|
this.mark()
|
||||||
}
|
}
|
||||||
map<U>(callbackfn: (value: ColumnInfo, index: number, array: ColumnInfo[]) => U, thisArg?: any): U[] {
|
map<U>(
|
||||||
|
callbackfn: (value: ColumnInfo, index: number, array: ColumnInfo[]) => U,
|
||||||
|
thisArg?: any,
|
||||||
|
): U[] {
|
||||||
return Array.from(this.values()).map(callbackfn, thisArg)
|
return Array.from(this.values()).map(callbackfn, thisArg)
|
||||||
}
|
}
|
||||||
[Symbol.iterator](): IterableIterator<ColumnInfo> {
|
[Symbol.iterator](): IterableIterator<ColumnInfo> {
|
||||||
return this.values()
|
return this.values()
|
||||||
}
|
}
|
||||||
[Symbol.toStringTag] = "ColumnSet";
|
[Symbol.toStringTag] = 'ColumnSet'
|
||||||
entries(): IterableIterator<[ColumnInfo, ColumnInfo]> {
|
entries(): IterableIterator<[ColumnInfo, ColumnInfo]> {
|
||||||
return Array.from(this.values()).map((x):[ColumnInfo,ColumnInfo]=>{return [x,x]}).values()
|
return Array.from(this.values())
|
||||||
|
.map((x): [ColumnInfo, ColumnInfo] => {
|
||||||
|
return [x, x]
|
||||||
|
})
|
||||||
|
.values()
|
||||||
}
|
}
|
||||||
keys(): IterableIterator<ColumnInfo> {
|
keys(): IterableIterator<ColumnInfo> {
|
||||||
return this.values()
|
return this.values()
|
||||||
}
|
}
|
||||||
forEach(callbackfn: (value: ColumnInfo, value2: ColumnInfo, set: Set<ColumnInfo>) => void, thisArg?: any): void{
|
forEach(
|
||||||
Array.from(this.values()).forEach((v)=>{
|
callbackfn: (value: ColumnInfo, value2: ColumnInfo, set: Set<ColumnInfo>) => void,
|
||||||
|
thisArg?: any,
|
||||||
|
): void {
|
||||||
|
Array.from(this.values()).forEach(v => {
|
||||||
if (this.has(v)) {
|
if (this.has(v)) {
|
||||||
callbackfn(v, v, new Set(this.values()))
|
callbackfn(v, v, new Set(this.values()))
|
||||||
}
|
}
|
||||||
}, thisArg)
|
}, thisArg)
|
||||||
}
|
}
|
||||||
values(): IterableIterator<ColumnInfo> {
|
values(): IterableIterator<ColumnInfo> {
|
||||||
return Array.from(this.s.values()).sort(ColumnSorter).map((a, b)=>{
|
return Array.from(this.s.values())
|
||||||
|
.sort(ColumnSorter)
|
||||||
|
.map((a, _b) => {
|
||||||
return Columns[a]
|
return Columns[a]
|
||||||
}).values()
|
})
|
||||||
|
.values()
|
||||||
}
|
}
|
||||||
mark() {
|
mark() {
|
||||||
this.dirty = this.dirty + 1
|
this.dirty = this.dirty + 1
|
||||||
@ -93,9 +104,7 @@ export class InventoryTable {
|
|||||||
getTableColumnNames(): string[] {
|
getTableColumnNames(): string[] {
|
||||||
return this.o.columns.map(x => x.displayName)
|
return this.o.columns.map(x => x.displayName)
|
||||||
}
|
}
|
||||||
getTableColumnSettings(){
|
getTableColumnSettings() {}
|
||||||
|
|
||||||
}
|
|
||||||
getTableRows(): any[][] {
|
getTableRows(): any[][] {
|
||||||
return Object.values(this.inv.items)
|
return Object.values(this.inv.items)
|
||||||
.filter((item): boolean => {
|
.filter((item): boolean => {
|
||||||
@ -103,11 +112,11 @@ export class InventoryTable {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
let found = true
|
let found = true
|
||||||
let hasAll = this.o.tags.has("All")
|
const hasAll = this.o.tags.has('All')
|
||||||
if (this.o.tags.s.size > 0) {
|
if (this.o.tags.s.size > 0) {
|
||||||
found = hasAll
|
found = hasAll
|
||||||
for (const tag of this.o.tags.values()) {
|
for (const tag of this.o.tags.values()) {
|
||||||
if(tag.name =="All") {
|
if (tag.name === 'All') {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if (tag.getter(item) === 1) {
|
if (tag.getter(item) === 1) {
|
||||||
@ -117,7 +126,7 @@ export class InventoryTable {
|
|||||||
}
|
}
|
||||||
return found
|
return found
|
||||||
})
|
})
|
||||||
.map((item)=>{
|
.map(item => {
|
||||||
return this.o.columns.map(x => {
|
return this.o.columns.map(x => {
|
||||||
return x.getter(item)
|
return x.getter(item)
|
||||||
})
|
})
|
||||||
@ -132,7 +141,7 @@ export class InventoryTable {
|
|||||||
data: dat,
|
data: dat,
|
||||||
colHeaders: this.getTableColumnNames(),
|
colHeaders: this.getTableColumnNames(),
|
||||||
columns: this.getTableColumnSettings(),
|
columns: this.getTableColumnSettings(),
|
||||||
...s
|
...s,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -142,4 +151,3 @@ export interface TableRecipe {
|
|||||||
data: any[][]
|
data: any[][]
|
||||||
settings: HotTableProps
|
settings: HotTableProps
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import { TricksterItem } from "../trickster";
|
import { TricksterItem } from '../trickster'
|
||||||
|
|
||||||
export interface ItemSelectionStatus {
|
export interface ItemSelectionStatus {
|
||||||
selected: boolean;
|
selected: boolean
|
||||||
amount?: number;
|
amount?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ItemWithSelection {
|
export interface ItemWithSelection {
|
||||||
item: TricksterItem
|
item: TricksterItem
|
||||||
status?: ItemSelectionStatus;
|
status?: ItemSelectionStatus
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,138 +1,145 @@
|
|||||||
import { createColumnHelper } from '@tanstack/react-table';
|
import { createColumnHelper } from '@tanstack/react-table'
|
||||||
import { ItemWithSelection } from './defs';
|
import { useAtomValue, useSetAtom } from 'jotai'
|
||||||
import { useAtomValue, useSetAtom } from 'jotai';
|
import { useMemo } from 'react'
|
||||||
import { currentItemSelectionAtom, itemSelectionSetActionAtom } from '@/state/atoms';
|
import { currentItemSelectionAtom, itemSelectionSetActionAtom } from '@/state/atoms'
|
||||||
import { useMemo } from 'react';
|
import { StatsColumns } from '../columns'
|
||||||
import { StatsColumns } from '../columns';
|
import { ItemWithSelection } from './defs'
|
||||||
|
|
||||||
const ch = createColumnHelper<ItemWithSelection>();
|
const ch = createColumnHelper<ItemWithSelection>()
|
||||||
|
|
||||||
const columns = {
|
const columns = {
|
||||||
icon: ch.display({
|
icon: ch.display({
|
||||||
id: 'icon',
|
id: 'icon',
|
||||||
header: function Component(col) {
|
header: function Component(_col) {
|
||||||
return <div className="flex flex-row justify-center"></div>
|
return <div className="flex flex-row justify-center"></div>
|
||||||
},
|
},
|
||||||
cell: function Component({ row }) {
|
cell: function Component({ row }) {
|
||||||
const setItemSelection= useSetAtom(itemSelectionSetActionAtom);
|
const setItemSelection = useSetAtom(itemSelectionSetActionAtom)
|
||||||
const c = useAtomValue(currentItemSelectionAtom);
|
const c = useAtomValue(currentItemSelectionAtom)
|
||||||
const selected = useMemo(() => {
|
const selected = useMemo(() => {
|
||||||
return c[0].has(row.original.item.id);
|
return c[0].has(row.original.item.id)
|
||||||
}, [c])
|
}, [c])
|
||||||
return <div
|
return (
|
||||||
className={`no-select flex flex-row ${ row.original.status?.selected ? "animate-pulse" : ""}`}
|
<div
|
||||||
onClick={(e)=>{
|
className={`no-select flex flex-row ${row.original.status?.selected ? 'animate-pulse' : ''}`}
|
||||||
|
onClick={_e => {
|
||||||
setItemSelection({
|
setItemSelection({
|
||||||
[row.original.item.id]: selected ? undefined : row.original.item.item_count,
|
[row.original.item.id]: selected ? undefined : row.original.item.item_count,
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div className="flex flex-row w-6 h-6 justify-center">
|
<div className="flex flex-row w-6 h-6 justify-center">
|
||||||
<img src={row.original.item.item_image || ""} alt="icon" className="select-none object-contain select-none"/>
|
<img
|
||||||
|
src={row.original.item.item_image || ''}
|
||||||
|
alt="icon"
|
||||||
|
className="select-none object-contain select-none"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
count: ch.display({
|
count: ch.display({
|
||||||
id: 'count',
|
id: 'count',
|
||||||
header: function Component(col){
|
header: function Component(_col) {
|
||||||
return <div className="flex flex-row justify-center">#</div>
|
return <div className="flex flex-row justify-center">#</div>
|
||||||
},
|
},
|
||||||
cell: function Component({ row }) {
|
cell: function Component({ row }) {
|
||||||
const c = useAtomValue(currentItemSelectionAtom);
|
const c = useAtomValue(currentItemSelectionAtom)
|
||||||
const setItemSelection= useSetAtom(itemSelectionSetActionAtom);
|
const setItemSelection = useSetAtom(itemSelectionSetActionAtom)
|
||||||
const currentValue = useMemo(() => {
|
const currentValue = useMemo(() => {
|
||||||
const got = c[0].get(row.original.item.id);
|
const got = c[0].get(row.original.item.id)
|
||||||
if (got !== undefined) {
|
if (got !== undefined) {
|
||||||
return got.toString();
|
return got.toString()
|
||||||
}
|
}
|
||||||
return ""
|
return ''
|
||||||
}, [c])
|
}, [c])
|
||||||
const itemCount = row.original.item.item_count
|
const itemCount = row.original.item.item_count
|
||||||
return <div
|
return (
|
||||||
className={`flex flex-row select-none ${ row.original.status?.selected ? "bg-gray-200" : ""}`}
|
<div
|
||||||
|
className={`flex flex-row select-none ${row.original.status?.selected ? 'bg-gray-200' : ''}`}
|
||||||
>
|
>
|
||||||
<input
|
<input
|
||||||
className="w-10 text-center "
|
className="w-10 text-center "
|
||||||
value={currentValue}
|
value={currentValue}
|
||||||
onChange={(e)=>{
|
onChange={e => {
|
||||||
if(e.target.value === ""){
|
if (e.target.value === '') {
|
||||||
setItemSelection({[row.original.item.id]: undefined});
|
setItemSelection({ [row.original.item.id]: undefined })
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if(e.target.value === "-"){
|
if (e.target.value === '-') {
|
||||||
setItemSelection({
|
setItemSelection({
|
||||||
[row.original.item.id]: itemCount,
|
[row.original.item.id]: itemCount,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
let parsedInt = parseInt(e.target.value);
|
let parsedInt = parseInt(e.target.value)
|
||||||
if (isNaN(parsedInt)) {
|
if (Number.isNaN(parsedInt)) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
if (parsedInt > itemCount) {
|
if (parsedInt > itemCount) {
|
||||||
parsedInt = itemCount;
|
parsedInt = itemCount
|
||||||
}
|
}
|
||||||
setItemSelection({
|
setItemSelection({
|
||||||
[row.original.item.id]: parsedInt,
|
[row.original.item.id]: parsedInt,
|
||||||
})
|
})
|
||||||
}}
|
}}
|
||||||
placeholder={itemCount.toString()} />
|
placeholder={itemCount.toString()}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
name: ch.display({
|
name: ch.display({
|
||||||
id: 'name',
|
id: 'name',
|
||||||
header: (col)=> {
|
header: _col => {
|
||||||
return <div
|
return <div className="flex flex-row text-sm">name</div>
|
||||||
className="flex flex-row text-sm"
|
|
||||||
>name</div>
|
|
||||||
},
|
},
|
||||||
cell: function Component({ row }) {
|
cell: function Component({ row }) {
|
||||||
return <div className="flex flex-row whitespace-pre">
|
return (
|
||||||
|
<div className="flex flex-row whitespace-pre">
|
||||||
<span>{row.original.item.item_name}</span>
|
<span>{row.original.item.item_name}</span>
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
slots: ch.display({
|
slots: ch.display({
|
||||||
id: 'slots',
|
id: 'slots',
|
||||||
header: (col)=>{
|
header: _col => {
|
||||||
return <div
|
return <div className="flex flex-row text-sm">slots</div>
|
||||||
className="flex flex-row text-sm"
|
|
||||||
>slots</div>
|
|
||||||
},
|
},
|
||||||
cell: function Component({ row }) {
|
cell: function Component({ row }) {
|
||||||
return <div className="flex flex-row justify-center">
|
return (
|
||||||
|
<div className="flex flex-row justify-center">
|
||||||
<span>{row.original.item.item_slots}</span>
|
<span>{row.original.item.item_slots}</span>
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
stats: ch.group({
|
stats: ch.group({
|
||||||
id: 'stats',
|
id: 'stats',
|
||||||
header: (col)=>{
|
header: _col => {
|
||||||
return <div
|
return <div className="flex flex-row text-sm">stats</div>
|
||||||
className="flex flex-row text-sm"
|
|
||||||
>stats</div>
|
|
||||||
},
|
},
|
||||||
columns: [
|
columns: [
|
||||||
...StatsColumns.map((c)=>{
|
...StatsColumns.map(c => {
|
||||||
return ch.display({
|
return ch.display({
|
||||||
id: 'stats.'+c,
|
id: `stats.${c}`,
|
||||||
header: (col)=>{
|
header: _col => {
|
||||||
return <div
|
return <div className="flex flex-row text-sm justify-center">{c}</div>
|
||||||
className="flex flex-row text-sm justify-center"
|
|
||||||
>{c}</div>
|
|
||||||
},
|
},
|
||||||
cell: function Component({ row }) {
|
cell: function Component({ row }) {
|
||||||
const stats = row.original.item.stats
|
const stats = row.original.item.stats
|
||||||
const stat = stats ? stats[c] : ""
|
const stat = stats ? stats[c] : ''
|
||||||
return <div className={`flex flex-row justify-start ${stat ? "border" : ""}`}>
|
return (
|
||||||
|
<div className={`flex flex-row justify-start ${stat ? 'border' : ''}`}>
|
||||||
<span>{stat}</span>
|
<span>{stat}</span>
|
||||||
</div>
|
</div>
|
||||||
|
)
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
|
||||||
]
|
|
||||||
}),
|
}),
|
||||||
} as const;
|
],
|
||||||
|
}),
|
||||||
|
} as const
|
||||||
|
|
||||||
export const InventoryColumns = columns;
|
export const InventoryColumns = columns
|
||||||
|
|||||||
@ -1,21 +1,21 @@
|
|||||||
export interface TricksterItem {
|
export interface TricksterItem {
|
||||||
id: string;
|
id: string
|
||||||
unique_id: number;
|
unique_id: number
|
||||||
item_name: string;
|
item_name: string
|
||||||
item_count: number;
|
item_count: number
|
||||||
item_comment: string;
|
item_comment: string
|
||||||
item_use: string;
|
item_use: string
|
||||||
item_slots?: number;
|
item_slots?: number
|
||||||
item_tab: number
|
item_tab: number
|
||||||
item_type: number,
|
item_type: number
|
||||||
item_min_level?: number;
|
item_min_level?: number
|
||||||
is_equip?: boolean;
|
is_equip?: boolean
|
||||||
is_drill?: boolean;
|
is_drill?: boolean
|
||||||
item_expire_time?: string;
|
item_expire_time?: string
|
||||||
refine_level?: number;
|
refine_level?: number
|
||||||
refine_type?: number;
|
refine_type?: number
|
||||||
refine_state?: number;
|
refine_state?: number
|
||||||
item_image?: string;
|
item_image?: string
|
||||||
stats?: { [key: string]: any }
|
stats?: { [key: string]: any }
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -48,51 +48,50 @@ export interface TricksterInventory extends Identifier{
|
|||||||
items: Map<string, TricksterItem>
|
items: Map<string, TricksterItem>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const jobMap: { [key: number]: string } = {
|
const jobMap: { [key: number]: string } = {
|
||||||
//---- job 1, fm
|
//---- job 1, fm
|
||||||
1: "schoolgirl",
|
1: 'schoolgirl',
|
||||||
2: "fighter",
|
2: 'fighter',
|
||||||
3: "librarian",
|
3: 'librarian',
|
||||||
4: "shaman",
|
4: 'shaman',
|
||||||
5: "archeologist",
|
5: 'archeologist',
|
||||||
6: "engineer",
|
6: 'engineer',
|
||||||
7: "model",
|
7: 'model',
|
||||||
8: "teacher",
|
8: 'teacher',
|
||||||
//---- job 2 fm
|
//---- job 2 fm
|
||||||
9: "boxer",
|
9: 'boxer',
|
||||||
10: "warrior",
|
10: 'warrior',
|
||||||
11: "bard",
|
11: 'bard',
|
||||||
12: "magician",
|
12: 'magician',
|
||||||
13: "explorer",
|
13: 'explorer',
|
||||||
14: "inventor",
|
14: 'inventor',
|
||||||
15: "entertainer",
|
15: 'entertainer',
|
||||||
16: "card master",
|
16: 'card master',
|
||||||
//----
|
//----
|
||||||
17: "champion",
|
17: 'champion',
|
||||||
18: "duelist",
|
18: 'duelist',
|
||||||
19: "mercinary",
|
19: 'mercinary',
|
||||||
20: "gladiator",
|
20: 'gladiator',
|
||||||
21: "soul master",
|
21: 'soul master',
|
||||||
22: "witch",
|
22: 'witch',
|
||||||
23: "wizard",
|
23: 'wizard',
|
||||||
24: "dark lord",
|
24: 'dark lord',
|
||||||
25: "priest",
|
25: 'priest',
|
||||||
26: "thief master",
|
26: 'thief master',
|
||||||
27: "hunter lord",
|
27: 'hunter lord',
|
||||||
28: "cyber hunter",
|
28: 'cyber hunter',
|
||||||
29: "scientist",
|
29: 'scientist',
|
||||||
30: "primadonna",
|
30: 'primadonna',
|
||||||
31: "diva",
|
31: 'diva',
|
||||||
32: "duke",
|
32: 'duke',
|
||||||
33: "gambler",
|
33: 'gambler',
|
||||||
}
|
}
|
||||||
|
|
||||||
export const JobNumberToString = (n: number): string => {
|
export const JobNumberToString = (n: number): string => {
|
||||||
if(n == -8) {
|
if (n === -8) {
|
||||||
return "bank"
|
return 'bank'
|
||||||
}
|
}
|
||||||
if(jobMap[n] != undefined) {
|
if (jobMap[n] !== undefined) {
|
||||||
return jobMap[n]
|
return jobMap[n]
|
||||||
}
|
}
|
||||||
return n.toString()
|
return n.toString()
|
||||||
|
|||||||
@ -1,24 +1,19 @@
|
|||||||
import { Session, TokenSession } from './lib/session'
|
import { Session, TokenSession } from './lib/session'
|
||||||
|
|
||||||
|
export const LIFETO_COOKIE_PREFIX = 'LIFETO_PANEL_'
|
||||||
|
|
||||||
export const LIFETO_COOKIE_PREFIX="LIFETO_PANEL_"
|
|
||||||
|
|
||||||
export const nameCookie = (...s: string[]): string => {
|
export const nameCookie = (...s: string[]): string => {
|
||||||
return LIFETO_COOKIE_PREFIX+s.join("_").toUpperCase()
|
return LIFETO_COOKIE_PREFIX + s.join('_').toUpperCase()
|
||||||
}
|
}
|
||||||
|
|
||||||
export class Storage {
|
export class Storage {
|
||||||
GetSession(): Session {
|
GetSession(): Session {
|
||||||
return new TokenSession()
|
return new TokenSession()
|
||||||
}
|
}
|
||||||
RemoveSession() {
|
RemoveSession() {}
|
||||||
}
|
AddSession(_s: Session) {
|
||||||
AddSession(s:Session) {
|
|
||||||
// setCookie(nameCookie("xsrf"),s.xsrf)
|
// setCookie(nameCookie("xsrf"),s.xsrf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const storage = new Storage()
|
export const storage = new Storage()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -1,37 +1,38 @@
|
|||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios'
|
||||||
|
import Fuse from 'fuse.js'
|
||||||
|
import { atom } from 'jotai'
|
||||||
|
import { atomWithStorage } from 'jotai/utils'
|
||||||
|
import { focusAtom } from 'jotai-optics'
|
||||||
|
import { atomWithQuery } from 'jotai-tanstack-query'
|
||||||
|
import { ItemWithSelection } from '@/lib/table/defs'
|
||||||
import { LTOApiv0 } from '../lib/lifeto'
|
import { LTOApiv0 } from '../lib/lifeto'
|
||||||
import { LoginHelper, TokenSession } from '../lib/session'
|
import { LoginHelper, TokenSession } from '../lib/session'
|
||||||
import { atomWithQuery } from 'jotai-tanstack-query'
|
import { TricksterCharacter, TricksterItem } from '../lib/trickster'
|
||||||
import {atomWithStorage} from "jotai/utils";
|
import { createSuperjsonStorage } from './storage'
|
||||||
import { atom } from 'jotai';
|
|
||||||
import { TricksterCharacter, TricksterInventory, TricksterItem } from '../lib/trickster';
|
|
||||||
import {focusAtom} from "jotai-optics";
|
|
||||||
import { createSuperjsonStorage, superJsonStorage } from './storage';
|
|
||||||
import { ItemWithSelection } from '@/lib/table/defs';
|
|
||||||
import Fuse from 'fuse.js';
|
|
||||||
|
|
||||||
export const LTOApi = new LTOApiv0(new TokenSession())
|
export const LTOApi = new LTOApiv0(new TokenSession())
|
||||||
|
|
||||||
|
export const loginStatusAtom = atomWithQuery(_get => {
|
||||||
export const loginStatusAtom = atomWithQuery((get) => {
|
|
||||||
return {
|
return {
|
||||||
queryKey: ['login_status'],
|
queryKey: ['login_status'],
|
||||||
enabled: true,
|
enabled: true,
|
||||||
placeholderData: {
|
placeholderData: {
|
||||||
logged_in: false,
|
logged_in: false,
|
||||||
community_name: "...",
|
community_name: '...',
|
||||||
},
|
},
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
return LoginHelper.info().then(info => {
|
return LoginHelper.info()
|
||||||
|
.then(info => {
|
||||||
return {
|
return {
|
||||||
logged_in: true,
|
logged_in: true,
|
||||||
community_name: info.community_name,
|
community_name: info.community_name,
|
||||||
}
|
}
|
||||||
}).catch(e => {
|
})
|
||||||
|
.catch(e => {
|
||||||
if (e instanceof AxiosError) {
|
if (e instanceof AxiosError) {
|
||||||
return {
|
return {
|
||||||
logged_in: false,
|
logged_in: false,
|
||||||
community_name: "...",
|
community_name: '...',
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
throw e
|
throw e
|
||||||
@ -40,13 +41,10 @@ export const loginStatusAtom = atomWithQuery((get) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
export const charactersAtom = atomWithQuery(get => {
|
||||||
|
|
||||||
export const charactersAtom = atomWithQuery((get) => {
|
|
||||||
const { data: loginStatus } = get(loginStatusAtom)
|
const { data: loginStatus } = get(loginStatusAtom)
|
||||||
console.log("charactersAtom", loginStatus)
|
|
||||||
return {
|
return {
|
||||||
queryKey: ['characters', loginStatus?.community_name || "..."],
|
queryKey: ['characters', loginStatus?.community_name || '...'],
|
||||||
enabled: !!loginStatus?.logged_in,
|
enabled: !!loginStatus?.logged_in,
|
||||||
refetchOnMount: true,
|
refetchOnMount: true,
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
@ -54,9 +52,15 @@ export const charactersAtom = atomWithQuery((get) => {
|
|||||||
if (!x) {
|
if (!x) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
const rawCharacters = x.flatMap(x=>{return x?.characters})
|
const rawCharacters = x.flatMap(x => {
|
||||||
const characterPairs: Record<string, {bank?: TricksterCharacter, character?: TricksterCharacter}> = {}
|
return x?.characters
|
||||||
rawCharacters.forEach(x=>{
|
})
|
||||||
|
const characterPairs: Record<
|
||||||
|
string,
|
||||||
|
{ bank?: TricksterCharacter; character?: TricksterCharacter }
|
||||||
|
> = {}
|
||||||
|
rawCharacters.forEach(
|
||||||
|
x => {
|
||||||
let item = characterPairs[x.account_name]
|
let item = characterPairs[x.account_name]
|
||||||
if (!item) {
|
if (!item) {
|
||||||
item = {}
|
item = {}
|
||||||
@ -67,13 +71,15 @@ export const charactersAtom = atomWithQuery((get) => {
|
|||||||
item.character = x
|
item.character = x
|
||||||
}
|
}
|
||||||
characterPairs[x.account_name] = item
|
characterPairs[x.account_name] = item
|
||||||
}, [rawCharacters])
|
},
|
||||||
|
[rawCharacters],
|
||||||
|
)
|
||||||
const cleanCharacterPairs = Object.values(characterPairs).filter(x => {
|
const cleanCharacterPairs = Object.values(characterPairs).filter(x => {
|
||||||
if (!(!!x.bank && !!x.character)) {
|
if (!(!!x.bank && !!x.character)) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}) as Array<{bank: TricksterCharacter, character: TricksterCharacter}>
|
}) as Array<{ bank: TricksterCharacter; character: TricksterCharacter }>
|
||||||
|
|
||||||
return cleanCharacterPairs
|
return cleanCharacterPairs
|
||||||
})
|
})
|
||||||
@ -81,18 +87,20 @@ export const charactersAtom = atomWithQuery((get) => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export const selectedCharacterAtom = atomWithStorage<TricksterCharacter | undefined>("lto_state.selected_character", undefined)
|
export const selectedCharacterAtom = atomWithStorage<TricksterCharacter | undefined>(
|
||||||
|
'lto_state.selected_character',
|
||||||
|
undefined,
|
||||||
|
)
|
||||||
export const selectedTargetInventoryAtom = atom<TricksterCharacter | undefined>(undefined)
|
export const selectedTargetInventoryAtom = atom<TricksterCharacter | undefined>(undefined)
|
||||||
|
|
||||||
export const currentFilter = atom<undefined>(undefined)
|
export const currentFilter = atom<undefined>(undefined)
|
||||||
|
|
||||||
|
export const currentCharacterInventoryAtom = atomWithQuery(get => {
|
||||||
export const currentCharacterInventoryAtom = atomWithQuery((get) => {
|
|
||||||
const currentCharacter = get(selectedCharacterAtom)
|
const currentCharacter = get(selectedCharacterAtom)
|
||||||
return {
|
return {
|
||||||
queryKey:["inventory", currentCharacter?.path || "-"],
|
queryKey: ['inventory', currentCharacter?.path || '-'],
|
||||||
queryFn: async () => {
|
queryFn: async () => {
|
||||||
return LTOApi.GetInventory(currentCharacter?.path|| "-")
|
return LTOApi.GetInventory(currentCharacter?.path || '-')
|
||||||
},
|
},
|
||||||
enabled: !!currentCharacter,
|
enabled: !!currentCharacter,
|
||||||
// placeholderData: keepPreviousData,
|
// placeholderData: keepPreviousData,
|
||||||
@ -101,26 +109,27 @@ export const currentCharacterInventoryAtom = atomWithQuery((get) => {
|
|||||||
|
|
||||||
const inventoryDisplaySettings = atomWithStorage<{
|
const inventoryDisplaySettings = atomWithStorage<{
|
||||||
page_size: number
|
page_size: number
|
||||||
}>("preference.inventory_display_settings", {
|
}>(
|
||||||
|
'preference.inventory_display_settings',
|
||||||
|
{
|
||||||
page_size: 25,
|
page_size: 25,
|
||||||
}, createSuperjsonStorage())
|
},
|
||||||
|
createSuperjsonStorage(),
|
||||||
|
)
|
||||||
|
|
||||||
export const inventoryDisplaySettingsAtoms = {
|
export const inventoryDisplaySettingsAtoms = {
|
||||||
pageSize: focusAtom(inventoryDisplaySettings, x => x.prop('page_size')),
|
pageSize: focusAtom(inventoryDisplaySettings, x => x.prop('page_size')),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const currentCharacterItemsAtom = atom(get => {
|
||||||
export const currentCharacterItemsAtom = atom((get)=>{
|
|
||||||
const { data: inventory } = get(currentCharacterInventoryAtom)
|
const { data: inventory } = get(currentCharacterInventoryAtom)
|
||||||
const items = inventory?.items || new Map<string, TricksterItem>()
|
const items = inventory?.items || new Map<string, TricksterItem>()
|
||||||
return {
|
return {
|
||||||
items,
|
items,
|
||||||
searcher: new Fuse(Array.from(items.values()), {
|
searcher: new Fuse(Array.from(items.values()), {
|
||||||
keys: [
|
keys: ['item_name'],
|
||||||
'item_name',
|
|
||||||
],
|
|
||||||
useExtendedSearch: true,
|
useExtendedSearch: true,
|
||||||
})
|
}),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -131,20 +140,23 @@ export interface InventoryFilter {
|
|||||||
sort_reverse: boolean
|
sort_reverse: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export const inventoryFilterAtom = atomWithStorage<InventoryFilter>("preference.inventory_filter", {
|
export const inventoryFilterAtom = atomWithStorage<InventoryFilter>(
|
||||||
search: "",
|
'preference.inventory_filter',
|
||||||
tab: "",
|
{
|
||||||
sort: "",
|
search: '',
|
||||||
|
tab: '',
|
||||||
|
sort: '',
|
||||||
sort_reverse: false,
|
sort_reverse: false,
|
||||||
}, createSuperjsonStorage())
|
},
|
||||||
|
createSuperjsonStorage(),
|
||||||
|
)
|
||||||
|
|
||||||
export const preferenceInventorySearch = focusAtom(inventoryFilterAtom, x => x.prop('search'))
|
export const preferenceInventorySearch = focusAtom(inventoryFilterAtom, x => x.prop('search'))
|
||||||
export const preferenceInventoryTab = focusAtom(inventoryFilterAtom, x => x.prop('tab'))
|
export const preferenceInventoryTab = focusAtom(inventoryFilterAtom, x => x.prop('tab'))
|
||||||
export const preferenceInventorySort = focusAtom(inventoryFilterAtom, x => x.prop('sort'))
|
export const preferenceInventorySort = focusAtom(inventoryFilterAtom, x => x.prop('sort'))
|
||||||
export const preferenceInventorySortReverse = focusAtom(inventoryFilterAtom, x=>x.prop('sort_reverse'))
|
export const preferenceInventorySortReverse = focusAtom(inventoryFilterAtom, x =>
|
||||||
|
x.prop('sort_reverse'),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
export const setInventoryFilterTabActionAtom = atom(null, (_get, set, tab: string) => {
|
export const setInventoryFilterTabActionAtom = atom(null, (_get, set, tab: string) => {
|
||||||
set(inventoryFilterAtom, x => {
|
set(inventoryFilterAtom, x => {
|
||||||
@ -168,26 +180,29 @@ export const nextInventoryPageActionAtom = atom(null, (get, set) => {
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
export const currentItemSelectionAtom = atom<[Map<string, number>, number]>([new Map<string, number>(), 0])
|
export const currentItemSelectionAtom = atom<[Map<string, number>, number]>([
|
||||||
export const currentInventorySearchQueryAtom = atom("")
|
new Map<string, number>(),
|
||||||
|
0,
|
||||||
|
])
|
||||||
|
export const currentInventorySearchQueryAtom = atom('')
|
||||||
|
|
||||||
export const filteredCharacterItemsAtom = atom((get)=>{
|
export const filteredCharacterItemsAtom = atom(get => {
|
||||||
const { items, searcher } = get(currentCharacterItemsAtom)
|
const { items, searcher } = get(currentCharacterItemsAtom)
|
||||||
const [selection] = get(currentItemSelectionAtom)
|
const [selection] = get(currentItemSelectionAtom)
|
||||||
const filter = get(inventoryFilterAtom)
|
const filter = get(inventoryFilterAtom)
|
||||||
const out: ItemWithSelection[] = []
|
const out: ItemWithSelection[] = []
|
||||||
for (const [_, value] of items.entries()) {
|
for (const [_, value] of items.entries()) {
|
||||||
if(filter.search !== "") {
|
if (filter.search !== '') {
|
||||||
if (!value.item_name.toLowerCase().includes(filter.search)) {
|
if (!value.item_name.toLowerCase().includes(filter.search)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(filter.tab !== "") {
|
if (filter.tab !== '') {
|
||||||
if (value.item_tab !== parseInt(filter.tab)) {
|
if (value.item_tab !== parseInt(filter.tab)) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let status = undefined
|
let status
|
||||||
if (selection.has(value.id)) {
|
if (selection.has(value.id)) {
|
||||||
status = {
|
status = {
|
||||||
selected: true,
|
selected: true,
|
||||||
@ -197,21 +212,21 @@ export const filteredCharacterItemsAtom = atom((get)=>{
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (filter.sort) {
|
switch (filter.sort) {
|
||||||
case "count":
|
case 'count':
|
||||||
out.sort((a, b) => {
|
out.sort((a, b) => {
|
||||||
return b.item.item_count - a.item.item_count
|
return b.item.item_count - a.item.item_count
|
||||||
})
|
})
|
||||||
break;
|
break
|
||||||
case "type":
|
case 'type':
|
||||||
out.sort((a, b) => {
|
out.sort((a, b) => {
|
||||||
return a.item.item_tab - b.item.item_tab
|
return a.item.item_tab - b.item.item_tab
|
||||||
})
|
})
|
||||||
break;
|
break
|
||||||
case "name":
|
case 'name':
|
||||||
out.sort((a, b) => {
|
out.sort((a, b) => {
|
||||||
return a.item.item_name.localeCompare(b.item.item_name)
|
return a.item.item_name.localeCompare(b.item.item_name)
|
||||||
})
|
})
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
if (filter.sort && filter.sort_reverse) {
|
if (filter.sort && filter.sort_reverse) {
|
||||||
out.reverse()
|
out.reverse()
|
||||||
@ -219,7 +234,7 @@ export const filteredCharacterItemsAtom = atom((get)=>{
|
|||||||
return out
|
return out
|
||||||
})
|
})
|
||||||
|
|
||||||
export const inventoryItemsCurrentPageAtom = atom((get)=>{
|
export const inventoryItemsCurrentPageAtom = atom(get => {
|
||||||
const items = get(filteredCharacterItemsAtom)
|
const items = get(filteredCharacterItemsAtom)
|
||||||
const { start, end } = get(inventoryPageRangeAtom)
|
const { start, end } = get(inventoryPageRangeAtom)
|
||||||
return items.slice(start, end).map((item): ItemWithSelection => {
|
return items.slice(start, end).map((item): ItemWithSelection => {
|
||||||
@ -227,17 +242,21 @@ export const inventoryItemsCurrentPageAtom = atom((get)=>{
|
|||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
export const rowSelectionLastActionAtom = atom<{
|
export const rowSelectionLastActionAtom = atom<
|
||||||
|
| {
|
||||||
index: number
|
index: number
|
||||||
action: "add" | "remove"
|
action: 'add' | 'remove'
|
||||||
}| undefined>(undefined)
|
}
|
||||||
|
| undefined
|
||||||
|
>(undefined)
|
||||||
|
|
||||||
export const clearItemSelectionActionAtom = atom(null, (_get, set) => {
|
export const clearItemSelectionActionAtom = atom(null, (_get, set) => {
|
||||||
set(currentItemSelectionAtom, [new Map<string, number>(), 0])
|
set(currentItemSelectionAtom, [new Map<string, number>(), 0])
|
||||||
})
|
})
|
||||||
|
|
||||||
export const itemSelectionSetActionAtom = atom(null, (get, set, arg: Record<string,number | undefined> ) => {
|
export const itemSelectionSetActionAtom = atom(
|
||||||
|
null,
|
||||||
|
(get, set, arg: Record<string, number | undefined>) => {
|
||||||
const cur = get(currentItemSelectionAtom)
|
const cur = get(currentItemSelectionAtom)
|
||||||
for (const [key, value] of Object.entries(arg)) {
|
for (const [key, value] of Object.entries(arg)) {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
@ -247,7 +266,8 @@ export const itemSelectionSetActionAtom = atom(null, (get, set, arg: Record<stri
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
set(currentItemSelectionAtom, [cur[0], cur[1] + 1])
|
set(currentItemSelectionAtom, [cur[0], cur[1] + 1])
|
||||||
})
|
},
|
||||||
|
)
|
||||||
|
|
||||||
export const itemSelectionSelectAllFilterActionAtom = atom(null, (get, set) => {
|
export const itemSelectionSelectAllFilterActionAtom = atom(null, (get, set) => {
|
||||||
const cur = get(currentItemSelectionAtom)
|
const cur = get(currentItemSelectionAtom)
|
||||||
@ -308,7 +328,7 @@ export const paginateInventoryActionAtom = atom(null, (get, set, pages: number |
|
|||||||
if (newEnd > filteredItems.length) {
|
if (newEnd > filteredItems.length) {
|
||||||
newEnd = filteredItems.length
|
newEnd = filteredItems.length
|
||||||
}
|
}
|
||||||
if(newEnd - newStart != pageSize) {
|
if (newEnd - newStart !== pageSize) {
|
||||||
newStart = newEnd - pageSize
|
newStart = newEnd - pageSize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { defineStore, storeToRefs } from 'pinia'
|
import { defineStore, storeToRefs } from 'pinia'
|
||||||
import { BasicColumns, ColumnInfo, ColumnName, Columns, DetailsColumns, MoveColumns } from '../lib/columns'
|
import { BasicColumns, ColumnInfo, ColumnName, DetailsColumns, MoveColumns } from '../lib/columns'
|
||||||
import { OrderTracker } from '../lib/lifeto/order_manager'
|
import { OrderTracker } from '../lib/lifeto/order_manager'
|
||||||
import { StoreAccounts, StoreChars, StoreColSet, StoreStr } from '../lib/storage'
|
import { StoreAccounts, StoreChars, StoreColSet, StoreStr } from '../lib/storage'
|
||||||
import { ColumnSet } from '../lib/table'
|
import { ColumnSet } from '../lib/table'
|
||||||
@ -38,43 +38,42 @@ export interface StoreProps {
|
|||||||
|
|
||||||
export const useStore = defineStore('state', {
|
export const useStore = defineStore('state', {
|
||||||
state: () => {
|
state: () => {
|
||||||
let store = {
|
const store = {
|
||||||
invs: new Map() as Map<string, TricksterInventory>,
|
invs: new Map() as Map<string, TricksterInventory>,
|
||||||
chars: new Map() as Map<string, TricksterCharacter>,
|
chars: new Map() as Map<string, TricksterCharacter>,
|
||||||
accs: new Map() as Map<string, TricksterAccount>,
|
accs: new Map() as Map<string, TricksterAccount>,
|
||||||
orders: new OrderTracker(),
|
orders: new OrderTracker(),
|
||||||
activeTable: "none",
|
activeTable: 'none',
|
||||||
screen: "default",
|
screen: 'default',
|
||||||
columns: new ColumnSet(_defaultColumn),
|
columns: new ColumnSet(_defaultColumn),
|
||||||
tags: new ColumnSet(),
|
tags: new ColumnSet(),
|
||||||
dirty: 0,
|
dirty: 0,
|
||||||
currentSearch: "",
|
currentSearch: '',
|
||||||
}
|
}
|
||||||
return store
|
return store
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
export const loadStore = () => {
|
export const loadStore = () => {
|
||||||
let store = useStoreRef()
|
const store = useStoreRef()
|
||||||
for (const [k, v] of Object.entries(StoreReviver)) {
|
for (const [k, v] of Object.entries(StoreReviver)) {
|
||||||
const coke = localStorage.getItem(nameCookie("last_"+k))
|
const coke = localStorage.getItem(nameCookie(`last_${k}`))
|
||||||
if (coke) {
|
if (coke) {
|
||||||
if((store[k as keyof RefStore]) != undefined){
|
if (store[k as keyof RefStore] !== undefined) {
|
||||||
store[k as keyof RefStore].value = v.Revive(coke) as any
|
store[k as keyof RefStore].value = v.Revive(coke) as any
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
export const saveStore = () => {
|
export const saveStore = () => {
|
||||||
let store = useStoreRef()
|
const store = useStoreRef()
|
||||||
for (const [k, v] of Object.entries(StoreReviver)) {
|
for (const [k, v] of Object.entries(StoreReviver)) {
|
||||||
let coke;
|
let coke
|
||||||
if((store[k as keyof RefStore]) != undefined){
|
if (store[k as keyof RefStore] !== undefined) {
|
||||||
coke = v.Murder(store[k as keyof RefStore].value as any)
|
coke = v.Murder(store[k as keyof RefStore].value as any)
|
||||||
}
|
}
|
||||||
if (coke) {
|
if (coke) {
|
||||||
localStorage.setItem(nameCookie("last_"+k),coke)
|
localStorage.setItem(nameCookie(`last_${k}`), coke)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -82,8 +81,6 @@ export const saveStore = ()=> {
|
|||||||
export const useStoreRef = () => {
|
export const useStoreRef = () => {
|
||||||
const refs = storeToRefs(useStore())
|
const refs = storeToRefs(useStore())
|
||||||
return refs
|
return refs
|
||||||
};
|
}
|
||||||
|
|
||||||
export type RefStore = ReturnType<typeof useStoreRef>;
|
|
||||||
|
|
||||||
|
|
||||||
|
export type RefStore = ReturnType<typeof useStoreRef>
|
||||||
|
|||||||
@ -1,4 +1,9 @@
|
|||||||
import { AsyncStorage, AsyncStringStorage, SyncStorage, SyncStringStorage } from "jotai/vanilla/utils/atomWithStorage"
|
import {
|
||||||
|
AsyncStorage,
|
||||||
|
AsyncStringStorage,
|
||||||
|
SyncStorage,
|
||||||
|
SyncStringStorage,
|
||||||
|
} from 'jotai/vanilla/utils/atomWithStorage'
|
||||||
import superjson from 'superjson'
|
import superjson from 'superjson'
|
||||||
|
|
||||||
const isPromiseLike = (x: unknown): x is PromiseLike<unknown> =>
|
const isPromiseLike = (x: unknown): x is PromiseLike<unknown> =>
|
||||||
@ -19,16 +24,12 @@ type StringSubscribe = (
|
|||||||
|
|
||||||
export function createSuperjsonStorage<Value>(): SyncStorage<Value>
|
export function createSuperjsonStorage<Value>(): SyncStorage<Value>
|
||||||
export function createSuperjsonStorage<Value>(
|
export function createSuperjsonStorage<Value>(
|
||||||
getStringStorage: () =>
|
getStringStorage: () => AsyncStringStorage | SyncStringStorage | undefined = () => {
|
||||||
| AsyncStringStorage
|
|
||||||
| SyncStringStorage
|
|
||||||
| undefined = () => {
|
|
||||||
try {
|
try {
|
||||||
return window.localStorage
|
return window.localStorage
|
||||||
} catch (e) {
|
} catch (_e) {
|
||||||
if (import.meta.env?.MODE !== 'production') {
|
if (import.meta.env?.MODE !== 'production') {
|
||||||
if (typeof window !== 'undefined') {
|
if (typeof window !== 'undefined') {
|
||||||
console.warn(e)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return undefined
|
return undefined
|
||||||
@ -58,18 +59,14 @@ export function createSuperjsonStorage<Value>(
|
|||||||
}
|
}
|
||||||
return parse(str) as never
|
return parse(str) as never
|
||||||
},
|
},
|
||||||
setItem: (key, newValue) =>
|
setItem: (key, newValue) => getStringStorage()?.setItem(key, superjson.stringify(newValue)),
|
||||||
getStringStorage()?.setItem(
|
removeItem: key => getStringStorage()?.removeItem(key),
|
||||||
key,
|
|
||||||
superjson.stringify(newValue),
|
|
||||||
),
|
|
||||||
removeItem: (key) => getStringStorage()?.removeItem(key),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const createHandleSubscribe =
|
const createHandleSubscribe =
|
||||||
(subscriber: StringSubscribe): Subscribe<Value> =>
|
(subscriber: StringSubscribe): Subscribe<Value> =>
|
||||||
(key, callback, initialValue) =>
|
(key, callback, initialValue) =>
|
||||||
subscriber(key, (v) => {
|
subscriber(key, v => {
|
||||||
let newValue: Value
|
let newValue: Value
|
||||||
try {
|
try {
|
||||||
newValue = superjson.parse(v || '')
|
newValue = superjson.parse(v || '')
|
||||||
|
|||||||
@ -21,13 +21,7 @@
|
|||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
"jsx": "react-jsx"
|
"jsx": "react-jsx"
|
||||||
},
|
},
|
||||||
"include": [
|
"include": ["src", "app", "index"],
|
||||||
"src",
|
"exclude": ["node_modules"],
|
||||||
"app",
|
|
||||||
"index",
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"node_modules",
|
|
||||||
],
|
|
||||||
"references": [{ "path": "./tsconfig.node.json" }]
|
"references": [{ "path": "./tsconfig.node.json" }]
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,4 +7,3 @@
|
|||||||
},
|
},
|
||||||
"include": ["vite.config.ts"]
|
"include": ["vite.config.ts"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,10 +1,12 @@
|
|||||||
import { defineConfig } from 'vite'
|
// ignore the type error onthe next line
|
||||||
|
// @ts-ignore
|
||||||
|
import tailwindcss from '@tailwindcss/vite'
|
||||||
import react from '@vitejs/plugin-react'
|
import react from '@vitejs/plugin-react'
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
|
import { defineConfig } from 'vite'
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
plugins: [react()],
|
plugins: [react(), tailwindcss()],
|
||||||
resolve: {
|
resolve: {
|
||||||
alias: {
|
alias: {
|
||||||
'@': path.resolve(__dirname, './src'),
|
'@': path.resolve(__dirname, './src'),
|
||||||
@ -14,12 +16,12 @@ export default defineConfig({
|
|||||||
proxy: {
|
proxy: {
|
||||||
// with options
|
// with options
|
||||||
'/lifeto': {
|
'/lifeto': {
|
||||||
target: "https://beta.lifeto.co/",
|
target: 'https://beta.lifeto.co/',
|
||||||
changeOrigin: true,
|
changeOrigin: true,
|
||||||
rewrite: (path) => path.replace(/^\/lifeto/, ''),
|
rewrite: path => path.replace(/^\/lifeto/, ''),
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user