mirror of
https://github.com/LukeHagar/unicorn-utterances.git
synced 2025-12-07 21:07:47 +00:00
add unicorn data to search API response, fix type errors
This commit is contained in:
@@ -23,7 +23,6 @@ export const MockCollection: ExtendedCollectionInfo = {
|
||||
},
|
||||
locales: ["en"],
|
||||
locale: "en",
|
||||
posts: [MockPost],
|
||||
slug: "this-collection-name-here",
|
||||
title: "Collection title",
|
||||
description: "This is a short description dunno why this would be this short",
|
||||
|
||||
@@ -1,33 +1,25 @@
|
||||
import { MockUnicorn, MockUnicornTwo } from "./mock-unicorn";
|
||||
import { MockLicense } from "./mock-license";
|
||||
import { ExtendedPostInfo } from "types/index";
|
||||
import { PostInfo } from "types/index";
|
||||
|
||||
export const MockPost: ExtendedPostInfo = {
|
||||
excerpt: "This would be an auto generated excerpt of the post in particular",
|
||||
export const MockPost: PostInfo = {
|
||||
title: "Post title",
|
||||
published: "10-10-2010T00:00:00.000Z",
|
||||
publishedMeta: "October 10, 2010",
|
||||
tags: ["item1"],
|
||||
description: "This is a short description dunno why this would be this short",
|
||||
authors: [MockUnicorn.id],
|
||||
authorsMeta: [MockUnicorn],
|
||||
license: MockLicense.id,
|
||||
licenseMeta: MockLicense,
|
||||
locale: "en",
|
||||
locales: ["en", "es"],
|
||||
slug: "this-post-name-here",
|
||||
headingsWithId: [],
|
||||
path: "path",
|
||||
wordCount: 10000,
|
||||
contentMeta: "",
|
||||
Content: {} as never,
|
||||
suggestedArticles: [] as never,
|
||||
attached: [],
|
||||
socialImg: "img.png",
|
||||
};
|
||||
|
||||
export const MockMultiAuthorPost: ExtendedPostInfo = {
|
||||
excerpt:
|
||||
"This would be a second auto generated excerpt of the post in particular",
|
||||
export const MockMultiAuthorPost: PostInfo = {
|
||||
title: "Another post title",
|
||||
published: "10-20-2010T00:00:00.000Z",
|
||||
publishedMeta: "October 20, 2010",
|
||||
@@ -35,24 +27,17 @@ export const MockMultiAuthorPost: ExtendedPostInfo = {
|
||||
description:
|
||||
"This is another short description dunno why this would be this short",
|
||||
authors: [MockUnicornTwo.id, MockUnicorn.id],
|
||||
authorsMeta: [MockUnicornTwo, MockUnicorn],
|
||||
license: MockLicense.id,
|
||||
licenseMeta: MockLicense,
|
||||
locale: "en",
|
||||
locales: ["en", "es"],
|
||||
slug: "this-other-post-name-here",
|
||||
headingsWithId: [],
|
||||
path: "path",
|
||||
wordCount: 100000,
|
||||
contentMeta: "",
|
||||
Content: {} as never,
|
||||
suggestedArticles: [] as never,
|
||||
attached: [],
|
||||
socialImg: "img.png",
|
||||
};
|
||||
|
||||
export const MockMuliLanguagePost: ExtendedPostInfo = {
|
||||
excerpt:
|
||||
"This would be a second auto generated excerpt of the post in particular",
|
||||
export const MockMuliLanguagePost: PostInfo = {
|
||||
title: "Another post title",
|
||||
published: "10-20-2010T00:00:00.000Z",
|
||||
publishedMeta: "October 20, 2010",
|
||||
@@ -60,24 +45,17 @@ export const MockMuliLanguagePost: ExtendedPostInfo = {
|
||||
description:
|
||||
"This is another short description dunno why this would be this short",
|
||||
authors: [MockUnicornTwo.id, MockUnicorn.id],
|
||||
authorsMeta: [MockUnicornTwo, MockUnicorn],
|
||||
license: MockLicense.id,
|
||||
licenseMeta: MockLicense,
|
||||
locale: "en",
|
||||
locales: ["en", "es"],
|
||||
slug: "this-other-post-name-here",
|
||||
headingsWithId: [],
|
||||
path: "path",
|
||||
wordCount: 100000,
|
||||
contentMeta: "",
|
||||
Content: {} as never,
|
||||
suggestedArticles: [] as never,
|
||||
attached: [],
|
||||
socialImg: "img.png",
|
||||
};
|
||||
|
||||
export const MockCanonicalPost: ExtendedPostInfo = {
|
||||
excerpt:
|
||||
"This would be a second auto generated excerpt of the post in particular",
|
||||
export const MockCanonicalPost: PostInfo = {
|
||||
title: "Another post title",
|
||||
published: "10-20-2010T00:00:00.000Z",
|
||||
publishedMeta: "October 20, 2010",
|
||||
@@ -86,17 +64,12 @@ export const MockCanonicalPost: ExtendedPostInfo = {
|
||||
description:
|
||||
"This is another short description dunno why this would be this short",
|
||||
authors: [MockUnicornTwo.id, MockUnicorn.id],
|
||||
authorsMeta: [MockUnicornTwo, MockUnicorn],
|
||||
license: MockLicense.id,
|
||||
licenseMeta: MockLicense,
|
||||
locale: "en",
|
||||
locales: ["en", "es"],
|
||||
slug: "this-other-post-name-here",
|
||||
headingsWithId: [],
|
||||
path: "path",
|
||||
wordCount: 100000,
|
||||
contentMeta: "",
|
||||
Content: {} as never,
|
||||
suggestedArticles: [] as never,
|
||||
attached: [],
|
||||
socialImg: "img.png",
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { RolesEnum } from "types/RolesInfo";
|
||||
import { RolesInfo } from "types/RolesInfo";
|
||||
|
||||
export const MockRole: RolesEnum = {
|
||||
export const MockRole: RolesInfo = {
|
||||
id: "developer",
|
||||
prettyname: "Developer",
|
||||
};
|
||||
|
||||
@@ -6,10 +6,11 @@ export const MockUnicorn: UnicornInfo = {
|
||||
firstName: "Joe",
|
||||
lastName: "Other",
|
||||
id: "joe",
|
||||
locale: "en",
|
||||
locales: ["en"],
|
||||
description: "Exists",
|
||||
color: "red",
|
||||
roles: [MockRole.id],
|
||||
rolesMeta: [MockRole],
|
||||
socials: {
|
||||
twitter: "twtrusrname",
|
||||
github: "ghusrname",
|
||||
@@ -36,10 +37,11 @@ export const MockUnicornTwo: UnicornInfo = {
|
||||
firstName: "Diane",
|
||||
lastName: "",
|
||||
id: "diane",
|
||||
locale: "en",
|
||||
locales: ["en"],
|
||||
description: "Is a human",
|
||||
color: "blue",
|
||||
roles: [MockRole.id],
|
||||
rolesMeta: [MockRole],
|
||||
socials: {
|
||||
twitter: "twtrusrname2",
|
||||
github: "ghusrname2",
|
||||
|
||||
@@ -2,7 +2,8 @@ import type { VercelRequest, VercelResponse } from "@vercel/node";
|
||||
import Fuse from "fuse.js";
|
||||
import { createRequire } from "node:module";
|
||||
|
||||
import type { ExtendedPostInfo } from "types/index";
|
||||
import { CollectionInfo, UnicornInfo, type PostInfo } from "types/index";
|
||||
import type { ServerReturnType } from "../src/views/search/types";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const searchIndex = require("./searchIndex.json");
|
||||
@@ -12,7 +13,7 @@ const collectionIndex = Fuse.parseIndex(searchIndex.collectionIndex);
|
||||
const posts = searchIndex.posts;
|
||||
const collections = searchIndex.collections;
|
||||
|
||||
const postFuse = new Fuse<ExtendedPostInfo>(
|
||||
const postFuse = new Fuse<PostInfo>(
|
||||
posts,
|
||||
{
|
||||
threshold: 0.3,
|
||||
@@ -23,7 +24,7 @@ const postFuse = new Fuse<ExtendedPostInfo>(
|
||||
postIndex,
|
||||
);
|
||||
|
||||
const collectionFuse = new Fuse(
|
||||
const collectionFuse = new Fuse<CollectionInfo>(
|
||||
collections,
|
||||
{
|
||||
threshold: 0.3,
|
||||
@@ -34,35 +35,53 @@ const collectionFuse = new Fuse(
|
||||
collectionIndex,
|
||||
);
|
||||
|
||||
export default async (req: VercelRequest, res: VercelResponse) => {
|
||||
const unicorns: Record<string, UnicornInfo> = searchIndex.unicorns;
|
||||
|
||||
function runQuery(req: VercelRequest): ServerReturnType {
|
||||
// TODO: `pickdeep` only required fields
|
||||
const searchStr = req?.query?.query as string;
|
||||
if (!searchStr) {
|
||||
res.send({
|
||||
return {
|
||||
unicorns: {},
|
||||
posts: [],
|
||||
totalPosts: 0,
|
||||
collections: [],
|
||||
totalCollections: 0,
|
||||
});
|
||||
return;
|
||||
};
|
||||
}
|
||||
if (searchStr === "*") {
|
||||
res.send({
|
||||
return {
|
||||
unicorns,
|
||||
posts,
|
||||
totalPosts: posts.length,
|
||||
collections,
|
||||
totalCollections: collections.length,
|
||||
});
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
const searchedPosts = postFuse.search(searchStr).map((item) => item.item);
|
||||
const searchedCollections = collectionFuse
|
||||
.search(searchStr)
|
||||
.map((item) => item.item);
|
||||
res.send({
|
||||
|
||||
const searchedUnicorns: Record<string, UnicornInfo> = {};
|
||||
for (const post of searchedPosts) {
|
||||
for (const id of post.authors) searchedUnicorns[id] = unicorns[id];
|
||||
}
|
||||
for (const collection of searchedCollections) {
|
||||
for (const id of collection.authors) searchedUnicorns[id] = unicorns[id];
|
||||
}
|
||||
|
||||
return {
|
||||
unicorns: searchedUnicorns,
|
||||
posts: searchedPosts,
|
||||
totalPosts: searchedPosts.length,
|
||||
collections: searchedCollections,
|
||||
totalCollections: searchedCollections.length,
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
export default async (req: VercelRequest, res: VercelResponse) => {
|
||||
const response = runQuery(req);
|
||||
res.send(response);
|
||||
};
|
||||
|
||||
@@ -2,7 +2,7 @@ import Fuse from "fuse.js";
|
||||
import * as fs from "fs";
|
||||
import * as path from "path";
|
||||
import * as api from "utils/api";
|
||||
import { PostInfo, CollectionInfo } from "types/index";
|
||||
import { PostInfo, CollectionInfo, UnicornInfo } from "types/index";
|
||||
|
||||
const posts = api.getPostsByLang("en");
|
||||
const collections = api.getCollectionsByLang("en");
|
||||
@@ -87,5 +87,18 @@ const createCollectionIndex = () => {
|
||||
const postIndex = createPostIndex();
|
||||
const collectionIndex = createCollectionIndex();
|
||||
|
||||
const json = JSON.stringify({ postIndex, posts, collectionIndex, collections });
|
||||
const unicorns: Record<string, UnicornInfo> = api
|
||||
.getUnicornsByLang("en")
|
||||
.reduce((obj, unicorn) => {
|
||||
obj[unicorn.id] = unicorn;
|
||||
return obj;
|
||||
}, {});
|
||||
|
||||
const json = JSON.stringify({
|
||||
postIndex,
|
||||
posts,
|
||||
collectionIndex,
|
||||
collections,
|
||||
unicorns,
|
||||
});
|
||||
fs.writeFileSync(path.resolve(process.cwd(), "./api/searchIndex.json"), json);
|
||||
|
||||
@@ -33,10 +33,10 @@ import YourGuide from "src/views/collections/framework-field-guide/segments/your
|
||||
import CodeBlock from "src/views/collections/framework-field-guide/segments/code-block.astro";
|
||||
import TheRestContainer from "src/views/collections/framework-field-guide/segments/the-rest-container.astro";
|
||||
import Pricing from "src/views/collections/framework-field-guide/segments/pricing.astro";
|
||||
import { unicorns } from "utils/data";
|
||||
import SignUp from "src/views/collections/framework-field-guide/segments/sign-up.astro";
|
||||
import WhyLearnAllThree from "src/views/collections/framework-field-guide/segments/why-learn-all-three.astro";
|
||||
import WhatDoIGet from "src/views/collections/framework-field-guide/segments/what-do-i-get.astro";
|
||||
import { getUnicornById } from "utils/api";
|
||||
---
|
||||
|
||||
<Barebones>
|
||||
@@ -45,7 +45,7 @@ import WhatDoIGet from "src/views/collections/framework-field-guide/segments/wha
|
||||
pathName={`/collections/framework-field-guide`}
|
||||
title={"The Framework Field Guide"}
|
||||
description={"A practical and free way to teach Angular, React, and Vue all at once, so you can choose the right tool for the job and learn the underlying concepts in depth."}
|
||||
unicornsData={[unicorns.find((uni) => uni.id === "crutchcorn")]}
|
||||
unicornsData={[getUnicornById("crutchcorn", "en")]}
|
||||
publishedTime={"2022-12-01T13:45:00.284Z"}
|
||||
type={"book"}
|
||||
shareImage={"/custom-content/collections/framework-field-guide/framework_field_guide_social.png"}
|
||||
|
||||
@@ -1,17 +1,26 @@
|
||||
---
|
||||
import { PostInfo } from "types/index";
|
||||
import { Languages, PostInfo } from "types/index";
|
||||
import { PostCardGrid } from "src/components/post-card/post-card-grid";
|
||||
import { getUnicornProfilePicMap } from "utils/get-unicorn-profile-pic-map";
|
||||
import { Pagination } from "components/pagination/pagination";
|
||||
import { Page } from "astro";
|
||||
import * as api from "utils/api";
|
||||
|
||||
export interface PageProps {
|
||||
posts: PostInfo[];
|
||||
page: Pick<Page<any>, "currentPage" | "lastPage">;
|
||||
locale: Languages;
|
||||
}
|
||||
|
||||
const { posts, page } = Astro.props as PageProps;
|
||||
const { posts, page, locale } = Astro.props as PageProps;
|
||||
const unicornProfilePicMap = await getUnicornProfilePicMap();
|
||||
|
||||
const postAuthors = new Map(
|
||||
[...new Set(posts.flatMap((p) => p.authors))].map((id) => [
|
||||
id,
|
||||
api.getUnicornById(id, locale),
|
||||
]),
|
||||
);
|
||||
---
|
||||
|
||||
<h1 class="visually-hidden">Posts</h1>
|
||||
@@ -20,6 +29,7 @@ const unicornProfilePicMap = await getUnicornProfilePicMap();
|
||||
expanded={true}
|
||||
aria-label="List of posts"
|
||||
postsToDisplay={posts}
|
||||
postAuthors={postAuthors}
|
||||
unicornProfilePicMap={unicornProfilePicMap}
|
||||
/>
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ProfilePictureMap } from "utils/get-unicorn-profile-pic-map";
|
||||
import { PostInfo } from "types/PostInfo";
|
||||
import { ExtendedCollectionInfo } from "types/CollectionInfo";
|
||||
import { CollectionInfo } from "types/CollectionInfo";
|
||||
import { useMemo } from "preact/hooks";
|
||||
import { UnicornInfo } from "types/UnicornInfo";
|
||||
import { CSSProperties } from "preact/compat";
|
||||
@@ -15,7 +15,8 @@ interface FilterDisplayProps {
|
||||
unicornProfilePicMap: ProfilePictureMap;
|
||||
posts: PostInfo[];
|
||||
|
||||
collections: ExtendedCollectionInfo[];
|
||||
collections: CollectionInfo[];
|
||||
unicornsMap: Map<string, UnicornInfo>,
|
||||
selectedTags: string[];
|
||||
setSelectedTags: (tags: string[]) => void;
|
||||
selectedAuthorIds: string[];
|
||||
@@ -33,6 +34,7 @@ interface FilterDisplayProps {
|
||||
export const FilterDisplay = ({
|
||||
unicornProfilePicMap,
|
||||
collections,
|
||||
unicornsMap,
|
||||
posts,
|
||||
sort,
|
||||
setSort,
|
||||
@@ -80,27 +82,14 @@ export const FilterDisplay = ({
|
||||
const authors = useMemo(() => {
|
||||
const postAuthorIdToPostNumMap = new Map<string, number>();
|
||||
|
||||
const authors: UnicornInfo[] = [];
|
||||
posts.forEach((post) => {
|
||||
post.authorsMeta.forEach((author) => {
|
||||
authors.push(author);
|
||||
|
||||
const numPosts = postAuthorIdToPostNumMap.get(author.id) || 0;
|
||||
postAuthorIdToPostNumMap.set(author.id, numPosts + 1);
|
||||
post.authors.forEach((author) => {
|
||||
const numPosts = postAuthorIdToPostNumMap.get(author) || 0;
|
||||
postAuthorIdToPostNumMap.set(author, numPosts + 1);
|
||||
});
|
||||
});
|
||||
|
||||
collections.forEach((collection) => {
|
||||
collection.authorsMeta.forEach((author) => {
|
||||
authors.push(author);
|
||||
});
|
||||
});
|
||||
|
||||
const uniqueAuthors = new Map<string, UnicornInfo>();
|
||||
authors.forEach((author) => {
|
||||
uniqueAuthors.set(author.id, author);
|
||||
});
|
||||
return Array.from(uniqueAuthors.values())
|
||||
return Array.from(unicornsMap.values())
|
||||
.sort((a, b) => a.name.localeCompare(b.name))
|
||||
.map((author) => ({
|
||||
...author,
|
||||
|
||||
@@ -9,7 +9,8 @@ import {
|
||||
queryByText,
|
||||
getByTestId,
|
||||
} from "@testing-library/preact";
|
||||
import SearchPage, { ServerReturnType } from "./search-page";
|
||||
import SearchPage from "./search-page";
|
||||
import type { ServerReturnType } from "./types";
|
||||
import { rest } from "msw";
|
||||
import { setupServer } from "msw/node";
|
||||
import { MockCanonicalPost, MockPost } from "../../../__mocks__/data/mock-post";
|
||||
@@ -67,6 +68,7 @@ describe("Search page", () => {
|
||||
|
||||
test("Should show search results for posts", async () => {
|
||||
mockFetch(() => ({
|
||||
unicorns: {},
|
||||
posts: [MockPost],
|
||||
totalPosts: 1,
|
||||
totalCollections: 0,
|
||||
@@ -84,6 +86,7 @@ describe("Search page", () => {
|
||||
|
||||
test("Should show search results for collections", async () => {
|
||||
mockFetch(() => ({
|
||||
unicorns: {},
|
||||
posts: [],
|
||||
totalPosts: 0,
|
||||
totalCollections: 1,
|
||||
@@ -120,6 +123,7 @@ describe("Search page", () => {
|
||||
|
||||
test("Should show 'nothing found'", async () => {
|
||||
mockFetch(() => ({
|
||||
unicorns: {},
|
||||
posts: [],
|
||||
totalPosts: 0,
|
||||
totalCollections: 0,
|
||||
@@ -139,6 +143,7 @@ describe("Search page", () => {
|
||||
|
||||
test("Remove collections header when none found", async () => {
|
||||
mockFetch(() => ({
|
||||
unicorns: {},
|
||||
posts: [MockPost],
|
||||
totalPosts: 1,
|
||||
totalCollections: 0,
|
||||
@@ -159,6 +164,7 @@ describe("Search page", () => {
|
||||
|
||||
test("Remove posts header when none found", async () => {
|
||||
mockFetch(() => ({
|
||||
unicorns: {},
|
||||
posts: [],
|
||||
totalPosts: 0,
|
||||
totalCollections: 1,
|
||||
@@ -179,6 +185,7 @@ describe("Search page", () => {
|
||||
|
||||
test("Filter by tag works on desktop sidebar", async () => {
|
||||
mockFetch(() => ({
|
||||
unicorns: {},
|
||||
posts: [
|
||||
{ ...MockPost, tags: ["Angular"], title: "One blog post" },
|
||||
{ ...MockCanonicalPost, tags: [], title: "Two blog post" },
|
||||
@@ -210,6 +217,7 @@ describe("Search page", () => {
|
||||
|
||||
test("Filter by author works on desktop sidebar", async () => {
|
||||
mockFetch(() => ({
|
||||
unicorns: {},
|
||||
posts: [
|
||||
{
|
||||
...MockPost,
|
||||
@@ -251,6 +259,7 @@ describe("Search page", () => {
|
||||
|
||||
test("Filter by content type work on radio group buttons", async () => {
|
||||
mockFetch(() => ({
|
||||
unicorns: {},
|
||||
posts: [{ ...MockPost, title: "One blog post" }],
|
||||
totalPosts: 1,
|
||||
totalCollections: 1,
|
||||
@@ -293,6 +302,7 @@ describe("Search page", () => {
|
||||
global.innerWidth = 2000;
|
||||
|
||||
mockFetch(() => ({
|
||||
unicorns: {},
|
||||
posts: [
|
||||
{
|
||||
...MockPost,
|
||||
@@ -352,6 +362,7 @@ describe("Search page", () => {
|
||||
test("Sort by date works on mobile radio group buttons", async () => {
|
||||
global.innerWidth = 500;
|
||||
mockFetch(() => ({
|
||||
unicorns: {},
|
||||
posts: [
|
||||
{
|
||||
...MockPost,
|
||||
@@ -411,6 +422,7 @@ describe("Search page", () => {
|
||||
test("Pagination - Changing pages to page 2 shows second page of results", async () => {
|
||||
// 6 posts per page
|
||||
mockFetch(() => ({
|
||||
unicorns: {},
|
||||
posts: [
|
||||
{ ...MockPost, slug: `blog-post-1`, title: "One blog post" },
|
||||
{ ...MockPost, slug: `blog-post-2`, title: "Two blog post" },
|
||||
@@ -473,6 +485,7 @@ describe("Search page", () => {
|
||||
global.innerWidth = 2000;
|
||||
// 6 posts per page
|
||||
mockFetch(() => ({
|
||||
unicorns: {},
|
||||
posts: [
|
||||
{
|
||||
...MockPost,
|
||||
@@ -603,6 +616,7 @@ describe("Search page", () => {
|
||||
// Search page, sort order, etc
|
||||
test("Make sure that initial search props are not thrown away", async () => {
|
||||
mockFetch(() => ({
|
||||
unicorns: {},
|
||||
posts: [
|
||||
{
|
||||
...MockPost,
|
||||
@@ -762,6 +776,7 @@ describe("Search page", () => {
|
||||
global.innerWidth = 2000;
|
||||
|
||||
mockFetch(() => ({
|
||||
unicorns: {},
|
||||
posts: [
|
||||
{
|
||||
...MockPost,
|
||||
@@ -830,6 +845,7 @@ describe("Search page", () => {
|
||||
|
||||
test("Make sure that re-searches reset page to 1 and preserve tags, authors, etc", async () => {
|
||||
mockFetch(() => ({
|
||||
unicorns: {},
|
||||
posts: [
|
||||
{
|
||||
...MockPost,
|
||||
@@ -981,6 +997,7 @@ describe("Search page", () => {
|
||||
|
||||
test("Make sure that re-searches to empty string reset page, tags, authors, etc", async () => {
|
||||
mockFetch(() => ({
|
||||
unicorns: {},
|
||||
posts: [
|
||||
{
|
||||
...MockPost,
|
||||
@@ -1132,6 +1149,7 @@ describe("Search page", () => {
|
||||
|
||||
test("Back button should show last query", async () => {
|
||||
mockFetch(() => ({
|
||||
unicorns: {},
|
||||
posts: [],
|
||||
totalPosts: 0,
|
||||
totalCollections: 0,
|
||||
|
||||
@@ -21,7 +21,6 @@ import style from "./search-page.module.scss";
|
||||
import { PostCardGrid } from "components/post-card/post-card-grid";
|
||||
import { SubHeader } from "components/subheader/subheader";
|
||||
import { Fragment } from "preact";
|
||||
import { ExtendedCollectionInfo } from "types/CollectionInfo";
|
||||
import { CollectionCard } from "components/collection-card/collection-card";
|
||||
import { FilterDisplay } from "./components/filter-display";
|
||||
import { useElementSize } from "../../hooks/use-element-size";
|
||||
@@ -43,6 +42,8 @@ import {
|
||||
import { debounce } from "utils/debounce";
|
||||
import { SortType } from "./components/types";
|
||||
import { SearchResultCount } from "./components/search-result-count";
|
||||
import { ServerReturnType } from "./types";
|
||||
import { CollectionInfo } from "types/CollectionInfo";
|
||||
|
||||
const DEFAULT_SORT = "relevance";
|
||||
const DEFAULT_CONTENT_TO_DISPLAY = "all";
|
||||
@@ -53,13 +54,6 @@ interface SearchPageProps {
|
||||
|
||||
const MAX_POSTS_PER_PAGE = 6;
|
||||
|
||||
export interface ServerReturnType {
|
||||
posts: PostInfo[];
|
||||
totalPosts: number;
|
||||
collections: ExtendedCollectionInfo[];
|
||||
totalCollections: number;
|
||||
}
|
||||
|
||||
function SearchPageBase({ unicornProfilePicMap }: SearchPageProps) {
|
||||
const { urlParams, pushState } = useSearchParams();
|
||||
|
||||
@@ -141,11 +135,12 @@ function SearchPageBase({ unicornProfilePicMap }: SearchPageProps) {
|
||||
},
|
||||
queryKey: ["search", debouncedSearch],
|
||||
initialData: {
|
||||
unicorns: {},
|
||||
posts: [],
|
||||
totalPosts: 0,
|
||||
collections: [],
|
||||
totalCollections: 0,
|
||||
} as ServerReturnType,
|
||||
},
|
||||
refetchOnWindowFocus: false,
|
||||
retry: false,
|
||||
enabled,
|
||||
@@ -271,7 +266,7 @@ function SearchPageBase({ unicornProfilePicMap }: SearchPageProps) {
|
||||
});
|
||||
}, [data, page, sort, selectedUnicorns, selectedTags]);
|
||||
|
||||
const filteredAndSortedCollections = useMemo(() => {
|
||||
const filteredAndSortedCollections: CollectionInfo[] = useMemo(() => {
|
||||
const collections = [...data.collections];
|
||||
|
||||
if (sort && sort !== "relevance") {
|
||||
@@ -365,6 +360,7 @@ function SearchPageBase({ unicornProfilePicMap }: SearchPageProps) {
|
||||
unicornProfilePicMap={unicornProfilePicMap}
|
||||
collections={data.collections}
|
||||
posts={data.posts}
|
||||
unicornsMap={new Map(Object.entries(data.unicorns))}
|
||||
selectedTags={selectedTags}
|
||||
setSelectedTags={setSelectedTags}
|
||||
selectedAuthorIds={selectedUnicorns}
|
||||
@@ -488,6 +484,9 @@ function SearchPageBase({ unicornProfilePicMap }: SearchPageProps) {
|
||||
<CollectionCard
|
||||
unicornProfilePicMap={unicornProfilePicMap}
|
||||
collection={collection}
|
||||
authors={collection.authors.map(id => data.unicorns[id])}
|
||||
// TODO: post count should be sourced from the collection info
|
||||
posts={[]}
|
||||
headingTag="h3"
|
||||
/>
|
||||
</li>
|
||||
@@ -509,6 +508,7 @@ function SearchPageBase({ unicornProfilePicMap }: SearchPageProps) {
|
||||
<PostCardGrid
|
||||
aria-labelledby={"articles-header"}
|
||||
postsToDisplay={posts}
|
||||
postAuthors={new Map(Object.entries(data.unicorns))}
|
||||
postHeadingTag="h3"
|
||||
unicornProfilePicMap={unicornProfilePicMap}
|
||||
/>
|
||||
|
||||
11
src/views/search/types.ts
Normal file
11
src/views/search/types.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { CollectionInfo } from "types/CollectionInfo";
|
||||
import { PostInfo } from "types/PostInfo";
|
||||
import { UnicornInfo } from "types/UnicornInfo";
|
||||
|
||||
export interface ServerReturnType {
|
||||
unicorns: Record<string, UnicornInfo>;
|
||||
posts: PostInfo[];
|
||||
totalPosts: number;
|
||||
collections: CollectionInfo[];
|
||||
totalCollections: number;
|
||||
}
|
||||
Reference in New Issue
Block a user