diff --git a/src/lib/components/common/item_holder_metadata.ts b/src/lib/components/common/item_holder_metadata.ts
index d75f79d7..c2c90b9b 100644
--- a/src/lib/components/common/item_holder_metadata.ts
+++ b/src/lib/components/common/item_holder_metadata.ts
@@ -4,9 +4,12 @@ import {state} from 'lit/decorators.js';
import {rgAsset} from '../../types/steam';
import {gFloatFetcher} from '../../services/float_fetcher';
import {ItemInfo} from '../../bridge/handlers/fetch_inspect_info';
+import {FetchRecommendedPrice} from '../../bridge/handlers/fetch_recommended_price';
import {
+ isSellableOnCSFloat,
formatFloatWithRank,
formatSeed,
+ formatPrice,
getFadePercentage,
getLowestRank,
isBlueSkin,
@@ -25,10 +28,21 @@ export abstract class ItemHolderMetadata extends FloatElement {
static styles = [
...FloatElement.styles,
css`
+ .price {
+ position: absolute;
+ bottom: 3px;
+ left: 3px;
+ right: 48px;
+ font-size: 12px;
+ text-align: left;
+ z-index: 2;
+ }
+
.float {
position: absolute;
bottom: 3px;
right: 3px;
+ left: 50px;
font-size: 12px;
text-align: right;
}
@@ -75,6 +89,9 @@ export abstract class ItemHolderMetadata extends FloatElement {
@state()
private bluegemData: FetchBluegemResponse | undefined;
+ @state()
+ private itemPrice: number | undefined;
+
get assetId(): string | undefined {
return $J(this).parent().attr('id')?.split('_')[2];
}
@@ -86,6 +103,11 @@ export abstract class ItemHolderMetadata extends FloatElement {
abstract get asset(): rgAsset | undefined;
abstract get ownerSteamId(): string | undefined;
+ get isSellable(): boolean {
+ if (!this.asset) return false;
+ return isSellableOnCSFloat(this.asset);
+ }
+
get inspectLink(): string | undefined {
if (!this.asset) return;
@@ -105,7 +127,17 @@ export abstract class ItemHolderMetadata extends FloatElement {
}
protected render(): HTMLTemplateResult {
- if (!this.itemInfo || !this.asset) return html``;
+ if (!this.asset) return html``;
+
+ if (!this.itemInfo) {
+ return html`
+
+ ${this.itemPrice
+ ? html`$${formatPrice(this.itemPrice / 100)}`
+ : nothing}
+
+ `
+ }
if (isSkin(this.asset)) {
const fadeDetails = this.asset && getFadePercentage(this.asset, this.itemInfo);
@@ -118,7 +150,10 @@ export abstract class ItemHolderMetadata extends FloatElement {
return html`
- ${formatFloatWithRank(this.itemInfo, 6)}
+ ${formatFloatWithRank(this.itemInfo, 3)}
+ ${this.itemPrice
+ ? html`$${formatPrice(this.itemPrice / 100)}`
+ : nothing}
${formatSeed(this.itemInfo)}
${fadeDetails !== undefined
@@ -138,9 +173,10 @@ export abstract class ItemHolderMetadata extends FloatElement {
} else if (isCharm(this.asset) && !isHighlightCharm(this.asset)) {
return html`
- #${this.itemInfo.keychains?.length > 0 ? this.itemInfo.keychains[0].pattern : 'NA'}
+ ${this.itemPrice
+ ? html`$${formatPrice(this.itemPrice / 100)}`
+ : nothing}
+ #${this.itemInfo.keychains?.length > 0 ? this.itemInfo.keychains[0].pattern : 'NA'}
`;
} else {
@@ -151,14 +187,14 @@ export abstract class ItemHolderMetadata extends FloatElement {
async connectedCallback() {
super.connectedCallback();
- if (this.inspectLink) {
+ if (this.isSellable) {
this.onInit();
} else {
// Wait until the asset exists
Observe(
- () => this.inspectLink,
+ () => this.isSellable,
() => {
- if (this.inspectLink) {
+ if (this.isSellable) {
this.onInit();
}
},
@@ -169,19 +205,28 @@ export abstract class ItemHolderMetadata extends FloatElement {
async onInit() {
if (!this.asset) return;
+
+ if ((isSkin(this.asset) || isCharm(this.asset)) && this.inspectLink && this.assetId) {
+ try {
+ this.itemInfo = await gFloatFetcher.fetch({
+ link: this.inspectLink,
+ asset_id: this.assetId,
+ });
+ } catch (e: any) {
+ console.error(`Failed to fetch float for ${this.assetId}: ${e.toString()}`);
+ }
+ }
- if (!isSkin(this.asset) && !isCharm(this.asset)) return;
-
- // Commodities won't have inspect links
- if (!this.inspectLink || !this.assetId) return;
-
- try {
- this.itemInfo = await gFloatFetcher.fetch({
- link: this.inspectLink,
- asset_id: this.assetId,
- });
- } catch (e: any) {
- console.error(`Failed to fetch float for ${this.assetId}: ${e.toString()}`);
+ if (isSellableOnCSFloat(this.asset)) {
+ try {
+ const result = await ClientSend(FetchRecommendedPrice, {
+ market_hash_name: this.asset.market_hash_name,
+ paint_index: this.itemInfo?.paintindex,
+ });
+ this.itemPrice = result.price;
+ } catch (e: any) {
+ console.error(`Failed to fetch price for ${this.asset.market_hash_name}: ${e.toString()}`);
+ }
}
if (this.itemInfo) {
diff --git a/src/lib/utils/skin.ts b/src/lib/utils/skin.ts
index c6408969..81ac25c7 100644
--- a/src/lib/utils/skin.ts
+++ b/src/lib/utils/skin.ts
@@ -41,8 +41,13 @@ export function parseRank(info: ItemInfo): {order: OrderType; rank: number} | un
}
}
+function truncate(num: number, digits: number): string {
+ const factor = 10 ** digits;
+ return (Math.trunc(num * factor) / factor).toFixed(digits);
+ }
+
export function formatFloatWithRank(info: ItemInfo, precisionDigits = 14): string {
- let r = info.floatvalue.toFixed(precisionDigits);
+ let r = truncate(info.floatvalue, precisionDigits);
const ranked = parseRank(info);
if (ranked) {
@@ -52,6 +57,16 @@ export function formatFloatWithRank(info: ItemInfo, precisionDigits = 14): strin
return r;
}
+export function formatPrice(price: number): string {
+
+ const formattedPrice =
+ price >= 100
+ ? Math.round(price).toString()
+ : Number(truncate(price, 2)).toString();
+
+ return formattedPrice;
+}
+
export function formatSeed(info: ItemInfo): string {
let r = info.paintseed.toString();