- {sortedSections && sortedSections.length > 0 ? (
-
-
-
- ) : null}
- {categories && categories.length > 0 ? (
-
-
-
- ) : null}
+
+
+
+
-
- setParamsBlobCategories(setSearchParamsBlob, searchParamsBlob, v)
- }
- rootClasses="package-search__tags"
- clearAll={clearAll(setSearchParamsBlob, searchParamsBlob)}
+
@@ -605,7 +639,10 @@ export function PackageSearch(props: Props) {
}>
-
+ }
+ >
{(resolvedValue) => (
}>
-
+ }
+ >
{(resolvedValue) => (
<>
{resolvedValue.results.length > 0 ? (
@@ -698,7 +738,10 @@ export function PackageSearch(props: Props) {
}>
-
+ }
+ >
{(resolvedValue) => (
+
+
+ );
+}
+
PackageSearch.displayName = "PackageSearch";
// Start setters
@@ -779,6 +838,115 @@ const clearAll =
});
// End setters
+interface SectionsFilterSectionProps {
+ sections?: CommunityFilters["sections"];
+ filtersError: unknown;
+ searchParamsBlob: SearchParamsType;
+ setSearchParamsBlob: (v: SearchParamsType) => void;
+}
+
+/**
+ * Renders the sections filter menu or throws when the sections promise rejects.
+ */
+function SectionsFilterSection(props: SectionsFilterSectionProps) {
+ const { sections, filtersError, searchParamsBlob, setSearchParamsBlob } =
+ props;
+
+ if (filtersError) {
+ throw filtersError instanceof Error
+ ? filtersError
+ : new Error("Failed to load section filters");
+ }
+
+ if (!sections || sections.length === 0) {
+ return null;
+ }
+
+ const radioSections = [
+ ...sections,
+ { uuid: "all", name: "All", slug: "all", priority: -999999999 },
+ ];
+
+ const selectedSection =
+ searchParamsBlob.section === ""
+ ? sections[0]?.uuid
+ : searchParamsBlob.section;
+
+ return (
+
+
+
+ );
+}
+
+interface CategoriesFilterSectionProps {
+ categories?: CategorySelection[];
+ filtersError: unknown;
+ items: CheckboxListItemsType;
+}
+
+/**
+ * Renders the categories filter menu and throws when filter resolution fails so
+ * the surrounding boundary can surface a localized fallback.
+ */
+function CategoriesFilterSection(props: CategoriesFilterSectionProps) {
+ const { categories, filtersError, items } = props;
+
+ if (filtersError) {
+ throw filtersError instanceof Error
+ ? filtersError
+ : new Error("Failed to load category filters");
+ }
+
+ if (!categories || categories.length === 0) {
+ return null;
+ }
+
+ return (
+
+
+
+ );
+}
+
+interface CategoryTagCloudSectionProps {
+ parsedCategories: CategorySelection[];
+ searchParamsBlob: SearchParamsType;
+ setSearchParamsBlob: (v: SearchParamsType) => void;
+}
+
+/**
+ * Wraps the category tag cloud, throwing when the filter promise rejects.
+ */
+function CategoryTagCloudSection(props: CategoryTagCloudSectionProps) {
+ const { parsedCategories, searchParamsBlob, setSearchParamsBlob } = props;
+
+ return (
+
+ setParamsBlobCategories(setSearchParamsBlob, searchParamsBlob, v)
+ }
+ rootClasses="package-search__tags"
+ clearAll={clearAll(setSearchParamsBlob, searchParamsBlob)}
+ />
+ );
+}
+
const PackageSearchPackagesSkeleton = memo(
function PackageSearchPackagesSkeleton() {
return (