Skip to content

Commit

Permalink
fixup
Browse files Browse the repository at this point in the history
  • Loading branch information
timche committed Feb 2, 2024
1 parent bbc48fb commit 290d6e0
Show file tree
Hide file tree
Showing 5 changed files with 279 additions and 77 deletions.
64 changes: 64 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
"element-ready": "^6.2.2",
"ky": "^1.2.0",
"lucide-react": "^0.292.0",
"memoize": "^10.0.0",
"p-memoize": "^7.1.1",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"select-dom": "^9.0.0",
Expand Down
261 changes: 192 additions & 69 deletions src/content/steamcommunity/features/trade-offer-items-info.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
import { ItemSkinportPrice } from "@/components/item-skinport-price";
import { featureManager } from "@/content/feature-manager";
import { createWidgetElement } from "@/content/widget";
import { useSkinportItemPrices } from "@/lib/skinport";
import { formatPrice } from "@/lib/format";
import { createUseSkinportItemPrices } from "@/lib/skinport";
import {
Item,
getIsSupportedSteamAppId,
getItemFromSteamMarketUrl,
getSteamUserWalletCurrencyFromMarket,
} from "@/lib/steam";
import { cn } from "@/lib/utils";
import elementReady from "element-ready";
import ky from "ky";
import { $, $$ } from "select-dom";
Expand Down Expand Up @@ -131,80 +132,202 @@ async function steamTradeOfferItemsInfo() {
}

