rule book ui
This commit is contained in:
@@ -8,7 +8,15 @@ export type Character = CharacterResponse
|
||||
export const useCharactersStore = defineStore('characters', () => {
|
||||
const characters = ref<Character[]>([]);
|
||||
|
||||
const findById = (characterId: number): Character | undefined => characters.value.find(c => c.characterId === characterId);
|
||||
const findById = async (characterId: number): Promise<Character | undefined> => {
|
||||
let character = characters.value.find(c => c.characterId === characterId);
|
||||
|
||||
if (!character) {
|
||||
await refresh(); // TODO call api instead of refresh
|
||||
character = characters.value.find(c => c.characterId === characterId);
|
||||
}
|
||||
return character;
|
||||
}
|
||||
|
||||
const refresh = () => characterControllerApi.getCharacters().then(response => characters.value = response.data);
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ export const percentFormater = new Intl.NumberFormat("en-US", {
|
||||
maximumFractionDigits: 0
|
||||
});
|
||||
|
||||
|
||||
const timeFormat = new Intl.NumberFormat("en-US", {
|
||||
minimumFractionDigits: 0,
|
||||
maximumFractionDigits: 0,
|
||||
|
||||
@@ -83,8 +83,8 @@ export interface RuleBookResponse {
|
||||
}
|
||||
export interface RuleResponse {
|
||||
'rate': RuleResponseRateEnum;
|
||||
'fromLedgerId': string;
|
||||
'toLedgerId': string;
|
||||
'fromLedgerId'?: string;
|
||||
'toLedgerId'?: string;
|
||||
}
|
||||
|
||||
export const RuleResponseRateEnum = {
|
||||
@@ -736,7 +736,7 @@ export const RuleBookControllerApiAxiosParamCreator = function (configuration?:
|
||||
findByCharacterId: async (characterId: number, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||
// verify required parameter 'characterId' is not null or undefined
|
||||
assertParamExists('findByCharacterId', 'characterId', characterId)
|
||||
const localVarPath = `/rule-books/{characterId}`
|
||||
const localVarPath = `/characters/{characterId}/rule-book`
|
||||
.replace('{characterId}', encodeURIComponent(String(characterId)));
|
||||
// use dummy base URL string because the URL constructor only accepts absolute URLs.
|
||||
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
|
||||
|
||||
@@ -6,6 +6,7 @@ import {isCombined, Ledger, LedgerType, LedgerTypes, useLedgersStore} from "./le
|
||||
import {Modal} from "@/components";
|
||||
import LedgerLabel from "./LedgerLabel.vue";
|
||||
import {PlusIcon, TrashIcon} from '@heroicons/vue/24/outline';
|
||||
import LedgerSelect from "@/ledger/LedgerSelect.vue";
|
||||
|
||||
interface Props {
|
||||
ledgerId?: string;
|
||||
@@ -119,9 +120,7 @@ defineExpose({ open });
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="availableLedgers.length" class="flex">
|
||||
<select v-model="selectedLedger" class="grow">
|
||||
<option v-for="ledger in availableLedgers" :key="ledger.ledgerId" :value="ledger">{{ ledger.name }}</option>
|
||||
</select>
|
||||
<LedgerSelect v-model="selectedLedger" class="grow" :ledgers="availableLedgers" />
|
||||
<div class="flex justify-end me-4 ms-2">
|
||||
<button class="btn-icon" @click="addMember"><PlusIcon /></button>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
<script setup lang="ts">
|
||||
import {Ledger, useLedgersStore} from "@/ledger/ledger.ts";
|
||||
import {storeToRefs} from "pinia";
|
||||
import {computed} from "vue";
|
||||
|
||||
interface Props {
|
||||
ledgers?: Ledger[];
|
||||
}
|
||||
|
||||
const props = defineProps<Props>()
|
||||
const ledger = defineModel<Ledger>();
|
||||
const {ledgers: allLedgers} = storeToRefs(useLedgersStore());
|
||||
|
||||
const ledgersToUse = computed(() => props.ledgers || allLedgers);
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<select v-model="ledger">
|
||||
<option v-for="ledger in ledgersToUse" :key="ledger.ledgerId" :value="ledger">{{ ledger.name }}</option>
|
||||
</select>
|
||||
</template>
|
||||
@@ -1,4 +1,5 @@
|
||||
export * from './ledger';
|
||||
|
||||
export {default as LedgerLabel} from './LedgerLabel.vue';
|
||||
export {default as LedgerSelect} from './LedgerSelect.vue';
|
||||
export {default as CreateLedgerModal} from './CreateLedgerModal.vue';
|
||||
@@ -1,6 +1,6 @@
|
||||
import {logResource} from "@/service";
|
||||
import axios from "axios";
|
||||
import {CharacterControllerApi, LedgerControllerApi} from "@/generated/mammon";
|
||||
import {CharacterControllerApi, LedgerControllerApi, RuleBookControllerApi} from "@/generated/mammon";
|
||||
|
||||
export const mammonUrl = import.meta.env.VITE_MAMMON_URL;
|
||||
export const mammonAddCharacterUrl = mammonUrl + "oauth2/authorization/esi"
|
||||
@@ -16,3 +16,4 @@ logResource(mammonAxiosInstance)
|
||||
|
||||
export const ledgerControllerApi = new LedgerControllerApi(undefined, mammonUrl, mammonAxiosInstance);
|
||||
export const characterControllerApi = new CharacterControllerApi(undefined, mammonUrl, mammonAxiosInstance);
|
||||
export const ruleBookControllerApi = new RuleBookControllerApi(undefined, mammonUrl, mammonAxiosInstance);
|
||||
|
||||
@@ -1,18 +1,28 @@
|
||||
<script setup lang="ts">
|
||||
import {Character, CharacterLabel, useCharactersStore} from "@/characters";
|
||||
import {useRoute} from "vue-router";
|
||||
import {ref, watch} from "vue";
|
||||
import {ref, watch, watchEffect} from "vue";
|
||||
import log from "loglevel";
|
||||
import {activityTypes, findByCharacterId, RuleBook, RuleSetInput} from "@/rules";
|
||||
|
||||
const {findById} = useCharactersStore();
|
||||
|
||||
const {findById: findCharacterById} = useCharactersStore();
|
||||
const character = ref<Character>();
|
||||
|
||||
const ruleBook = ref<RuleBook>();
|
||||
|
||||
watchEffect(async () => {
|
||||
const characterId = character.value?.characterId;
|
||||
|
||||
if (characterId) {
|
||||
ruleBook.value = await findByCharacterId(characterId);
|
||||
}
|
||||
});
|
||||
|
||||
watch(useRoute(), async route => {
|
||||
if (route.params.characterId) {
|
||||
const id = parseInt(typeof route.params.characterId === 'string' ? route.params.characterId : route.params.characterId[0]);
|
||||
|
||||
character.value = findById(id);
|
||||
character.value = await findCharacterById(id);
|
||||
log.info('Loaded character:', character.value);
|
||||
} else {
|
||||
character.value = undefined;
|
||||
@@ -23,8 +33,14 @@ watch(useRoute(), async route => {
|
||||
|
||||
<template>
|
||||
<div v-if="character" class="grid mb-2 mt-4">
|
||||
<div class="mb-4 border-b-1 flex">
|
||||
<CharacterLabel class="flex grow mb-2" :character="character" size="128" />
|
||||
<div class="mb-2 border-b-1 flex">
|
||||
<CharacterLabel class="flex grow mb-2" :character="character" :size="64" />
|
||||
</div>
|
||||
<div v-if="ruleBook" class="flex-col">
|
||||
<div class="flex-col grow border-b-1" v-for="activityType in activityTypes" :key="activityType">
|
||||
<span>{{ activityType }}</span>
|
||||
<RuleSetInput v-model="ruleBook.ruleSets[activityType]" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
+1
-1
@@ -10,7 +10,7 @@ export const routes: RouteRecordRaw[] = [
|
||||
|
||||
{path: '/rules', component: () => import('@/pages/Rules.vue'), children: [
|
||||
{path: '', component: () => import('./pages/rules/ListRuleBooks.vue')},
|
||||
{path: ':characterId', name: 'character-rulebook', component: () => import('@/pages/rules/EditRuleBook.vue')},
|
||||
{path: '/characters/:characterId/rule-book', name: 'character-rulebook', component: () => import('@/pages/rules/EditRuleBook.vue')},
|
||||
]},
|
||||
|
||||
{path: '/market', component: () => import('@/pages/Market.vue'), children: [
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import {RuleResponse, RuleResponseRateEnum} from "@/generated/mammon";
|
||||
import {computed} from "vue";
|
||||
import {isMain, Ledger, LedgerSelect, useLedgersStore} from "@/ledger";
|
||||
|
||||
const rule = defineModel<RuleResponse>();
|
||||
|
||||
const ledgersStore = useLedgersStore();
|
||||
const {findById} = ledgersStore;
|
||||
const ledgers = computed(() => ledgersStore.ledgers.filter(isMain));
|
||||
|
||||
const ledgerComputed = (key: 'fromLedgerId' | 'toLedgerId') => computed<Ledger | undefined>({
|
||||
get: () => rule.value && rule.value[key] ? findById(rule.value[key]) : undefined,
|
||||
set: value => {
|
||||
if (value) {
|
||||
rule.value = {...rule.value, [key]: value.ledgerId}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
const fromLedger = ledgerComputed('fromLedgerId')
|
||||
const toLedger = ledgerComputed('toLedgerId')
|
||||
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<select class="me-2 grow" v-model="rule.rate">
|
||||
<option v-for="rateType in RuleResponseRateEnum" :key="rateType" :value="rateType">{{ rateType }}</option>
|
||||
</select>
|
||||
<LedgerSelect class="me-2 grow" v-model="fromLedger" :ledgers="ledgers" />
|
||||
<LedgerSelect class="me-2 grow" v-model="toLedger" :ledgers="ledgers" />
|
||||
</template>
|
||||
|
||||
<style scoped>
|
||||
|
||||
</style>
|
||||
@@ -0,0 +1,40 @@
|
||||
<script setup lang="ts">
|
||||
|
||||
import {RuleResponse, RuleResponseRateEnum, RuleSetResponse} from "@/generated/mammon";
|
||||
import RuleInput from "@/rules/RuleInput.vue";
|
||||
import {computed} from "vue";
|
||||
import {PlusIcon, TrashIcon} from '@heroicons/vue/24/outline';
|
||||
|
||||
const ruleSet = defineModel<RuleSetResponse>();
|
||||
const rules = computed<RuleResponse[]>({
|
||||
get: () => ruleSet.value && ruleSet.value.rules ? ruleSet.value.rules : [],
|
||||
set: value => ruleSet.value = {rules: value}
|
||||
})
|
||||
|
||||
const addRule = () => {
|
||||
rules.value = [...rules.value, {rate: RuleResponseRateEnum.None}]
|
||||
}
|
||||
|
||||
const setRule = (index: number, rule?: RuleResponse) => {
|
||||
if (!rule) {
|
||||
return;
|
||||
}
|
||||
rules.value = rules.value.with(index, rule)
|
||||
}
|
||||
|
||||
const removeRule = (index: number) => {
|
||||
rules.value = rules.value.toSpliced(index, 1)
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="flex-col">
|
||||
<div class="flex items-end gap-2 mt-2" v-for="(rule, index) in rules" :key="index">
|
||||
<RuleInput :modelValue="rule" @update:modelValue="v => setRule(index, v)" />
|
||||
<button class="btn-icon" @click="removeRule(index)"><TrashIcon /></button>
|
||||
</div>
|
||||
<div class="flex justify-end mb-2 mt-2">
|
||||
<button class="btn-icon" @click="addRule"><PlusIcon /></button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
@@ -0,0 +1,3 @@
|
||||
export * from "./rules";
|
||||
|
||||
export {default as RuleSetInput} from './RuleSetInput.vue';
|
||||
@@ -0,0 +1,16 @@
|
||||
import {ruleBookControllerApi} from "@/mammon";
|
||||
import {RuleBookResponse, RuleSetResponse} from "@/generated/mammon";
|
||||
|
||||
export const activityTypes = {
|
||||
itemBought: "ITEM_BOUGHT",
|
||||
itemSold: "ITEM_SOLD",
|
||||
bountyEarned: "BOUNTY_EARNED",
|
||||
itemManufactured: "ITEM_MANUFACTURED"
|
||||
} as const;
|
||||
|
||||
export type ActivityType = typeof activityTypes[keyof typeof activityTypes];
|
||||
export type RuleBook = RuleBookResponse & { ruleSets: { [key: ActivityType]: RuleSetResponse; } }
|
||||
|
||||
export const findByCharacterId = (characterId: number): Promise<RuleBook> => ruleBookControllerApi.findByCharacterId(characterId)
|
||||
.then(response => response.data)
|
||||
.catch(() => ({characterId, ruleSets: {}}));
|
||||
+1
-1
@@ -1 +1 @@
|
||||
export const copyToClipboard = (s: string) => navigator.clipboard.writeText(s);
|
||||
export const copyToClipboard = (s: string) => navigator.clipboard.writeText(s);
|
||||
|
||||
Reference in New Issue
Block a user