Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions components/Search/SearchSuggestions.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useState } from 'react';
import { FileText, History, Search, X, ArrowRight, User, Hash, HelpCircle } from 'lucide-react';
import Icon from '@/components/ui/icons/Icon';
import { useSearchSuggestions } from '@/hooks/useSearchSuggestions';
import { cn } from '@/utils/styles';
import { SearchSuggestion } from '@/types/search';
Expand Down Expand Up @@ -81,6 +82,8 @@ export function SearchSuggestions({
const isUserSuggestion =
suggestion.entityType === 'user' || suggestion.entityType === 'author';
const isTopicSuggestion = suggestion.entityType === 'hub';
const isPostSuggestion = suggestion.entityType === 'post';
const isGrantPost = isPostSuggestion && suggestion?.documentType === 'GRANT';

// Safely access nested properties
const safeGetAuthorsList = () => {
Expand Down Expand Up @@ -130,15 +133,6 @@ export function SearchSuggestions({
return 'Research Topic';
};

// Get the appropriate icon for the suggestion type
const getIcon = () => {
if (suggestion.isRecent) return <History className="h-6 w-6 text-gray-600" />;
if (isPaperSuggestion) return <FileText className="h-6 w-6 text-gray-600" />;
if (isUserSuggestion) return <User className="h-6 w-6 text-gray-600" />;
if (isTopicSuggestion) return <Hash className="h-6 w-6 text-gray-600" />;
return <HelpCircle className="h-6 w-6 text-gray-600" />; // Default with a more distinctive fallback icon
};

// Get the smaller icon variant for dropdown mode
const getSmallIcon = () => {
if (suggestion.isRecent)
Expand All @@ -161,6 +155,14 @@ export function SearchSuggestions({
}
if (isTopicSuggestion)
return <Hash className="h-5 w-8 text-gray-500 mt-0.5 flex-shrink-0" />;
if (isGrantPost)
return (
<div style={{ padding: '6px' }} className="mt-0.5 flex-shrink-0">
<Icon name="fund" size={20} className="text-gray-500" />
</div>
);
if (isPostSuggestion)
return <FileText className="h-5 w-8 text-gray-500 mt-0.5 flex-shrink-0" />;
return <HelpCircle className="h-5 w-8 text-gray-500 mt-0.5 flex-shrink-0" />; // Default
};

Expand Down
7 changes: 6 additions & 1 deletion types/search.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createTransformer, BaseTransformed } from './transformer';
import { buildWorkUrl, buildAuthorUrl, buildTopicUrl } from '@/utils/url';
import { mapApiContentTypeToClientType } from '@/utils/contentTypeMapping';
import { AuthorProfile } from './authorProfile';
import { ID } from './root';
import { transformTopic } from './topic';
Expand Down Expand Up @@ -42,6 +43,7 @@ export interface PostSuggestion extends BaseSuggestion {
entityType: 'post';
displayName: string;
id: number;
documentType?: string;
}

export interface TopicSuggestion extends BaseSuggestion {
Expand Down Expand Up @@ -176,15 +178,18 @@ export const transformSearchSuggestion = createTransformer<any, SearchSuggestion
};

case 'post':
const documentType = raw.document_type || raw.type;

return {
entityType: 'post',
id: raw.id,
displayName: raw.display_name || 'Untitled Post',
source: raw.source || '',
isRecent: false,
documentType,
url: buildWorkUrl({
id: raw.id,
contentType: 'post',
contentType: mapApiContentTypeToClientType(documentType),
}),
};

Expand Down
22 changes: 22 additions & 0 deletions utils/contentTypeMapping.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,25 @@ export function getContentTypePath(contentType: ContentType): string {

return contentType.toLowerCase();
}

/**
* Maps document types from the API to content types for URL building
* @param documentType The document type from the API (e.g., 'GRANT', 'PREREGISTRATION', 'DISCUSSION')
* @returns The corresponding content type for URL building
*/
export function mapApiContentTypeToClientType(
documentType: string
): 'paper' | 'post' | 'funding_request' | 'preregistration' {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to do cleanup because funding_request and preregistration mean the same thing.

I feel like Nick created this function already in one of his PRs. @nicktytarenko - can you confirm?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  • if i am not mistaken funding_request is the same thing as grant in the web app world.. you can see the evidence in this historical mocked data: https://github.com/ResearchHub/web/blob/main/store/grantStore.ts#L27
    there was naming changes to this entity. so, it's probably still confused in the web app 🤯

  • actually we do not have a function to convert API contentType to the App type, we do it on a fly when we transform the work details response in the types/work.ts.

  • if you pull the latest main into this branch you will see the method for converting WebApptypeToAPIType. it's like the opposite of this

cc @yattias

const contentTypeMap: Record<string, 'paper' | 'post' | 'funding_request' | 'preregistration'> = {
GRANT: 'funding_request',
PREREGISTRATION: 'preregistration',
DISCUSSION: 'post',
ELN: 'post',
NOTE: 'post',
PAPER: 'paper',
QUESTION: 'post',
BOUNTY: 'post',
HYPOTHESIS: 'post',
};
return contentTypeMap[documentType] || 'post';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather we not use post as default. We can return null as well if no appropriate match is found

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm.. if we switch it to null that might potentially break few things and would require a bigger refactor of the codebase to incorporate the new approach which is why it was defaulting to post in the first place.

Pros:

  • We could identify when unknown document types appear

Cons:

  • Requires defensive coding: Every caller would need to handle null explicitly
  • Risk of broken links: Without proper null handling, URLs could break or redirect incorrectly

My recommendation is to keep the post as default and add a warning log. Your call but refactoring would prolly require its own PR and potentially be changing many files.

}