import React from "react";
import {
Badge,
Box,
Flex,
Popover,
PopoverArrow,
PopoverContent,
PopoverTrigger,
Portal,
Select,
Skeleton,
Spinner,
Tooltip,
useToast,
VStack,
} from "@chakra-ui/react";
import { ExternalLinkIcon, ChevronRightIcon } from "@chakra-ui/icons";
import { gql, useMutation } from "@apollo/client";
import {
ItemBadgeList,
ItemKindBadge,
ItemThumbnail,
} from "./components/ItemCard";
import { Heading1 } from "./util";
import useSupport from "./WardrobePage/support/useSupport";
function ItemPageLayout({ children, item, isEmbedded }) {
return (
{children}
);
}
function ItemPageHeader({ item, isEmbedded }) {
return (
{item?.name || "Item name here"}
);
}
/**
* SubtleSkeleton hides the skeleton animation until a second has passed, and
* doesn't fade in the content if it loads near-instantly. This helps avoid
* flash-of-content stuff!
*
* For plain Skeletons, we often use instead. But
* that pattern doesn't work as well for wrapper skeletons where we're using
* placeholder content for layout: we don't want the delay if the content
* really _is_ present!
*/
export function SubtleSkeleton({ isLoaded, ...props }) {
const [shouldFadeIn, setShouldFadeIn] = React.useState(false);
const [shouldShowSkeleton, setShouldShowSkeleton] = React.useState(false);
React.useEffect(() => {
const t = setTimeout(() => {
if (!isLoaded) {
setShouldFadeIn(true);
}
}, 150);
return () => clearTimeout(t);
});
React.useEffect(() => {
const t = setTimeout(() => setShouldShowSkeleton(true), 500);
return () => clearTimeout(t);
});
return (
);
}
function ItemPageBadges({ item, isEmbedded }) {
const searchBadgesAreLoaded = item?.name != null && item?.isNc != null;
const shouldShowOwls = useShouldShowOwls();
return (
{
// If the createdAt date is null (loaded and empty), hide the badge.
item.createdAt !== null && (
{item.createdAt && }
)
}
Classic DTI
Jellyneo
{item.isNc && shouldShowOwls && (
{item.ncTradeValueText && (
OWLS: {item.ncTradeValueText}
)}
)}
{!item?.isNc && !item?.isPb && (
Shop Wiz
)}
{!item?.isNc && !item?.isPb && (
Super Wiz
)}
{!item?.isNc && !item?.isPb && (
Trade Post
)}
{!item?.isNc && !item?.isPb && (
Auctions
)}
);
}
function ItemKindBadgeWithSupportTools({ item }) {
const { isSupportUser, supportSecret } = useSupport();
const toast = useToast();
const ncRef = React.useRef(null);
const isNcAutoDetectedFromRarity =
item.rarityIndex === 500 || item.rarityIndex === 0;
const [mutate, { loading }] = useMutation(gql`
mutation ItemPageSupportSetIsManuallyNc(
$itemId: ID!
$isManuallyNc: Boolean!
$supportSecret: String!
) {
setItemIsManuallyNc(
itemId: $itemId
isManuallyNc: $isManuallyNc
supportSecret: $supportSecret
) {
id
isNc
isManuallyNc
}
}
`);
if (isSupportUser && item.rarityIndex != null && item.isManuallyNc != null) {
// TODO: Could code-split this into a SupportOnly file...
return (
NC:
{loading && }
PB:
Support 💖
);
}
return ;
}
const LinkBadge = React.forwardRef(
({ children, href, isEmbedded, ...props }, ref) => {
return (
{children}
{
// We also change the icon to signal whether this will launch in a new
// window or not!
isEmbedded ? (
) : (
)
}
);
}
);
const fullDateFormatter = new Intl.DateTimeFormat("en-US", {
dateStyle: "long",
});
const monthYearFormatter = new Intl.DateTimeFormat("en-US", {
month: "short",
year: "numeric",
});
const monthDayYearFormatter = new Intl.DateTimeFormat("en-US", {
month: "short",
day: "numeric",
year: "numeric",
});
function ShortTimestamp({ when }) {
const date = new Date(when);
// To find the start of last month, take today, then set its date to the 1st
// and its time to midnight (the start of this month), and subtract one
// month. (JS handles negative months and rolls them over correctly.)
const startOfLastMonth = new Date();
startOfLastMonth.setDate(1);
startOfLastMonth.setHours(0);
startOfLastMonth.setMinutes(0);
startOfLastMonth.setSeconds(0);
startOfLastMonth.setMilliseconds(0);
startOfLastMonth.setMonth(startOfLastMonth.getMonth() - 1);
const dateIsOlderThanLastMonth = date < startOfLastMonth;
return (
{dateIsOlderThanLastMonth
? monthYearFormatter.format(date)
: monthDayYearFormatter.format(date)}
);
}
const SHOULD_SHOW_OWLS = false;
/**
* useShouldShowOwls will return false until the user types "~owls" on the
* page, after which the ~owls badge will appear.
*
* We also keep the value in a global, so it'll stick if you go search for
* another item too!
*/
function useShouldShowOwls() {
const [mostRecentKeys, setMostRecentKeys] = React.useState([]);
const [shouldShowOwls, setShouldShowOwls] = React.useState(SHOULD_SHOW_OWLS);
React.useEffect(() => {
const onKeyPress = (e) => {
const newMostRecentKeys = [...mostRecentKeys, e.key].slice(-5);
if (newMostRecentKeys.join("") === "~owls") {
SHOULD_SHOW_OWLS = true;
setShouldShowOwls(true);
}
setMostRecentKeys(newMostRecentKeys);
};
window.addEventListener("keypress", onKeyPress);
return () => window.removeEventListener("keypress", onKeyPress);
});
return shouldShowOwls;
}
export default ItemPageLayout;