From 7f3010ce1e41f3e4f8594bf66599acd786264dc6 Mon Sep 17 00:00:00 2001
From: John Hatton <hattonjohn@gmail.com>
Date: Mon, 6 Apr 2020 18:17:41 -0600
Subject: [PATCH] Use Publisher field for Publisher Group instead of
 bookshelves

Also, allow grid filtering on publisher & original publisher
---
 src/IFilter.ts                                |  4 +-
 src/components/BookShelfGroup.tsx             | 44 ++++++---
 src/components/BulkEdit/AddTagPanel.tsx       |  8 +-
 .../BulkEdit/AssignPublisherPanel.tsx         |  8 +-
 src/components/BulkEdit/BulkEditPanel.tsx     | 14 +--
 src/components/Grid/GridColumns.tsx           | 91 +++++++++++--------
 src/components/Grid/GridControlInternal.tsx   |  2 +-
 src/components/HomePage.tsx                   |  8 +-
 src/components/PublisherGroup.tsx             | 51 +++++++++++
 src/components/PublisherPages.tsx             | 28 ++++++
 src/connection/LibraryQueryHooks.ts           |  8 ++
 11 files changed, 191 insertions(+), 75 deletions(-)
 create mode 100644 src/components/PublisherGroup.tsx

diff --git a/src/IFilter.ts b/src/IFilter.ts
index 5e940fce..fd79be4a 100644
--- a/src/IFilter.ts
+++ b/src/IFilter.ts
@@ -1,12 +1,14 @@
 export enum InCirculationOptions {
     All,
     No,
-    Yes
+    Yes,
 }
 export interface IFilter {
     language?: string; // review: what is this exactly? BCP 47? Our Parse has duplicate "ethnologueCode" and "isoCode" columns, which actually contain code and full script tags.
     //    publisher?: string;
     bookshelf?: string;
+    publisher?: string;
+    originalPublisher?: string;
     feature?: string;
     topic?: string;
     bookShelfCategory?: string;
diff --git a/src/components/BookShelfGroup.tsx b/src/components/BookShelfGroup.tsx
index 6945ade6..bb18ea53 100644
--- a/src/components/BookShelfGroup.tsx
+++ b/src/components/BookShelfGroup.tsx
@@ -28,14 +28,11 @@ interface IProps {
 
 // Normally the bookshelf name matches the image name, but if not we change it here:
 const nameToImageMap = new Map<string, string>([
-    //  // something in our pipeline won't deliver an image that starts with "3"
-    ["3Asafeer", "Asafeer"],
-    ["Room To Read", "Room to Read"],
     ["Ministerio de EducaciĆ³n de Guatemala", "Guatemala MOE"],
-    ["Resources for the Blind, Inc. (Philippines)", "Resources for the Blind"]
+    ["Resources for the Blind, Inc. (Philippines)", "Resources for the Blind"],
 ]);
 
-export const BookshelfGroup: React.FunctionComponent<IProps> = props => {
+export const BookshelfGroup: React.FunctionComponent<IProps> = (props) => {
     // At this point there are so few bookshelves that we just retrieve the whole list and then filter here.
     // Might be a good thing to cache.
     const bookshelfResults = useGetBookshelvesByCategory(
@@ -49,26 +46,26 @@ export const BookshelfGroup: React.FunctionComponent<IProps> = props => {
     // From that we need to determine that on this level, we should be showing [painting, sculpture].
 
     const bookshelfPathsAtThisLevel = props.pathToTheCurrentLevel
-        ? bookshelfResults.filter(b =>
+        ? bookshelfResults.filter((b) =>
               b.key.startsWith(props.pathToTheCurrentLevel!)
           )
         : bookshelfResults;
 
     const prefix: string = props.pathToTheCurrentLevel || "";
     const allNamesAtThisLevel = bookshelfPathsAtThisLevel
-        .map(b => b.key.replace(prefix, ""))
-        .map(name => {
+        .map((b) => b.key.replace(prefix, ""))
+        .map((name) => {
             const i = name.indexOf("/");
             return i < 0 ? name : name.substr(0, i);
         });
 
     const uniqueNamesAtThisLevel = [
-        ...Array.from(new Set(allNamesAtThisLevel))
+        ...Array.from(new Set(allNamesAtThisLevel)),
     ];
 
     const { bookshelves } = useContext(CachedTablesContext);
 
-    const cards =
+    const bookshelfCards =
         bookshelfResults &&
         uniqueNamesAtThisLevel.sort().map((nextLevel: string) => {
             const imageName = nameToImageMap.get(nextLevel) ?? nextLevel;
@@ -86,7 +83,7 @@ export const BookshelfGroup: React.FunctionComponent<IProps> = props => {
                     title={bookshelf.displayName || ""}
                     bookCount="??"
                     filter={{
-                        bookshelf: fullBookshelfKey
+                        bookshelf: fullBookshelfKey,
                     }}
                     pageType={props.bookShelfCategory}
                     img={
@@ -98,5 +95,30 @@ export const BookshelfGroup: React.FunctionComponent<IProps> = props => {
             );
         });
 
+    // enhance: once we get the Publisher field filled in, we can switch to getting a full list of publishers
+    // and then us the following group
+    const publishers = ["Little Zebra Books"]; // temporary until we switch over instead of hard-coding "Little Zebra"
+    const cardsFromPublisherField =
+        bookshelfResults &&
+        publishers.sort().map((publisher) => {
+            return (
+                <CategoryCard
+                    key={publisher}
+                    //preTitle={publisher}
+                    title={publisher}
+                    bookCount="??"
+                    filter={{
+                        publisher,
+                    }}
+                    pageType={props.bookShelfCategory}
+                    img={
+                        "https://share.bloomlibrary.org/bookshelf-images/" +
+                        encodeUrl(publisher) +
+                        ".png"
+                    }
+                />
+            );
+        });
+    const cards = bookshelfCards.concat(cardsFromPublisherField);
     return <CategoryCardGroup {...props}>{cards}</CategoryCardGroup>;
 };
diff --git a/src/components/BulkEdit/AddTagPanel.tsx b/src/components/BulkEdit/AddTagPanel.tsx
index 4752c65a..5459dcc6 100644
--- a/src/components/BulkEdit/AddTagPanel.tsx
+++ b/src/components/BulkEdit/AddTagPanel.tsx
@@ -1,9 +1,3 @@
-// this engages a babel macro that does cool emotion stuff (like source maps). See https://emotion.sh/docs/babel-macros
-import css from "@emotion/css/macro";
-// these two lines make the css prop work on react elements
-import { jsx } from "@emotion/core";
-/** @jsx jsx */
-
 import React from "react";
 import { IFilter } from "../../IFilter";
 import { observer } from "mobx-react";
@@ -15,7 +9,7 @@ export const AddTagPanel: React.FunctionComponent<{
     filterHolder: FilterHolder;
     refresh: () => void;
     backgroundColor: string;
-}> = observer(props => {
+}> = observer((props) => {
     return (
         <BulkEditPanel
             panelLabel="Add Tag"
diff --git a/src/components/BulkEdit/AssignPublisherPanel.tsx b/src/components/BulkEdit/AssignPublisherPanel.tsx
index 979938f1..59e1095e 100644
--- a/src/components/BulkEdit/AssignPublisherPanel.tsx
+++ b/src/components/BulkEdit/AssignPublisherPanel.tsx
@@ -1,9 +1,3 @@
-// this engages a babel macro that does cool emotion stuff (like source maps). See https://emotion.sh/docs/babel-macros
-import css from "@emotion/css/macro";
-// these two lines make the css prop work on react elements
-import { jsx } from "@emotion/core";
-/** @jsx jsx */
-
 import React from "react";
 import { IFilter } from "../../IFilter";
 import { observer } from "mobx-react";
@@ -15,7 +9,7 @@ export const AssignPublisherPanel: React.FunctionComponent<{
     filterHolder: FilterHolder;
     backgroundColor: string;
     refresh: () => void;
-}> = observer(props => {
+}> = observer((props) => {
     return (
         <BulkEditPanel
             panelLabel="Change Publisher"
diff --git a/src/components/BulkEdit/BulkEditPanel.tsx b/src/components/BulkEdit/BulkEditPanel.tsx
index 17406f3b..c40f04b7 100644
--- a/src/components/BulkEdit/BulkEditPanel.tsx
+++ b/src/components/BulkEdit/BulkEditPanel.tsx
@@ -11,7 +11,7 @@ import {
     Checkbox,
     FormControlLabel,
     Select,
-    MenuItem
+    MenuItem,
 } from "@material-ui/core";
 
 import { IFilter } from "../../IFilter";
@@ -33,7 +33,7 @@ export const BulkEditPanel: React.FunctionComponent<{
     ) => void;
     filterHolder: FilterHolder;
     refresh: () => void;
-}> = observer(props => {
+}> = observer((props) => {
     const [valueToSet, setValueToSet] = useState<string | undefined>("");
     const [armed, setArmed] = useState(false);
     const user = useGetLoggedInUser();
@@ -44,6 +44,8 @@ export const BulkEditPanel: React.FunctionComponent<{
     const notFilteredYet = !(
         !!props.filterHolder.completeFilter.bookshelf ||
         !!props.filterHolder.completeFilter.language ||
+        !!props.filterHolder.completeFilter.publisher ||
+        !!props.filterHolder.completeFilter.originalPublisher ||
         // lots of other fields, e.g. copyright, end up as part of search (e.g. search:"copyright:foo")
         !!props.filterHolder.completeFilter.search
     );
@@ -78,7 +80,7 @@ export const BulkEditPanel: React.FunctionComponent<{
                         control={
                             <Checkbox
                                 checked={armed}
-                                onChange={e => {
+                                onChange={(e) => {
                                     setArmed(e.target.checked);
                                 }}
                             />
@@ -101,11 +103,11 @@ export const BulkEditPanel: React.FunctionComponent<{
                             css={css`
                                 width: 400px;
                             `}
-                            onChange={e => {
+                            onChange={(e) => {
                                 setValueToSet(e.target.value as string);
                             }}
                         >
-                            {props.choices.map(c => (
+                            {props.choices.map((c) => (
                                 <MenuItem key={c} value={c}>
                                     {c}
                                 </MenuItem>
@@ -121,7 +123,7 @@ export const BulkEditPanel: React.FunctionComponent<{
                                 width: 600px;
                             `}
                             defaultValue={valueToSet}
-                            onChange={evt => {
+                            onChange={(evt) => {
                                 const v = evt.target.value.trim();
                                 setValueToSet(v.length ? v : undefined);
                             }}
diff --git a/src/components/Grid/GridColumns.tsx b/src/components/Grid/GridColumns.tsx
index 70925783..17f674f8 100644
--- a/src/components/Grid/GridColumns.tsx
+++ b/src/components/Grid/GridColumns.tsx
@@ -7,7 +7,7 @@ import { jsx } from "@emotion/core";
 import React, { useState, FunctionComponent } from "react";
 import {
     Column as DevExpressColumn,
-    TableFilterRow
+    TableFilterRow,
 } from "@devexpress/dx-react-grid";
 
 import { Checkbox, Link, TableCell, Select, MenuItem } from "@material-ui/core";
@@ -52,17 +52,18 @@ export function getBookGridColumnsDefinitions(): IGridColumn[] {
             addToFilter: (filter: IFilter, value: string) => {
                 // enhance: at the moment we don't have a "title:" search axis, so this will search other fields as well
                 filter.search = value;
-            }
+            },
         },
         {
             name: "languages",
             title: "Languages",
             defaultVisible: true,
-            getCellValue: (b: Book) => b.languages.map(l => l.name).join(", "),
+            getCellValue: (b: Book) =>
+                b.languages.map((l) => l.name).join(", "),
             addToFilter: (filter: IFilter, value: string) => {
                 // enhance: at the moment we don't have a "language:" search axis, so this will search other fields as well
                 filter.search = value;
-            }
+            },
         },
         {
             name: "tags",
@@ -70,15 +71,15 @@ export function getBookGridColumnsDefinitions(): IGridColumn[] {
             getCellValue: (b: Book) =>
                 b.tags
                     .filter(
-                        t =>
-                            !kTagsToFilterOutOfTagsList.find(tagToFilterOut =>
+                        (t) =>
+                            !kTagsToFilterOutOfTagsList.find((tagToFilterOut) =>
                                 t.startsWith(tagToFilterOut)
                             )
                     )
                     .join(", "),
             addToFilter: (filter: IFilter, value: string) => {
                 filter.otherTags = value;
-            }
+            },
         },
         {
             name: "bookshelves",
@@ -87,7 +88,7 @@ export function getBookGridColumnsDefinitions(): IGridColumn[] {
             getCellValue: (b: Book) => b.bookshelves.join(","),
             addToFilter: (filter: IFilter, value: string) => {
                 filter.bookshelf = value;
-            }
+            },
         },
         {
             name: "incoming",
@@ -100,7 +101,7 @@ export function getBookGridColumnsDefinitions(): IGridColumn[] {
                 <TagExistsFilterCell {...props} />
             ),
             addToFilter: (filter: IFilter, value: string) =>
-                updateFilterForExistenceOfTag("system:Incoming", filter, value)
+                updateFilterForExistenceOfTag("system:Incoming", filter, value),
         },
         {
             name: "level",
@@ -115,22 +116,22 @@ export function getBookGridColumnsDefinitions(): IGridColumn[] {
             // TODO: we need a way to query to for a missing level indicator
             addToFilter: (filter: IFilter, value: string) => {
                 filter.search += ` level:${titleCase(value)}`;
-            }
+            },
         },
         {
             name: "topic",
             defaultVisible: true,
             getCellValue: (b: Book) =>
                 b.tags
-                    .filter(t => t.startsWith("topic:"))
-                    .map(t => (
+                    .filter((t) => t.startsWith("topic:"))
+                    .map((t) => (
                         <GridSearchLink key={t} search={t}>
                             {t.replace(/topic:/, "")}
                         </GridSearchLink>
                     )),
             addToFilter: (filter: IFilter, value: string) => {
                 filter.topic = titleCase(value);
-            }
+            },
         },
         {
             name: "harvestState",
@@ -143,11 +144,11 @@ export function getBookGridColumnsDefinitions(): IGridColumn[] {
                     choices={["", "Done", "Failed", "New", "Updated"]}
                     {...props}
                 />
-            )
+            ),
         },
         {
             name: "harvestLog",
-            defaultVisible: false
+            defaultVisible: false,
         },
         {
             name: "inCirculation",
@@ -162,7 +163,7 @@ export function getBookGridColumnsDefinitions(): IGridColumn[] {
                 if (value === "Yes")
                     filter.inCirculation = InCirculationOptions.Yes;
                 // otherwise don't mention it
-            }
+            },
         },
         { name: "license", sortingEnabled: true },
         {
@@ -171,12 +172,24 @@ export function getBookGridColumnsDefinitions(): IGridColumn[] {
 
             addToFilter: (filter: IFilter, value: string) => {
                 filter.search = `copyright:${value} ` + (filter.search || "");
-            }
+            },
         },
         { name: "pageCount", sortingEnabled: true },
         { name: "createdAt", sortingEnabled: true },
-        { name: "publisher", sortingEnabled: true },
-        { name: "originalPublisher", sortingEnabled: true },
+        {
+            name: "publisher",
+            sortingEnabled: true,
+            addToFilter: (filter: IFilter, value: string) => {
+                filter.publisher = value;
+            },
+        },
+        {
+            name: "originalPublisher",
+            sortingEnabled: true,
+            addToFilter: (filter: IFilter, value: string) => {
+                filter.originalPublisher = value;
+            },
+        },
         {
             name: "uploader",
             sortingEnabled: true,
@@ -192,15 +205,15 @@ export function getBookGridColumnsDefinitions(): IGridColumn[] {
             ),
             addToFilter: (filter: IFilter, value: string) => {
                 filter.search = `uploader:${value} ` + (filter.search || "");
-            }
-        }
+            },
+        },
     ];
 
     // generate the capitalized column names since the grid doesn't do that.
     return (
         definitions
             //.sort((a, b) => a.name.localeCompare(b.name))
-            .map(c => {
+            .map((c) => {
                 const x = { ...c };
                 if (c.title === undefined) {
                     x.title = titleCase(c.name);
@@ -212,13 +225,13 @@ export function getBookGridColumnsDefinitions(): IGridColumn[] {
 
 export const GridSearchLink: React.FunctionComponent<{
     search: string;
-}> = props => {
+}> = (props) => {
     const location = {
         title: props.search,
         pageType: "grid",
         filter: {
-            search: props.search
-        }
+            search: props.search,
+        },
     };
     const url = "/grid/?" + QueryString.stringify(location);
     return (
@@ -236,12 +249,12 @@ export const GridSearchLink: React.FunctionComponent<{
 const TagCheckbox: React.FunctionComponent<{
     book: Book;
     tag: string;
-}> = props => {
+}> = (props) => {
     const [present, setPresent] = useState(props.book.tags.includes(props.tag));
     return (
         <Checkbox
             checked={present}
-            onChange={e => {
+            onChange={(e) => {
                 props.book.setBooleanTag(props.tag, e.target.checked);
                 props.book.saveAdminDataToParse();
                 setPresent(e.target.checked);
@@ -251,9 +264,11 @@ const TagCheckbox: React.FunctionComponent<{
 };
 
 // eslint-disable-next-line @typescript-eslint/no-unused-vars
-const ChoicesFilterCell: React.FunctionComponent<TableFilterRow.CellProps & {
-    choices: string[];
-}> = props => {
+const ChoicesFilterCell: React.FunctionComponent<
+    TableFilterRow.CellProps & {
+        choices: string[];
+    }
+> = (props) => {
     const [value, setValue] = useState(props.filter?.value || "");
     return (
         <TableCell>
@@ -273,7 +288,7 @@ const ChoicesFilterCell: React.FunctionComponent<TableFilterRow.CellProps & {
                 id="demo-simple-select"
                 color="secondary" //<--- doesn't work
                 displayEmpty={true}
-                renderValue={v => {
+                renderValue={(v) => {
                     const x = v as string;
                     return <div>{x ? x : "All"}</div>;
                 }}
@@ -281,16 +296,16 @@ const ChoicesFilterCell: React.FunctionComponent<TableFilterRow.CellProps & {
                 css={css`
                     font-size: 0.875rem !important;
                 `}
-                onChange={e => {
+                onChange={(e) => {
                     setValue(e.target.value as string);
                     props.onFilter({
                         columnName: props.column.name,
                         operation: "contains",
-                        value: e.target.value as string
+                        value: e.target.value as string,
                     });
                 }}
             >
-                {props.choices.map(c => (
+                {props.choices.map((c) => (
                     <MenuItem key={c} value={c}>
                         {c.length === 0 ? "All" : c}
                     </MenuItem>
@@ -301,7 +316,9 @@ const ChoicesFilterCell: React.FunctionComponent<TableFilterRow.CellProps & {
 };
 
 // shows a checkbox in the filter row; ticking the box leads to a call to the gridColumn definition `addToFilter()`
-const TagExistsFilterCell: React.FunctionComponent<TableFilterRow.CellProps> = props => {
+const TagExistsFilterCell: React.FunctionComponent<TableFilterRow.CellProps> = (
+    props
+) => {
     const [checked, setChecked] = useState(
         props.filter?.value === "true" || false
     );
@@ -312,12 +329,12 @@ const TagExistsFilterCell: React.FunctionComponent<TableFilterRow.CellProps> = p
                     padding-left: 0;
                 `}
                 checked={checked}
-                onChange={e => {
+                onChange={(e) => {
                     props.onFilter({
                         columnName: props.column.name,
                         operation: "contains",
                         // we're switching to the opposite of what `checked` was
-                        value: !checked ? "true" : "false"
+                        value: !checked ? "true" : "false",
                     });
                     setChecked(!checked);
                 }}
diff --git a/src/components/Grid/GridControlInternal.tsx b/src/components/Grid/GridControlInternal.tsx
index 81fdc680..b4a773ad 100644
--- a/src/components/Grid/GridControlInternal.tsx
+++ b/src/components/Grid/GridControlInternal.tsx
@@ -171,7 +171,7 @@ const GridControlInternal: React.FunctionComponent<IGridControlProps> = observer
                 )
             );
             //setColumnNamesInDisplayOrder(bookGridColumns.map(c => c.name));
-        }, [router, user, user?.moderator, bookGridColumnDefinitions]);
+        }, [router, user, bookGridColumnDefinitions]);
 
         // note: this is an embedded function as a way to get at bookGridColumnDefinitions. It's important
         // that we don't reconstruct it on every render, or else we'll lose cursor focus on each key press.
diff --git a/src/components/HomePage.tsx b/src/components/HomePage.tsx
index 6fdd6882..4618dfd8 100644
--- a/src/components/HomePage.tsx
+++ b/src/components/HomePage.tsx
@@ -7,10 +7,11 @@ import { HomeBanner } from "./banners/HomeBanner";
 import { ListOfBookGroups } from "./ListOfBookGroups";
 import { FeatureGroup } from "./FeatureGroup";
 import { SpecialInterestGroup } from "./SpecialInterestsGroup";
+import { PublisherGroup } from "./PublisherGroup";
 
 export const HomePage: React.FunctionComponent = () => {
     const almostAllBooksFilter: IFilter = {
-        inCirculation: InCirculationOptions.Yes
+        inCirculation: InCirculationOptions.Yes,
     };
     return (
         <>
@@ -31,10 +32,7 @@ export const HomePage: React.FunctionComponent = () => {
                     order={"-createdAt"}
                 />
 
-                <BookshelfGroup
-                    title="Publishers"
-                    bookShelfCategory="publisher"
-                />
+                <PublisherGroup />
 
                 <FeatureGroup title="Book Features" />
 
diff --git a/src/components/PublisherGroup.tsx b/src/components/PublisherGroup.tsx
new file mode 100644
index 00000000..9a070b9f
--- /dev/null
+++ b/src/components/PublisherGroup.tsx
@@ -0,0 +1,51 @@
+import React from "react";
+import CategoryCard from "./CategoryCard";
+import { CategoryCardGroup } from "./CategoryCardGroup";
+
+const encodeUrl = require("encodeurl");
+
+// Normally the publisher name matches the image name, but if not we change it here:
+const nameToImageMap = new Map<string, string>([
+    //  // something in our pipeline won't deliver an image that starts with "3"
+    ["3Asafeer", "Asafeer"],
+    ["Room To Read", "Room to Read"],
+]);
+
+export const PublisherGroup: React.FunctionComponent<{}> = (props) => {
+    // enhance: once we get the Publisher field filled in, we can switch to getting a full list of publishers
+    // and then us the following group
+    const publishers = [
+        "African Storybook",
+        "3Asafeer",
+        "Book Dash",
+        "Little Zebra Books",
+        "Pratham",
+        "Room To Read",
+    ];
+    const cards = publishers.sort().map((publisher) => {
+        const imageName = nameToImageMap.get(publisher) ?? publisher;
+        return (
+            <CategoryCard
+                key={publisher}
+                //preTitle={publisher}
+                title={publisher}
+                bookCount="??"
+                filter={{
+                    publisher,
+                }}
+                pageType={"project"}
+                img={
+                    "https://share.bloomlibrary.org/bookshelf-images/" +
+                    encodeUrl(imageName) +
+                    ".png"
+                }
+            />
+        );
+    });
+
+    return (
+        <CategoryCardGroup title="Publishers" {...props}>
+            {cards}
+        </CategoryCardGroup>
+    );
+};
diff --git a/src/components/PublisherPages.tsx b/src/components/PublisherPages.tsx
index 467b8b6a..3ad90eea 100644
--- a/src/components/PublisherPages.tsx
+++ b/src/components/PublisherPages.tsx
@@ -66,6 +66,34 @@ export const AsafeerPage: React.FunctionComponent = () => {
     );
 };
 
+export const LittleZebraPage: React.FunctionComponent = () => {
+    const filter = { publisher: "Little Zebra" };
+    const description = (
+        <React.Fragment>
+            <ExternalLink href="https://www.littlezebrabooks.com/">
+                Little Zebra Books{" "}
+            </ExternalLink>
+            &nbsp;is a Christian non-profit organization that exists to serve
+            African communities through the development, production, and
+            distribution of African-language books.
+        </React.Fragment>
+    );
+    return (
+        <div>
+            <PublisherBanner
+                title="Little Zebra"
+                showTitle={false}
+                filter={filter}
+                logoUrl={`https://share.bloomlibrary.org/bookshelf-images/LittleZebra.png`}
+                collectionDescription={description}
+            />
+
+            <ListOfBookGroups>
+                <StandardPublisherGroups filter={filter} />
+            </ListOfBookGroups>
+        </div>
+    );
+};
 export const PrathamPage: React.FunctionComponent = () => {
     const filter = { bookshelf: "Pratham" };
     const description = (
diff --git a/src/connection/LibraryQueryHooks.ts b/src/connection/LibraryQueryHooks.ts
index 6acb4030..783e98eb 100644
--- a/src/connection/LibraryQueryHooks.ts
+++ b/src/connection/LibraryQueryHooks.ts
@@ -674,6 +674,14 @@ export function constructParseBookQuery(
         delete params.where.feature;
         params.where.features = f.feature; //my understanding is that this means it just has to contain this, could have others
     }
+    if (f.publisher) {
+        delete params.where.publisher;
+        params.where.publisher = f.publisher;
+    }
+    if (f.originalPublisher) {
+        delete params.where.originalPublisher;
+        params.where.publisher = f.originalPublisher;
+    }
     delete params.where.inCirculation;
     switch (f.inCirculation) {
         case undefined: