mirror of
https://github.com/Kvan7/Exiled-Exchange-2.git
synced 2025-10-30 14:17:55 +00:00
Fully add support for multiple currencies?
This commit is contained in:
@@ -228,7 +228,7 @@
|
|||||||
"currency_only_chaos": "Chaos Orb",
|
"currency_only_chaos": "Chaos Orb",
|
||||||
"currency_only_div": "Divine Orb",
|
"currency_only_div": "Divine Orb",
|
||||||
"currency_chaos_div": "Both Orbs",
|
"currency_chaos_div": "Both Orbs",
|
||||||
"currency_exalted_div": "Both Orbs",
|
"currency_exalted_div": "Ex/Div Orbs",
|
||||||
"currency_only_exalted": "Exalted Orbs",
|
"currency_only_exalted": "Exalted Orbs",
|
||||||
"ratio_tooltip": "Ratio used for sorting locally\nDefault on trade site is 7.5:1"
|
"ratio_tooltip": "Ratio used for sorting locally\nDefault on trade site is 7.5:1"
|
||||||
},
|
},
|
||||||
|
|||||||
BIN
renderer/public/images/annul.png
Normal file
BIN
renderer/public/images/annul.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.2 KiB |
@@ -28,8 +28,8 @@ export interface CurrencyValue {
|
|||||||
currency: "chaos" | "exalted" | "div";
|
currency: "chaos" | "exalted" | "div";
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CoreCurrency {
|
export interface CoreCurrency {
|
||||||
id: string;
|
id: "exalted" | "chaos";
|
||||||
abbrev: string;
|
abbrev: string;
|
||||||
ref: string;
|
ref: string;
|
||||||
text: string;
|
text: string;
|
||||||
@@ -79,10 +79,20 @@ export const usePoeninja = createGlobalState(() => {
|
|||||||
return listed;
|
return listed;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* core/div
|
||||||
|
*/
|
||||||
const xchgRate = shallowRef<number | undefined>(undefined);
|
const xchgRate = shallowRef<number | undefined>(undefined);
|
||||||
|
/**
|
||||||
|
* Current core currency
|
||||||
|
*/
|
||||||
const xchgRateCurrency = shallowRef<"chaos" | "exalted" | undefined>(
|
const xchgRateCurrency = shallowRef<"chaos" | "exalted" | undefined>(
|
||||||
undefined,
|
undefined,
|
||||||
);
|
);
|
||||||
|
/**
|
||||||
|
* exalted/div
|
||||||
|
*/
|
||||||
|
const exaltXchgRate = shallowRef<number | undefined>(undefined);
|
||||||
|
|
||||||
const isLoading = shallowRef(false);
|
const isLoading = shallowRef(false);
|
||||||
let PRICES_DB: PriceDatabase = [];
|
let PRICES_DB: PriceDatabase = [];
|
||||||
@@ -150,24 +160,24 @@ export const usePoeninja = createGlobalState(() => {
|
|||||||
ns: "ITEM",
|
ns: "ITEM",
|
||||||
name: "Divine Orb",
|
name: "Divine Orb",
|
||||||
});
|
});
|
||||||
const preferred =
|
const preferred = selectedCoreCurrency.value;
|
||||||
AppConfig<PriceCheckWidget>("price-check")!.coreCurrency;
|
|
||||||
|
|
||||||
if (divine && divine.exalted >= 30) {
|
if (divine && divine.exalted >= 30) {
|
||||||
if (preferred === "exalted") {
|
exaltXchgRate.value = divine.exalted;
|
||||||
|
if (!preferred || preferred.id === "exalted") {
|
||||||
xchgRate.value = divine.exalted;
|
xchgRate.value = divine.exalted;
|
||||||
xchgRateCurrency.value = "exalted";
|
xchgRateCurrency.value = "exalted";
|
||||||
} else {
|
} else {
|
||||||
const ex = divine.exalted;
|
const ninjaPreferred = findPriceByQuery({
|
||||||
if (preferred === "chaos") {
|
|
||||||
const chaos = findPriceByQuery({
|
|
||||||
ns: "ITEM",
|
ns: "ITEM",
|
||||||
name: "Chaos Orb",
|
name: preferred.ref,
|
||||||
});
|
});
|
||||||
if (chaos && ex / chaos.exalted >= 5) {
|
if (
|
||||||
xchgRate.value = ex / chaos.exalted;
|
ninjaPreferred &&
|
||||||
xchgRateCurrency.value = "chaos";
|
exaltXchgRate.value / ninjaPreferred.exalted >= 5
|
||||||
}
|
) {
|
||||||
|
xchgRate.value = exaltXchgRate.value / ninjaPreferred.exalted;
|
||||||
|
xchgRateCurrency.value = preferred.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -230,34 +240,69 @@ export const usePoeninja = createGlobalState(() => {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function autoCurrency(value: number | [number, number]): CurrencyValue {
|
/**
|
||||||
|
* Converts item value from exalts to stable or current core currency
|
||||||
|
* @param value item value in exalts
|
||||||
|
* @returns Value in stable or core currency
|
||||||
|
*/
|
||||||
|
function autoCurrency(
|
||||||
|
value: number | [number, number],
|
||||||
|
useOnlyCore: boolean = false,
|
||||||
|
): CurrencyValue {
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
if (value[1] > (xchgRate.value || 9999)) {
|
if (value[1] > (exaltXchgRate.value || 9999) && !useOnlyCore) {
|
||||||
return {
|
return {
|
||||||
min: exaltedToStable(value[0]),
|
min: exaltToStable(value[0]),
|
||||||
max: exaltedToStable(value[1]),
|
max: exaltToStable(value[1]),
|
||||||
currency: "div",
|
currency: "div",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (selectedCoreCurrency.value?.id) {
|
||||||
|
// NOTE: This if should catch everything
|
||||||
|
return {
|
||||||
|
min: exaltToCore(value[0]),
|
||||||
|
max: exaltToCore(value[1]),
|
||||||
|
currency: selectedCoreCurrency.value.id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// this should never run, assuming we have loaded a currency
|
||||||
return { min: value[0], max: value[1], currency: "exalted" };
|
return { min: value[0], max: value[1], currency: "exalted" };
|
||||||
}
|
}
|
||||||
if (value > (xchgRate.value || 9999) * 0.94) {
|
if (value > (exaltXchgRate.value || 9999) * 0.94 && !useOnlyCore) {
|
||||||
if (value < (xchgRate.value || 9999) * 1.06) {
|
if (value < (exaltXchgRate.value || 9999) * 1.06) {
|
||||||
return { min: 1, max: 1, currency: "div" };
|
return { min: 1, max: 1, currency: "div" };
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
min: exaltedToStable(value),
|
min: exaltToStable(value),
|
||||||
max: exaltedToStable(value),
|
max: exaltToStable(value),
|
||||||
currency: "div",
|
currency: "div",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (selectedCoreCurrency.value?.id) {
|
||||||
|
// NOTE: This if should catch everything
|
||||||
|
return {
|
||||||
|
min: exaltToCore(value),
|
||||||
|
max: exaltToCore(value),
|
||||||
|
currency: selectedCoreCurrency.value.id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// this should never run, assuming we have loaded a currency
|
||||||
return { min: value, max: value, currency: "exalted" };
|
return { min: value, max: value, currency: "exalted" };
|
||||||
}
|
}
|
||||||
|
|
||||||
function exaltedToStable(count: number) {
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
function coreToStable(count: number) {
|
||||||
return count / (xchgRate.value || 9999);
|
return count / (xchgRate.value || 9999);
|
||||||
}
|
}
|
||||||
|
function exaltToStable(count: number) {
|
||||||
|
return count / (exaltXchgRate.value || 9999);
|
||||||
|
}
|
||||||
|
function exaltToCore(count: number) {
|
||||||
|
// ex -> core
|
||||||
|
// ex => ex * (div/ex) * (core/div) = core
|
||||||
|
return (count / (exaltXchgRate.value || 9999)) * (xchgRate.value || 9999);
|
||||||
|
}
|
||||||
|
|
||||||
function cachedCurrencyByQuery(query: DbQuery, count: number) {
|
function cachedCurrencyByQuery(query: DbQuery, count: number) {
|
||||||
const key = { ns: query.ns, name: query.name, count };
|
const key = { ns: query.ns, name: query.name, count };
|
||||||
@@ -265,7 +310,8 @@ export const usePoeninja = createGlobalState(() => {
|
|||||||
return priceCache.get(key)!;
|
return priceCache.get(key)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
const price = findPriceByQuery(query);
|
const price = // since ex aren't currently in db
|
||||||
|
query.name === "Exalted Orb" ? { exalted: 1 } : findPriceByQuery(query);
|
||||||
if (!price) {
|
if (!price) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,7 +50,7 @@
|
|||||||
:title="title"
|
:title="title"
|
||||||
>
|
>
|
||||||
<ui-popover
|
<ui-popover
|
||||||
v-if="stableOrbCost"
|
v-if="stableOrbCost && xchgRateCurrency?.id"
|
||||||
trigger="click"
|
trigger="click"
|
||||||
boundary="#price-window"
|
boundary="#price-window"
|
||||||
>
|
>
|
||||||
@@ -65,13 +65,14 @@
|
|||||||
:price="{
|
:price="{
|
||||||
min: stableOrbCost,
|
min: stableOrbCost,
|
||||||
max: stableOrbCost,
|
max: stableOrbCost,
|
||||||
currency: 'exalted',
|
currency: xchgRateCurrency.id,
|
||||||
}"
|
}"
|
||||||
item-img="/images/divine.png"
|
item-img="/images/divine.png"
|
||||||
/>
|
/>
|
||||||
<div v-for="i in 9" :key="i">
|
<div v-for="i in 9" :key="i">
|
||||||
<div class="pl-1">
|
<div class="pl-1">
|
||||||
{{ i / 10 }} div ⇒ {{ Math.round((stableOrbCost * i) / 10) }} c
|
{{ i / 10 }} div ⇒ {{ Math.round((stableOrbCost * i) / 10) }}
|
||||||
|
{{ xchgRateCurrency.abbrev }}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
@@ -271,6 +272,7 @@ export default defineComponent({
|
|||||||
const wm = inject<WidgetManager>("wm")!;
|
const wm = inject<WidgetManager>("wm")!;
|
||||||
const {
|
const {
|
||||||
xchgRate,
|
xchgRate,
|
||||||
|
xchgRateCurrency,
|
||||||
initialLoading: xchgRateLoading,
|
initialLoading: xchgRateLoading,
|
||||||
queuePricesFetch,
|
queuePricesFetch,
|
||||||
} = usePoeninja();
|
} = usePoeninja();
|
||||||
@@ -452,6 +454,7 @@ export default defineComponent({
|
|||||||
closePriceCheck,
|
closePriceCheck,
|
||||||
title,
|
title,
|
||||||
stableOrbCost,
|
stableOrbCost,
|
||||||
|
xchgRateCurrency,
|
||||||
xchgRateLoading,
|
xchgRateLoading,
|
||||||
showCheckPos,
|
showCheckPos,
|
||||||
checkPosition,
|
checkPosition,
|
||||||
|
|||||||
@@ -42,14 +42,10 @@ export default defineComponent({
|
|||||||
function getPriceFor(n: number) {
|
function getPriceFor(n: number) {
|
||||||
const one = findPriceByQuery(getDetailsId(props.item)!)!;
|
const one = findPriceByQuery(getDetailsId(props.item)!)!;
|
||||||
|
|
||||||
const price =
|
const price = autoCurrency(
|
||||||
props.item.info.refName === "Divine Orb"
|
n * one.exalted,
|
||||||
? {
|
props.item.info.refName === "Divine Orb",
|
||||||
min: n * one.exalted,
|
);
|
||||||
max: n * one.exalted,
|
|
||||||
currency: "exalted" as const,
|
|
||||||
}
|
|
||||||
: autoCurrency(n * one.exalted);
|
|
||||||
|
|
||||||
return `${displayRounding(price.min)} ${price.currency}`;
|
return `${displayRounding(price.min)} ${price.currency}`;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ const MIN_TTL = 300;
|
|||||||
|
|
||||||
export class Cache {
|
export class Cache {
|
||||||
private cached = new Map<string, unknown>();
|
private cached = new Map<string, unknown>();
|
||||||
|
private currency = "";
|
||||||
|
|
||||||
get<T = unknown>(key: unknown): T | undefined {
|
get<T = unknown>(key: unknown): T | undefined {
|
||||||
const _key = hash.sha1(JSON.parse(JSON.stringify(key)));
|
const _key = hash.sha1(JSON.parse(JSON.stringify(key)));
|
||||||
@@ -20,6 +21,13 @@ export class Cache {
|
|||||||
}, ttl * 1000);
|
}, ttl * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
purgeIfDifferentCurrency(currency: string | undefined) {
|
||||||
|
if (!currency || this.currency === currency) return;
|
||||||
|
this.currency = currency;
|
||||||
|
this.cached.clear();
|
||||||
|
console.log("Purged cache");
|
||||||
|
}
|
||||||
|
|
||||||
static deriveTtl(...limits: RateLimiter[]): number {
|
static deriveTtl(...limits: RateLimiter[]): number {
|
||||||
return Math.max(MIN_TTL, ...limits.map((limit) => limit.window));
|
return Math.max(MIN_TTL, ...limits.map((limit) => limit.window));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -84,9 +84,9 @@
|
|||||||
<ui-radio v-model="filters.trade.currency" value="exalted">{{
|
<ui-radio v-model="filters.trade.currency" value="exalted">{{
|
||||||
t(":currency_only_exalted")
|
t(":currency_only_exalted")
|
||||||
}}</ui-radio>
|
}}</ui-radio>
|
||||||
<!-- <ui-radio v-model="filters.trade.currency" value="chaos">{{
|
<ui-radio v-model="filters.trade.currency" value="chaos">{{
|
||||||
t(":currency_only_chaos")
|
t(":currency_only_chaos")
|
||||||
}}</ui-radio> -->
|
}}</ui-radio>
|
||||||
<ui-radio v-model="filters.trade.currency" value="divine">{{
|
<ui-radio v-model="filters.trade.currency" value="divine">{{
|
||||||
t(":currency_only_div")
|
t(":currency_only_div")
|
||||||
}}</ui-radio>
|
}}</ui-radio>
|
||||||
|
|||||||
@@ -12,16 +12,11 @@
|
|||||||
}"
|
}"
|
||||||
>{{ result.priceAmount }} {{ result.priceCurrency
|
>{{ result.priceAmount }} {{ result.priceCurrency
|
||||||
}}{{
|
}}{{
|
||||||
result.priceCurrency !== "exalted" &&
|
result.normalizedPriceCurrency &&
|
||||||
|
result.priceCurrency !== result.normalizedPriceCurrency.id &&
|
||||||
result.priceCurrency !== "divine" &&
|
result.priceCurrency !== "divine" &&
|
||||||
result.normalizedPrice
|
result.normalizedPrice
|
||||||
? ` (${result.normalizedPrice} ${
|
? ` (${result.normalizedPrice} ${result.normalizedPriceCurrency.abbrev})`
|
||||||
result.normalizedPriceCurrency! === "exalted"
|
|
||||||
? "ex"
|
|
||||||
: result.normalizedPriceCurrency! === "chaos"
|
|
||||||
? "c"
|
|
||||||
: result.normalizedPriceCurrency!
|
|
||||||
})`
|
|
||||||
: ""
|
: ""
|
||||||
}}</span
|
}}</span
|
||||||
>
|
>
|
||||||
@@ -31,18 +26,6 @@
|
|||||||
><span class="font-sans">×</span> {{ result.listedTimes }}</span
|
><span class="font-sans">×</span> {{ result.listedTimes }}</span
|
||||||
><i v-else-if="!result.hasNote" class="fas fa-question" />
|
><i v-else-if="!result.hasNote" class="fas fa-question" />
|
||||||
</td>
|
</td>
|
||||||
<!-- <td class="px-2">
|
|
||||||
<div v-if="result.priceCurrencyRank" class="my-2 flex flex-row">
|
|
||||||
<div
|
|
||||||
v-for="i in result.priceCurrencyRank"
|
|
||||||
class="account-status mr-1"
|
|
||||||
:class="{
|
|
||||||
'rank-2': result.priceCurrencyRank === 2,
|
|
||||||
'rank-3': result.priceCurrencyRank === 3,
|
|
||||||
}"
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</td> -->
|
|
||||||
<td v-if="item.stackSize" class="px-2 text-right">
|
<td v-if="item.stackSize" class="px-2 text-right">
|
||||||
{{ result.stackSize }}
|
{{ result.stackSize }}
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -310,7 +310,13 @@ export interface PricingResult {
|
|||||||
priceCurrency: string;
|
priceCurrency: string;
|
||||||
priceCurrencyRank?: number;
|
priceCurrencyRank?: number;
|
||||||
normalizedPrice?: string;
|
normalizedPrice?: string;
|
||||||
normalizedPriceCurrency?: string;
|
normalizedPriceCurrency?: {
|
||||||
|
id: "exalted" | "chaos";
|
||||||
|
abbrev: string;
|
||||||
|
ref: string;
|
||||||
|
text: string;
|
||||||
|
icon: string;
|
||||||
|
};
|
||||||
isMine: boolean;
|
isMine: boolean;
|
||||||
hasNote: boolean;
|
hasNote: boolean;
|
||||||
isInstantBuyout: boolean;
|
isInstantBuyout: boolean;
|
||||||
@@ -953,8 +959,11 @@ export async function requestResults(
|
|||||||
resultIds: string[],
|
resultIds: string[],
|
||||||
opts: { accountName: string },
|
opts: { accountName: string },
|
||||||
): Promise<PricingResult[]> {
|
): Promise<PricingResult[]> {
|
||||||
|
const { cachedCurrencyByQuery, xchgRateCurrency } = usePoeninja();
|
||||||
|
// Solves cached results showing random incorrect values
|
||||||
|
cache.purgeIfDifferentCurrency(xchgRateCurrency.value?.id);
|
||||||
|
|
||||||
let data = cache.get<FetchResult[]>(resultIds);
|
let data = cache.get<FetchResult[]>(resultIds);
|
||||||
const { cachedCurrencyByQuery } = usePoeninja();
|
|
||||||
|
|
||||||
if (!data) {
|
if (!data) {
|
||||||
await RateLimiter.waitMulti(RATE_LIMIT_RULES.FETCH);
|
await RateLimiter.waitMulti(RATE_LIMIT_RULES.FETCH);
|
||||||
@@ -1053,21 +1062,15 @@ export async function requestResults(
|
|||||||
const query = getCurrencyDetailsId(
|
const query = getCurrencyDetailsId(
|
||||||
result.listing.price?.currency ?? "no price",
|
result.listing.price?.currency ?? "no price",
|
||||||
);
|
);
|
||||||
const normalizedCurrency =
|
const normalizedCurrency = cachedCurrencyByQuery(
|
||||||
result.listing.price?.currency === "exalted"
|
query,
|
||||||
? // exalts aren't in db since they are the stable currency
|
result.listing.price?.amount ?? 0,
|
||||||
{
|
);
|
||||||
min: result.listing.price.amount,
|
|
||||||
max: result.listing.price.amount,
|
|
||||||
currency: "exalted",
|
|
||||||
}
|
|
||||||
: // otherwise convert to stable
|
|
||||||
cachedCurrencyByQuery(query, result.listing.price?.amount ?? 0);
|
|
||||||
const normalizedPrice =
|
const normalizedPrice =
|
||||||
normalizedCurrency !== undefined
|
normalizedCurrency !== undefined
|
||||||
? displayRounding(normalizedCurrency.min)
|
? displayRounding(normalizedCurrency.min)
|
||||||
: undefined;
|
: undefined;
|
||||||
const normalizedPriceCurrency = normalizedCurrency?.currency;
|
const normalizedPriceCurrency = xchgRateCurrency.value;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id: result.id,
|
id: result.id,
|
||||||
|
|||||||
@@ -40,6 +40,11 @@
|
|||||||
src="/images/chaos.png"
|
src="/images/chaos.png"
|
||||||
class="max-w-full max-h-full"
|
class="max-w-full max-h-full"
|
||||||
/>
|
/>
|
||||||
|
<img
|
||||||
|
v-else-if="price?.currency === 'annul'"
|
||||||
|
src="/images/annul.png"
|
||||||
|
class="max-w-full max-h-full"
|
||||||
|
/>
|
||||||
<img v-else src="/images/exa.png" class="max-w-full max-h-full" />
|
<img v-else src="/images/exa.png" class="max-w-full max-h-full" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -56,7 +61,7 @@ export default defineComponent({
|
|||||||
type: Object as PropType<{
|
type: Object as PropType<{
|
||||||
min: number;
|
min: number;
|
||||||
max: number;
|
max: number;
|
||||||
currency: "chaos" | "div" | "exalted";
|
currency: string;
|
||||||
}>,
|
}>,
|
||||||
default: undefined,
|
default: undefined,
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user