Compare commits
4
Commits
dadcf97bec
...
55c2628c75
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
55c2628c75 | ||
|
|
75d1d5f7fa | ||
|
|
2622d9f01e | ||
|
|
a7407b8e06 |
@@ -0,0 +1,110 @@
|
||||
import log from "loglevel";
|
||||
import {getAccessToken} from "@/auth/token";
|
||||
import {mammonUrl, refreshAccessToken} from "@/mammon";
|
||||
|
||||
const STREAM_URL = mammonUrl + "activities/processed";
|
||||
const RECONNECT_DELAY_MILLIS = 3_000;
|
||||
const FRAME_SEPARATOR = "\n\n";
|
||||
const PROCESSED_EVENT = "event:processed";
|
||||
|
||||
const listeners = new Set<() => void>();
|
||||
|
||||
let controller: AbortController | undefined;
|
||||
let reconnectTimer: ReturnType<typeof setTimeout> | undefined;
|
||||
|
||||
const notifyProcessed = () => listeners.forEach(listener => listener());
|
||||
|
||||
const scheduleReconnect = () => {
|
||||
if (listeners.size === 0) {
|
||||
return;
|
||||
}
|
||||
reconnectTimer = setTimeout(() => connect(), RECONNECT_DELAY_MILLIS);
|
||||
};
|
||||
|
||||
const consume = async (body: ReadableStream<Uint8Array>) => {
|
||||
const reader = body.getReader();
|
||||
const decoder = new TextDecoder();
|
||||
let buffer = "";
|
||||
|
||||
for (; ;) {
|
||||
const {value, done} = await reader.read();
|
||||
|
||||
if (done) {
|
||||
return;
|
||||
}
|
||||
buffer += decoder.decode(value, {stream: true});
|
||||
|
||||
let boundary = buffer.indexOf(FRAME_SEPARATOR);
|
||||
|
||||
while (boundary !== -1) {
|
||||
const frame = buffer.slice(0, boundary);
|
||||
buffer = buffer.slice(boundary + FRAME_SEPARATOR.length);
|
||||
|
||||
if (frame.split("\n").some(line => line.trim() === PROCESSED_EVENT)) {
|
||||
notifyProcessed();
|
||||
}
|
||||
boundary = buffer.indexOf(FRAME_SEPARATOR);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const connect = async (retried = false): Promise<void> => {
|
||||
if (listeners.size === 0) {
|
||||
return;
|
||||
}
|
||||
const signal = controller?.signal;
|
||||
const token = getAccessToken();
|
||||
|
||||
try {
|
||||
const response = await fetch(STREAM_URL, {
|
||||
headers: {
|
||||
Accept: "text/event-stream",
|
||||
...(token ? {Authorization: `Bearer ${token}`} : {}),
|
||||
},
|
||||
signal,
|
||||
});
|
||||
|
||||
if (response.status === 401) {
|
||||
if (!retried && await refreshAccessToken() && listeners.size > 0) {
|
||||
return connect(true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!response.ok || !response.body) {
|
||||
throw new Error(`Activity processing SSE stream failed with ${response.status}`);
|
||||
}
|
||||
await consume(response.body);
|
||||
scheduleReconnect();
|
||||
} catch (error) {
|
||||
if (listeners.size === 0 || signal?.aborted) {
|
||||
return;
|
||||
}
|
||||
log.debug("Activity processing SSE error, reconnecting", error);
|
||||
scheduleReconnect();
|
||||
}
|
||||
};
|
||||
|
||||
const close = () => {
|
||||
if (reconnectTimer) {
|
||||
clearTimeout(reconnectTimer);
|
||||
reconnectTimer = undefined;
|
||||
}
|
||||
controller?.abort();
|
||||
controller = undefined;
|
||||
};
|
||||
|
||||
export const onActivitiesProcessed = (listener: () => void): (() => void) => {
|
||||
listeners.add(listener);
|
||||
|
||||
if (!controller) {
|
||||
controller = new AbortController();
|
||||
connect();
|
||||
}
|
||||
|
||||
return () => {
|
||||
if (listeners.delete(listener) && listeners.size === 0) {
|
||||
close();
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -1 +1,4 @@
|
||||
export {default as SourceLabel} from './SourceLabel.vue';
|
||||
export {onActivitiesProcessed} from './activitiesProcessed';
|
||||
export {useActivitiesProcessed} from './useActivitiesProcessed';
|
||||
export {useProcessedResource} from './useProcessedResource';
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import {onUnmounted} from "vue";
|
||||
import {onActivitiesProcessed} from "./activitiesProcessed";
|
||||
|
||||
export const useActivitiesProcessed = (listener: () => void): (() => void) => {
|
||||
const unsubscribe = onActivitiesProcessed(listener);
|
||||
onUnmounted(unsubscribe);
|
||||
return unsubscribe;
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
import {ref, type Ref, watchEffect} from "vue";
|
||||
import {useActivitiesProcessed} from "./useActivitiesProcessed";
|
||||
|
||||
export const useProcessedResource = <T>(loader: () => Promise<T>, initial: T): Ref<T> => {
|
||||
const data = ref(initial) as Ref<T>;
|
||||
|
||||
const load = async () => {
|
||||
data.value = await loader();
|
||||
};
|
||||
|
||||
watchEffect(load);
|
||||
useActivitiesProcessed(load);
|
||||
|
||||
return data;
|
||||
};
|
||||
@@ -24,5 +24,5 @@ export const useCharactersStore = defineStore('characters', () => {
|
||||
|
||||
refresh();
|
||||
|
||||
return {characters, findById, reloadActivities, refresh};
|
||||
return {characters, findById, reloadActivities};
|
||||
})
|
||||
@@ -37,7 +37,7 @@ describe('useSort', () => {
|
||||
})
|
||||
|
||||
test('Hides ignored columns', () => {
|
||||
const { showColumn } = useSort(array, { ignoredColums: ['key1'] })
|
||||
const { showColumn } = useSort(array, { ignoredColumns: ['key1'] })
|
||||
|
||||
expect(showColumn('key1')).toBe(false)
|
||||
})
|
||||
|
||||
@@ -5,7 +5,7 @@ export type SortDirection = "asc" | "desc";
|
||||
export type UseSortOptions = {
|
||||
defaultSortKey?: string;
|
||||
defaultSortDirection?: SortDirection;
|
||||
ignoredColums?: MaybeRefOrGetter<string[]>;
|
||||
ignoredColumns?: MaybeRefOrGetter<string[]>;
|
||||
headerComponent?: HeaderComponent;
|
||||
};
|
||||
|
||||
@@ -16,7 +16,7 @@ export const useSort = <T>(array: MaybeRefOrGetter<T[]>, options?: UseSortOption
|
||||
sortKey.value = key;
|
||||
sortDirection.value = direction;
|
||||
};
|
||||
const showColumn = (sortKey: string) => !toValue(options?.ignoredColums)?.includes(sortKey);
|
||||
const showColumn = (sortKey: string) => !toValue(options?.ignoredColumns)?.includes(sortKey);
|
||||
const headerProps = computed(() => ({
|
||||
onSort: sortBy,
|
||||
showColumn,
|
||||
|
||||
@@ -13,6 +13,7 @@ import {defineStore} from "pinia";
|
||||
import {computed, ref, triggerRef} from "vue";
|
||||
import {ledgerApi, transactionApi} from "@/mammon";
|
||||
import {useRouteParams} from "@vueuse/router";
|
||||
import {onActivitiesProcessed} from "@/activity";
|
||||
|
||||
export const LedgerTypes = {
|
||||
Main: 'MAIN',
|
||||
@@ -71,7 +72,9 @@ export const useLedgersStore = defineStore('ledgers', () => {
|
||||
|
||||
refresh();
|
||||
|
||||
return {ledgers, findById, findAllById, createMain, createCombined, updateMain, updateCombined, refresh};
|
||||
onActivitiesProcessed(refresh);
|
||||
|
||||
return {ledgers, findById, findAllById, createMain, createCombined, updateMain, updateCombined};
|
||||
})
|
||||
|
||||
const getLedgerId = (ledger: Ledger | string): string => typeof ledger == 'string' ? ledger : ledger.ledgerId;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<script setup lang="ts">
|
||||
import {SliderCheckbox} from '@/components';
|
||||
import {SortableHeader, useSort, VirtualScrollTable} from '@/components/table';
|
||||
import {MarketType, MarketTypeLabel, TaxInput, useMarketOrdersStore, useMarketTaxStore} from "@/market";
|
||||
import {getListedSellTypeIds, MarketType, MarketTypeLabel, TaxInput, useMarketTaxStore} from "@/market";
|
||||
import {MinusIcon, PlusIcon} from '@heroicons/vue/24/outline';
|
||||
import {useStorage} from '@vueuse/core';
|
||||
import {computedAsync, useStorage} from '@vueuse/core';
|
||||
import {computed, ref} from 'vue';
|
||||
import {AcquiredType} from './AcquiredType';
|
||||
import AcquisitionQuartilesTooltip from './AcquisitionQuartilesTooltip.vue';
|
||||
@@ -31,7 +31,7 @@ interface Props {
|
||||
items?: AcquiredType[];
|
||||
infoOnly?: boolean;
|
||||
showAll?: boolean;
|
||||
ignoredColums?: string[] | string;
|
||||
ignoredColumns?: string[] | string;
|
||||
defaultSortKey?: string;
|
||||
}
|
||||
|
||||
@@ -44,36 +44,37 @@ const props = withDefaults(defineProps<Props>(), {
|
||||
items: () => [],
|
||||
infoOnly: false,
|
||||
showAll: false,
|
||||
ignoredColums: () => [],
|
||||
ignoredColumns: () => [],
|
||||
defaultSortKey: 'precentProfit',
|
||||
});
|
||||
defineEmits<Emits>();
|
||||
|
||||
const columnsToIgnore = computed(() => {
|
||||
const ignoredColums = typeof props.ignoredColums === 'string' ? [props.ignoredColums] : [...props.ignoredColums];
|
||||
const ignoredColumns = typeof props.ignoredColumns === 'string' ? [props.ignoredColumns] : [...props.ignoredColumns];
|
||||
|
||||
if (props.infoOnly && !ignoredColums.includes('buttons')) {
|
||||
ignoredColums.push('buttons');
|
||||
if (props.infoOnly && !ignoredColumns.includes('buttons')) {
|
||||
ignoredColumns.push('buttons');
|
||||
}
|
||||
if (!props.showAll && !ignoredColums.includes('ledger')) {
|
||||
ignoredColums.push('ledger');
|
||||
if (!props.showAll && !ignoredColumns.includes('ledger')) {
|
||||
ignoredColumns.push('ledger');
|
||||
}
|
||||
if (ignoredColums.includes('ledger')) {
|
||||
ignoredColums.push('ledgerName');
|
||||
if (ignoredColumns.includes('ledger')) {
|
||||
ignoredColumns.push('ledgerName');
|
||||
}
|
||||
return ignoredColums;
|
||||
return ignoredColumns;
|
||||
});
|
||||
|
||||
const marketTaxStore = useMarketTaxStore();
|
||||
const ledgersStore = useLedgersStore();
|
||||
const marketOrdersStore = useMarketOrdersStore();
|
||||
|
||||
const listedTypeIds = computedAsync(getListedSellTypeIds, new Set<number>());
|
||||
|
||||
const threshold = useStorage('market-acquisition-threshold', 10);
|
||||
const filter = ref("");
|
||||
const unlistedOnly = ref(false);
|
||||
const matchesFilter = (r: AcquiredType) =>
|
||||
r.type.name.toLowerCase().includes(filter.value.toLowerCase())
|
||||
&& (!unlistedOnly.value || !marketOrdersStore.listedTypeIds.has(r.type.id));
|
||||
&& (!unlistedOnly.value || !listedTypeIds.value.has(r.type.id));
|
||||
const { sortedArray, headerProps, showColumn } = useSort<Result>(computed(() => {
|
||||
const filteredItems = props.items.filter(matchesFilter);
|
||||
|
||||
@@ -135,7 +136,7 @@ const { sortedArray, headerProps, showColumn } = useSort<Result>(computed(() =>
|
||||
}), {
|
||||
defaultSortKey: props.defaultSortKey,
|
||||
defaultSortDirection: 'desc',
|
||||
ignoredColums: columnsToIgnore
|
||||
ignoredColumns: columnsToIgnore
|
||||
})
|
||||
const getLineColor = (result: Result) => {
|
||||
if (result.precentProfit >= (threshold.value / 100)) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<script setup lang="ts">
|
||||
import {getMarketTypes, MarketTypePrice, useApraisalStore} from "@/market";
|
||||
import {getMarketTypes, MarketTypePrice, useAppraisalStore} from "@/market";
|
||||
import {ref, watch} from 'vue';
|
||||
import {AcquiredType} from './AcquiredType';
|
||||
import {RawAcquiredType} from './acquisition';
|
||||
@@ -9,7 +9,7 @@ import SellModal from './SellModal.vue';
|
||||
|
||||
interface Props {
|
||||
items: RawAcquiredType[];
|
||||
ignoredColums?: string[] | string;
|
||||
ignoredColumns?: string[] | string;
|
||||
ledgerId?: string;
|
||||
}
|
||||
|
||||
@@ -18,17 +18,17 @@ const props = defineProps<Props>();
|
||||
const buyModal = ref<typeof BuyModal>();
|
||||
const sellModal = ref<typeof SellModal>();
|
||||
|
||||
const apraisalStore = useApraisalStore();
|
||||
const appraisalStore = useAppraisalStore();
|
||||
const enriched = ref<AcquiredType[]>([]);
|
||||
|
||||
watch(() => props.items, async itms => {
|
||||
const refresh = async (itms: RawAcquiredType[] = props.items) => {
|
||||
if (itms.length === 0) {
|
||||
enriched.value = [];
|
||||
return;
|
||||
}
|
||||
|
||||
const types = await getMarketTypes([...new Set(itms.map(i => i.type))]);
|
||||
const prices = await apraisalStore.getPrices(types);
|
||||
const prices = await appraisalStore.getPrices(types);
|
||||
|
||||
enriched.value = itms.map(i => {
|
||||
const price = prices.find(p => p.type.id === i.type) as MarketTypePrice;
|
||||
@@ -40,12 +40,16 @@ watch(() => props.items, async itms => {
|
||||
sell: price.sell
|
||||
};
|
||||
});
|
||||
}, {immediate: true});
|
||||
};
|
||||
|
||||
watch(() => props.items, refresh, {immediate: true});
|
||||
|
||||
defineExpose({refresh});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<template v-if="enriched.length > 0">
|
||||
<AcquisitionResultTable :items="enriched" :ignoredColums="ignoredColums" @buy="(types, price, buy, sell) => buyModal?.open(types[0].type, { 'Price': price, 'Buy': buy, 'Sell': sell }, props.ledgerId)" @sell="types => sellModal?.open(types, props.ledgerId)" />
|
||||
<AcquisitionResultTable :items="enriched" :ignoredColumns="ignoredColumns" @buy="(types, price, buy, sell) => buyModal?.open(types[0].type, { 'Price': price, 'Buy': buy, 'Sell': sell }, props.ledgerId)" @sell="types => sellModal?.open(types, props.ledgerId)" />
|
||||
<BuyModal ref="buyModal" />
|
||||
<SellModal ref="sellModal" />
|
||||
</template>
|
||||
|
||||
@@ -2,6 +2,7 @@ import {defineStore} from "pinia";
|
||||
import {computed, ref} from "vue";
|
||||
import {acquisitionApi, activityApi} from "@/mammon";
|
||||
import {AcquisitionResponse, ActivitySourceResponse} from "@/generated/mammon";
|
||||
import {onActivitiesProcessed} from "@/activity";
|
||||
|
||||
export type RawAcquiredType = {
|
||||
id: string;
|
||||
@@ -66,5 +67,7 @@ export const useAcquiredTypesStore = defineStore('market-acquisition', () => {
|
||||
|
||||
refresh();
|
||||
|
||||
return { acquiredTypes: types, addAcquiredType, removeAcquiredType, processNewActivities, refresh };
|
||||
onActivitiesProcessed(refresh);
|
||||
|
||||
return { acquiredTypes: types, addAcquiredType, removeAcquiredType, processNewActivities };
|
||||
});
|
||||
|
||||
@@ -8,7 +8,7 @@ import {getMammonPrices} from './mammon';
|
||||
const CACHE_DURATION = 1000 * 60 * 5; // 5 minutes
|
||||
const BATCH_SIZE = 100;
|
||||
|
||||
export const useApraisalStore = defineStore('appraisal', () => {
|
||||
export const useAppraisalStore = defineStore('appraisal', () => {
|
||||
const cache: RegionalMarketCache<MarketTypePrice> = new RegionalMarketCache(CACHE_DURATION);
|
||||
|
||||
const getPricesUncached = getMammonPrices;
|
||||
|
||||
@@ -1,21 +1,7 @@
|
||||
import {defineStore} from "pinia";
|
||||
import {computed, ref} from "vue";
|
||||
import {marketApi} from "@/mammon";
|
||||
import {MarketOrderResponse, MarketOrderResponseDirectionEnum} from "@/generated/mammon";
|
||||
import {MarketOrderResponseDirectionEnum} from "@/generated/mammon";
|
||||
|
||||
export const useMarketOrdersStore = defineStore('market-orders', () => {
|
||||
const orders = ref<MarketOrderResponse[]>([]);
|
||||
|
||||
const listedTypeIds = computed(() => new Set(
|
||||
orders.value
|
||||
.filter(o => o.direction === MarketOrderResponseDirectionEnum.Sell)
|
||||
.map(o => o.marketTypeId)
|
||||
));
|
||||
|
||||
const refresh = () => marketApi.findAllMarketOrders()
|
||||
.then(response => orders.value = response.data);
|
||||
|
||||
refresh();
|
||||
|
||||
return {orders, listedTypeIds, refresh};
|
||||
});
|
||||
export const getListedSellTypeIds = (): Promise<Set<number>> => marketApi.findAllMarketOrders()
|
||||
.then(response => new Set(response.data
|
||||
.filter(o => o.direction === MarketOrderResponseDirectionEnum.Sell)
|
||||
.map(o => o.marketTypeId)));
|
||||
|
||||
@@ -27,7 +27,7 @@ type Result = {
|
||||
interface Props {
|
||||
items?: ScanResult[];
|
||||
infoOnly?: boolean;
|
||||
ignoredColums?: string[] | string;
|
||||
ignoredColumns?: string[] | string;
|
||||
}
|
||||
|
||||
const scoreFormater = new Intl.NumberFormat("en-US", {
|
||||
@@ -40,7 +40,7 @@ const volumeFormater = new Intl.NumberFormat("en-US", {
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
items: () => [],
|
||||
infoOnly: false,
|
||||
ignoredColums: () => []
|
||||
ignoredColumns: () => []
|
||||
});
|
||||
|
||||
const acquiredTypesStore = useAcquiredTypesStore();
|
||||
@@ -54,7 +54,7 @@ const trackedTrends = useStorage<MarketTrend[]>('market-scan-trends', [
|
||||
MarketTrends.Down,
|
||||
]);
|
||||
const columnsToIgnore = computed(() =>
|
||||
typeof props.ignoredColums === 'string' ? [props.ignoredColums] : props.ignoredColums
|
||||
typeof props.ignoredColumns === 'string' ? [props.ignoredColumns] : props.ignoredColumns
|
||||
);
|
||||
const { sortedArray, headerProps, showColumn } = useSort<Result>(computed(() => props.items
|
||||
.filter(r => r.type.name.toLowerCase().includes(filter.value.toLowerCase()))
|
||||
@@ -82,7 +82,7 @@ const { sortedArray, headerProps, showColumn } = useSort<Result>(computed(() =>
|
||||
}).filter(r => !onlyCheap.value || (r.buy <= r.q1 && r.profit >= (threshold.value / 100)))), {
|
||||
defaultSortKey: 'score',
|
||||
defaultSortDirection: 'desc',
|
||||
ignoredColums: columnsToIgnore
|
||||
ignoredColumns: columnsToIgnore
|
||||
})
|
||||
const getLineColor = (result: Result) => {
|
||||
if (props.infoOnly) {
|
||||
|
||||
@@ -7,19 +7,17 @@ import {IskLabel} from "@/market";
|
||||
import {SortableHeader, useSort, VirtualScrollTable} from "@/components/table";
|
||||
import {TransferList, TransferTypes} from "@/transaction";
|
||||
import {Dropdown} from "@/components";
|
||||
import {SourceLabel} from "@/activity";
|
||||
import {SourceLabel, useProcessedResource} from "@/activity";
|
||||
import {useCharactersStore} from "@/characters";
|
||||
import {formatEveDate} from "@/formaters.ts";
|
||||
|
||||
const {ledgerId} = useLedgerParam();
|
||||
const charactersStore = useCharactersStore();
|
||||
|
||||
const transactions = computedAsync<TransactionResponse[]>(async () => {
|
||||
if (ledgerId.value) {
|
||||
return await findAllTransactionInLeger(ledgerId.value);
|
||||
}
|
||||
return [];
|
||||
}, []);
|
||||
const transactions = useProcessedResource<TransactionResponse[]>(
|
||||
() => ledgerId.value ? findAllTransactionInLeger(ledgerId.value) : Promise.resolve([]),
|
||||
[],
|
||||
);
|
||||
|
||||
const { sortedArray, headerProps } = useSort(computedAsync(() => Promise.all(transactions.value.map(async transaction => {
|
||||
const source = transaction.source;
|
||||
|
||||
@@ -14,7 +14,6 @@ const editLedgerModal = ref<typeof EditLedgerModal>();
|
||||
const processActivities = async () => {
|
||||
await activityApi.fetchAllNewActivities();
|
||||
await activityApi.processNewActivities();
|
||||
await ledgersStore.refresh();
|
||||
}
|
||||
|
||||
const { sortedArray, headerProps } = useSort<Ledger>(() => ledgersStore.ledgers);
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import {AcquisitionsPanel, toAcquiredType} from '@/market/acquisition';
|
||||
import {AcquisitionsPanel, RawAcquiredType, toAcquiredType} from '@/market/acquisition';
|
||||
import {useLedgerParam} from "@/ledger";
|
||||
import {acquisitionApi} from "@/mammon";
|
||||
import {computedAsync} from "@vueuse/core";
|
||||
import {useProcessedResource} from "@/activity";
|
||||
|
||||
const {ledgerId} = useLedgerParam();
|
||||
|
||||
const items = computedAsync(async () => {
|
||||
const items = useProcessedResource<RawAcquiredType[]>(async () => {
|
||||
if (!ledgerId.value) {
|
||||
return [];
|
||||
}
|
||||
@@ -19,6 +19,6 @@ const items = computedAsync(async () => {
|
||||
|
||||
<template>
|
||||
<div class="mt-4">
|
||||
<AcquisitionsPanel :items="items" :ledgerId="ledgerId" :ignoredColums="['date', 'ledger']" />
|
||||
<AcquisitionsPanel :items="items" :ledgerId="ledgerId" :ignoredColumns="['date', 'ledger']" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -4,15 +4,14 @@ import {computedAsync} from "@vueuse/core";
|
||||
import {BalanceResponse} from "@/generated/mammon";
|
||||
import {getMarketType, MarketTypeLabel} from "@/market";
|
||||
import {SortableHeader, useSort, VirtualScrollTable} from "@/components/table";
|
||||
import {useProcessedResource} from "@/activity";
|
||||
|
||||
const {ledgerId} = useLedgerParam();
|
||||
|
||||
const balance = computedAsync<BalanceResponse>(async () => {
|
||||
if (ledgerId.value) {
|
||||
return await getLedgerBalance(ledgerId.value);
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
const balance = useProcessedResource<BalanceResponse | undefined>(
|
||||
() => ledgerId.value ? getLedgerBalance(ledgerId.value) : Promise.resolve(undefined),
|
||||
undefined,
|
||||
);
|
||||
|
||||
const { sortedArray, headerProps } = useSort(computedAsync(async () => {
|
||||
const itemBalances = balance.value?.itemBalances;
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
import {AcquisitionsPanel, useAcquiredTypesStore} from '@/market/acquisition';
|
||||
import {ArrowPathIcon} from '@heroicons/vue/24/outline';
|
||||
import {useAutoRefresh} from '@/composables';
|
||||
import {ref} from 'vue';
|
||||
|
||||
const acquiredTypesStore = useAcquiredTypesStore();
|
||||
const panel = ref<InstanceType<typeof AcquisitionsPanel>>();
|
||||
|
||||
const refresh = async () => {
|
||||
await acquiredTypesStore.refresh();
|
||||
await panel.value?.refresh();
|
||||
}
|
||||
|
||||
const {active: autoRefresh, toggle: toggleAutoRefresh} = useAutoRefresh(refresh, 5 * 60 * 1000);
|
||||
@@ -22,6 +24,6 @@ const {active: autoRefresh, toggle: toggleAutoRefresh} = useAutoRefresh(refresh,
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<AcquisitionsPanel :items="acquiredTypesStore.acquiredTypes" ignoredColums="date" />
|
||||
<AcquisitionsPanel ref="panel" :items="acquiredTypesStore.acquiredTypes" ignoredColumns="date" />
|
||||
</div>
|
||||
</template>
|
||||
@@ -1,6 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import {ClipboardButton} from '@/components';
|
||||
import {getMarketType, MarketType, MarketTypeInput, useApraisalStore, useMarketTaxStore} from "@/market";
|
||||
import {getMarketType, MarketType, MarketTypeInput, useAppraisalStore, useMarketTaxStore} from "@/market";
|
||||
import {AcquisitionResultTable, BuyModal} from '@/market/acquisition';
|
||||
import {ScanResultTable, toScanResult} from '@/market/scan';
|
||||
import {acquisitionApi, marketApi} from "@/mammon";
|
||||
@@ -18,10 +18,10 @@ const router = useRouter();
|
||||
const item = ref<MarketType>();
|
||||
const inputItem = ref<MarketType>();
|
||||
|
||||
const apraisalStore = useApraisalStore();
|
||||
const appraisalStore = useAppraisalStore();
|
||||
const marketTaxStore = useMarketTaxStore();
|
||||
const days = useStorage('market-scan-days', 365);
|
||||
const price = computedAsync(() => item.value ? apraisalStore.getPrice(item.value) : undefined);
|
||||
const price = computedAsync(() => item.value ? appraisalStore.getPrice(item.value) : undefined);
|
||||
const result = computedAsync(async () => {
|
||||
if (!item.value) {
|
||||
return undefined;
|
||||
@@ -107,11 +107,11 @@ watch(useRoute(), async route => {
|
||||
</div>
|
||||
<div v-if="result" class="mb-4">
|
||||
<span>Market Info:</span>
|
||||
<ScanResultTable :items="[result]" infoOnly :ignoredColums="['name', 'acquisitions']" />
|
||||
<ScanResultTable :items="[result]" infoOnly :ignoredColumns="['name', 'acquisitions']" />
|
||||
</div>
|
||||
<div v-if="acquisitions && acquisitions.length > 0">
|
||||
<span>Acquisitions:</span>
|
||||
<AcquisitionResultTable :items="acquisitions" infoOnly showAll :ignoredColums="['name', 'buy', 'sell']" defaultSortKey="date"/>
|
||||
<AcquisitionResultTable :items="acquisitions" infoOnly showAll :ignoredColumns="['name', 'buy', 'sell']" defaultSortKey="date"/>
|
||||
</div>
|
||||
</template>
|
||||
<BuyModal ref="buyModal" />
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ export const useRuleBookStore = defineStore('rule-book', () => {
|
||||
|
||||
refresh();
|
||||
|
||||
return {ruleBook, refresh, update};
|
||||
return {ruleBook, update};
|
||||
})
|
||||
|
||||
export const fetchScriptDefinitions = (): Promise<string> =>
|
||||
|
||||
Reference in New Issue
Block a user