accords-library.com/src/pages/library/index.tsx

320 lines
10 KiB
TypeScript

import { GetStaticProps } from "next";
import SubPanel from "components/Panels/SubPanel";
import ContentPanel, {
ContentPanelWidthSizes,
} from "components/Panels/ContentPanel";
import {
GetLibraryItemsPreviewQuery,
GetWebsiteInterfaceQuery,
} from "graphql/operations-types";
import { getLibraryItemsPreview } from "graphql/operations";
import PanelHeader from "components/PanelComponents/PanelHeader";
import AppLayout from "components/AppLayout";
import LibraryItemsPreview from "components/Library/LibraryItemsPreview";
import Select from "components/Select";
import { useEffect, useState } from "react";
import { prettyDate, prettyinlineTitle } from "queries/helpers";
import Switch from "components/Switch";
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
interface LibraryProps extends AppStaticProps {
items: GetLibraryItemsPreviewQuery["libraryItems"]["data"];
}
type GroupLibraryItems = Map<
string,
GetLibraryItemsPreviewQuery["libraryItems"]["data"]
>;
export default function Library(props: LibraryProps): JSX.Element {
const { langui, items } = props;
const [showSubitems, setShowSubitems] = useState<boolean>(false);
const [showPrimaryItems, setShowPrimaryItems] = useState<boolean>(true);
const [showSecondaryItems, setShowSecondaryItems] = useState<boolean>(false);
const [sortingMethod, setSortingMethod] = useState<number>(0);
const [groupingMethod, setGroupingMethod] = useState<number>(-1);
const [filteredItems, setFilteredItems] = useState<LibraryProps["items"]>(
filterItems(showSubitems, showPrimaryItems, showSecondaryItems, items)
);
const [sortedItems, setSortedItem] = useState<LibraryProps["items"]>(
sortBy(groupingMethod, filteredItems)
);
const [groups, setGroups] = useState<GroupLibraryItems>(
getGroups(langui, groupingMethod, sortedItems)
);
useEffect(() => {
setFilteredItems(
filterItems(showSubitems, showPrimaryItems, showSecondaryItems, items)
);
}, [showSubitems, items, showPrimaryItems, showSecondaryItems]);
useEffect(() => {
setSortedItem(sortBy(sortingMethod, filteredItems));
}, [filteredItems, sortingMethod]);
useEffect(() => {
setGroups(getGroups(langui, groupingMethod, sortedItems));
}, [langui, groupingMethod, sortedItems]);
const subPanel = (
<SubPanel>
<PanelHeader
icon="library_books"
title={langui.library}
description={langui.library_description}
/>
<div className="flex flex-row gap-2 place-items-center">
<p className="flex-shrink-0">{langui.group_by}:</p>
<Select
className="w-full"
options={[langui.category, langui.type, langui.release_year]}
state={groupingMethod}
setState={setGroupingMethod}
allowEmpty
/>
</div>
<div className="flex flex-row gap-2 place-items-center">
<p className="flex-shrink-0">{langui.order_by}:</p>
<Select
className="w-full"
options={[langui.name, langui.price, langui.release_date]}
state={sortingMethod}
setState={setSortingMethod}
/>
</div>
<div className="flex flex-row gap-2 place-items-center">
<p className="flex-shrink-0">{langui.show_subitems}:</p>
<Switch state={showSubitems} setState={setShowSubitems} />
</div>
<div className="flex flex-row gap-2 place-items-center">
<p className="flex-shrink-0">{langui.show_primary_items}:</p>
<Switch state={showPrimaryItems} setState={setShowPrimaryItems} />
</div>
<div className="flex flex-row gap-2 place-items-center">
<p className="flex-shrink-0">{langui.show_secondary_items}:</p>
<Switch state={showSecondaryItems} setState={setShowSecondaryItems} />
</div>
</SubPanel>
);
const contentPanel = (
<ContentPanel width={ContentPanelWidthSizes.large}>
{[...groups].map(([name, items]) => (
<>
{items.length > 0 && (
<>
<h2 className="text-2xl pb-2 pt-10 first-of-type:pt-0">{name}</h2>
<div
key={name}
className="grid gap-8 items-end mobile:grid-cols-2 desktop:grid-cols-[repeat(auto-fill,_minmax(13rem,1fr))] pb-12 border-b-[3px] border-dotted last-of-type:border-0"
>
{items.map((item) => (
<LibraryItemsPreview
key={item.id}
item={item.attributes}
currencies={props.currencies}
/>
))}
</div>
</>
)}
</>
))}
</ContentPanel>
);
return (
<AppLayout
navTitle={langui.library}
subPanel={subPanel}
contentPanel={contentPanel}
{...props}
/>
);
}
export const getStaticProps: GetStaticProps = async (context) => {
const props: LibraryProps = {
...(await getAppStaticProps(context)),
items: (
await getLibraryItemsPreview({
language_code: context.locale || "en",
})
).libraryItems.data,
};
return {
props: props,
};
};
function getGroups(
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"],
groupByType: number,
items: LibraryProps["items"]
): GroupLibraryItems {
switch (groupByType) {
case 0:
return new Map();
case 1:
const groupType: GroupLibraryItems = new Map();
groupType.set(langui.audio, []);
groupType.set(langui.game, []);
groupType.set(langui.textual, []);
groupType.set(langui.video, []);
groupType.set(langui.other, []);
groupType.set(langui.group, []);
groupType.set(langui.no_type, []);
items.map((item) => {
if (item.attributes.metadata.length > 0) {
switch (item.attributes.metadata[0].__typename) {
case "ComponentMetadataAudio":
groupType.get(langui.audio)?.push(item);
break;
case "ComponentMetadataGame":
groupType.get(langui.game)?.push(item);
break;
case "ComponentMetadataBooks":
groupType.get(langui.textual)?.push(item);
break;
case "ComponentMetadataVideo":
groupType.get(langui.video)?.push(item);
break;
case "ComponentMetadataOther":
groupType.get(langui.other)?.push(item);
break;
case "ComponentMetadataGroup":
switch (
item.attributes.metadata[0].subitems_type.data.attributes.slug
) {
case "audio":
groupType.get(langui.audio)?.push(item);
break;
case "video":
groupType.get(langui.video)?.push(item);
break;
case "game":
groupType.get(langui.game)?.push(item);
break;
case "textual":
groupType.get(langui.textual)?.push(item);
break;
case "mixed":
groupType.get(langui.group)?.push(item);
break;
}
break;
}
} else {
groupType.get(langui.no_type)?.push(item);
}
});
return groupType;
case 2:
const years: number[] = [];
items.map((item) => {
if (item.attributes.release_date) {
if (!years.includes(item.attributes.release_date.year))
years.push(item.attributes.release_date.year);
}
});
const groupYear: GroupLibraryItems = new Map();
years.sort();
years.map((year) => {
groupYear.set(year.toString(), []);
});
groupYear.set(langui.no_year, []);
items.map((item) => {
if (item.attributes.release_date) {
groupYear
.get(item.attributes.release_date.year.toString())
?.push(item);
} else {
groupYear.get(langui.no_year)?.push(item);
}
});
return groupYear;
default:
const groupDefault: GroupLibraryItems = new Map();
groupDefault.set("", items);
return groupDefault;
}
}
function filterItems(
showSubitems: boolean,
showPrimaryItems: boolean,
showSecondaryItems: boolean,
items: LibraryProps["items"]
): LibraryProps["items"] {
return [...items].filter((item) => {
if (!showSubitems && !item.attributes.root_item) return false;
if (
showSubitems &&
item.attributes.metadata.length > 0 &&
item.attributes.metadata[0].__typename === "ComponentMetadataGroup" &&
(item.attributes.metadata[0].subtype.data.attributes.slug ===
"variant-set" ||
item.attributes.metadata[0].subtype.data.attributes.slug ===
"relation-set")
)
return false;
if (item.attributes.primary && !showPrimaryItems) return false;
if (!item.attributes.primary && !showSecondaryItems) return false;
return true;
});
}
function sortBy(
orderByType: number,
items: LibraryProps["items"]
): LibraryProps["items"] {
switch (orderByType) {
case 0:
return [...items].sort((a, b) => {
const titleA = prettyinlineTitle(
"",
a.attributes.title,
a.attributes.subtitle
);
const titleB = prettyinlineTitle(
"",
b.attributes.title,
b.attributes.subtitle
);
return titleA.localeCompare(titleB);
});
case 1:
return [...items].sort((a, b) => {
const priceA = a.attributes.price ? a.attributes.price.amount : 99999;
const priceB = b.attributes.price ? b.attributes.price.amount : 99999;
return priceA - priceB;
});
case 2:
return [...items].sort((a, b) => {
const dateA =
a.attributes.release_date !== null
? prettyDate(a.attributes.release_date)
: "9999";
const dateB =
b.attributes.release_date !== null
? prettyDate(b.attributes.release_date)
: "9999";
return dateA.localeCompare(dateB);
});
default:
return items;
}
}