if (/\/tradeoffers\/$/.test(location.pathname)) {
const tradeItemElements = $$(".trade_item[data-economy-item]");

const tradeItems: (Item & { element: HTMLElement })[] = [];

for (const tradeItemElement of tradeItemElements) {
const economyItemValue =
tradeItemElement.getAttribute("data-economy-item");

if (!economyItemValue) {
return;
}

const [_, itemMarketHashName, itemAppId] =
(
await ky(
`https://steamcommunity.com/economy/${economyItemValue.replace(
"classinfo",
"itemclasshover",
)}`,
{
searchParams: {
content_only: 1,
l: "english",
},
},
).text()
).match(/"market_hash_name\":"([\w\s()|-]+)".*"appid":"(\d+)"/) || [];

if (
itemMarketHashName &&
itemAppId &&
getIsSupportedSteamAppId(itemAppId)
) {
tradeItems.push({
name: itemMarketHashName,
appId: itemAppId as Item["appId"],
element: tradeItemElement,
});
}
}

const skinportItemPriceItemNames = tradeItems.map(({ name }) => name);
const tradeOfferElements = $$(".tradeoffer");

for (const tradeOfferElement of tradeOfferElements) {
const tradeOfferPartyElements = [
$(".tradeoffer_items.primary", tradeOfferElement),
$(".tradeoffer_items.secondary", tradeOfferElement),
];

const [
usePrimaryPartySkinportItemPrices,
useSecondaryPartySkinportItemPrices,
] = await Promise.all(
tradeOfferPartyElements.map(async (tradeOfferPartyElement) => {
const tradeItemElements = $$(
".trade_item[data-economy-item]",
tradeOfferPartyElement,
);

const tradeItemsByDataEconomyItem: Record<
string,
Item & { element: HTMLElement }
> = {};

await Promise.all(
tradeItemElements.map(async (tradeItemElement) => {
const tradeItemDataEconomyItemValue =
tradeItemElement.getAttribute("data-economy-item");

if (!tradeItemDataEconomyItemValue) {
return;
}

const [_, itemMarketHashName, itemAppId] =
(
await ky(
`https://steamcommunity.com/economy/${tradeItemDataEconomyItemValue.replace(
"classinfo",
"itemclasshover",
)}`,
{
searchParams: {
content_only: 1,
l: "english",
},
},
).text()
).match(/"market_hash_name\":"([^"]+)".*"appid":"(\d+)"/) || [];

if (
itemMarketHashName &&
itemAppId &&
getIsSupportedSteamAppId(itemAppId)
) {
tradeItemsByDataEconomyItem[tradeItemDataEconomyItemValue] = {
name: decodeURIComponent(itemMarketHashName),
appId: itemAppId as Item["appId"],
element: tradeItemElement,
};
}
}),
);

const useSkinportItemPrices = await createUseSkinportItemPrices(
Object.values(tradeItemsByDataEconomyItem).map(({ name }) => name),
);

for (const tradeItem of Object.values(tradeItemsByDataEconomyItem)) {
const [skinportItemPriceElement] = createWidgetElement(() => {
const skinportItemPrices = useSkinportItemPrices();

const skinportItemPrice =
skinportItemPrices.data?.items[tradeItem.name];

if (!skinportItemPrice) {
return;
}

return (
<div className="absolute left-1.5 bottom-0.5 z-10 flex gap-1">
<ItemSkinportPrice
price={skinportItemPrice[1]}
currency={skinportItemPrices.data?.currency}
size="sm"
priceTitle="none"
linkItem={tradeItem}
/>
</div>
);
});

tradeItem.element.append(skinportItemPriceElement);
}

return useSkinportItemPrices;
}),
);

const steamUserWalletCurrency =
await getSteamUserWalletCurrencyFromMarket();
for (const tradeOfferPartyElement of tradeOfferPartyElements) {
if (!tradeOfferPartyElement) {
break;
}

for (const tradeItem of tradeItems) {
const [skinportItemPriceElement] = createWidgetElement(() => {
const skinportItemPrices = useSkinportItemPrices(
skinportItemPriceItemNames,
steamUserWalletCurrency,
const tradeOfferPartyHeaderElement = $(
".tradeoffer_items_header",
tradeOfferPartyElement,
);

const skinportItemPrice =
skinportItemPrices.data?.items[tradeItem.name];

if (!skinportItemPrice) {
return;
if (!tradeOfferPartyHeaderElement) {
break;
}

return (
<div className="absolute left-1.5 bottom-0.5 z-10 flex gap-1">
<ItemSkinportPrice
price={skinportItemPrice[1]}
currency={skinportItemPrices.data?.currency}
size="sm"
priceTitle="none"
linkItem={tradeItem}
/>
</div>
);
});
const [totalSkinportItemPriceElement] = createWidgetElement(() => {
const primaryPartySkinportItemPrices =
usePrimaryPartySkinportItemPrices();
const secondaryPartySkinportItemPrices =
useSecondaryPartySkinportItemPrices();

if (
!primaryPartySkinportItemPrices.data ||
!secondaryPartySkinportItemPrices.data
) {
return;
}

const isPrimaryParty =
tradeOfferPartyElement.classList.contains("primary");

let totalPartySkinportItemPrice = 0;

for (const [
_lowestPrice,
suggestedSkinportItemPrice,
] of Object.values(
isPrimaryParty
? primaryPartySkinportItemPrices.data.items
: secondaryPartySkinportItemPrices.data.items,
)) {
if (suggestedSkinportItemPrice) {
totalPartySkinportItemPrice += suggestedSkinportItemPrice;
}
}

let totalOtherPartySkinportItemPrice = 0;

for (const [
_lowestPrice,
suggestedSkinportItemPrice,
] of Object.values(
isPrimaryParty
? secondaryPartySkinportItemPrices.data.items
: primaryPartySkinportItemPrices.data.items,
)) {
if (suggestedSkinportItemPrice) {
totalOtherPartySkinportItemPrice += suggestedSkinportItemPrice;
}
}

const totalDifferencePrice =
totalOtherPartySkinportItemPrice - totalPartySkinportItemPrice;

const totalDifferencePercentage = (
(totalDifferencePrice / totalPartySkinportItemPrice) *
100
).toFixed(2);

return (
<div className="flex gap-1">
<div>
Total{" "}
<span className="text-white font-semibold">
{formatPrice(
totalPartySkinportItemPrice,
primaryPartySkinportItemPrices.data.currency,
)}
</span>
</div>
<div
className={cn({
"text-red-600": totalDifferencePrice < 0,
"text-green-600": totalDifferencePrice > 0,
})}
>
({totalDifferencePrice > 0 && "+"}
{formatPrice(
totalDifferencePrice,
primaryPartySkinportItemPrices.data.currency,
)}{" "}
/ {totalDifferencePrice > 0 && "+"}
{totalDifferencePercentage}%)
</div>
</div>
);
});

tradeItem.element.append(skinportItemPriceElement);
tradeOfferPartyElement.append(totalSkinportItemPriceElement);
}
}
}
}
Expand Down
Loading

0 comments on commit 290d6e0

Please sign in to comment.