11'use client' ;
22
33import GraphqlPagination from '@/app/[locale]/dashboard/components/GraphqlPagination/graphqlPagination' ;
4+ import Link from 'next/link' ;
45import { useRouter } from 'next/navigation' ;
56import {
67 Button ,
@@ -126,7 +127,7 @@ const initialState: QueryParams = {
126127 query : '' ,
127128 sort : 'recent' ,
128129 order : '' ,
129- types : 'dataset,usecase,aimodel,collaborative' , // Default: search all types
130+ types : 'dataset,usecase,aimodel,collaborative,publisher ' , // Default: search all types
130131} ;
131132
132133// Query Reducer
@@ -193,15 +194,15 @@ const useUrlParams = (
193194 currentPage : pageParam ? Number ( pageParam ) : 1 ,
194195 filters,
195196 query : urlParams . get ( 'query' ) || '' ,
196- types : typesParam || 'dataset,usecase,aimodel,collaborative' ,
197+ types : typesParam || 'dataset,usecase,aimodel,collaborative,publisher ' ,
197198 } ;
198199
199200 setQueryParams ( { type : 'INITIALIZE' , payload : initialParams } ) ;
200201 } , [ setQueryParams ] ) ;
201202
202203 useEffect ( ( ) => {
203204 const filtersString = Object . entries ( queryParams . filters )
204- . filter ( ( [ _key , values ] ) => values . length > 0 )
205+ . filter ( ( [ , values ] ) => values . length > 0 )
205206 . map ( ( [ key , values ] ) => `${ key } =${ values . join ( ',' ) } ` )
206207 . join ( '&' ) ;
207208
@@ -313,8 +314,8 @@ const UnifiedListingComponent: React.FC<UnifiedListingProps> = ({
313314 useUrlParams ( queryParams , setQueryParams , setVariables ) ;
314315 const latestFetchId = useRef ( 0 ) ;
315316
316- const [ error , setError ] = useState < string | null > ( null ) ;
317- const [ isLoading , setIsLoading ] = useState ( false ) ;
317+ const [ , setError ] = useState < string | null > ( null ) ;
318+ const [ , setIsLoading ] = useState ( false ) ;
318319
319320 useEffect ( ( ) => {
320321 if ( variables ) {
@@ -422,6 +423,13 @@ const UnifiedListingComponent: React.FC<UnifiedListingProps> = ({
422423 return `/aimodels/${ item . id } ` ;
423424 case 'collaborative' :
424425 return `/collaboratives/${ item . slug } ` ;
426+ case 'publisher' :
427+ // For publishers, redirect based on publisher_type
428+ if ( item . publisher_type === 'organization' ) {
429+ return `/publishers/organization/${ item . id } ` ;
430+ } else {
431+ return `/publishers/${ item . id } ` ;
432+ }
425433 default :
426434 return `${ redirectionURL } /${ item . id } ` ;
427435 }
@@ -447,24 +455,26 @@ const UnifiedListingComponent: React.FC<UnifiedListingProps> = ({
447455 < div className = "rounded-lg border border-gray-200 flex flex-wrap gap-2 bg-white p-3" >
448456 < Button
449457 kind = {
450- queryParams . types === 'dataset,usecase,aimodel,collaborative'
458+ queryParams . types === 'dataset,usecase,aimodel,collaborative,publisher '
451459 ? 'primary'
452460 : 'secondary'
453461 }
454- onClick = { ( ) => handleTypeFilter ( 'dataset,usecase,aimodel,collaborative' ) }
462+ onClick = { ( ) => handleTypeFilter ( 'dataset,usecase,aimodel,collaborative,publisher ' ) }
455463 size = "slim"
456464 >
457465 All Results
458466 { typeCounts . dataset !== undefined &&
459467 typeCounts . usecase !== undefined &&
460468 typeCounts . aimodel !== undefined &&
461- typeCounts . collaborative !== undefined && (
469+ typeCounts . collaborative !== undefined &&
470+ typeCounts . publisher !== undefined && (
462471 < span className = "text-xs ml-1" >
463472 (
464473 { ( typeCounts . dataset || 0 ) +
465474 ( typeCounts . usecase || 0 ) +
466475 ( typeCounts . aimodel || 0 ) +
467- ( typeCounts . collaborative || 0 ) }
476+ ( typeCounts . collaborative || 0 ) +
477+ ( typeCounts . publisher || 0 ) }
468478 )
469479 </ span >
470480 ) }
@@ -525,6 +535,20 @@ const UnifiedListingComponent: React.FC<UnifiedListingProps> = ({
525535 </ span >
526536 ) }
527537 </ Button >
538+ < Button
539+ kind = {
540+ queryParams . types === 'publisher' ? 'primary' : 'secondary'
541+ }
542+ onClick = { ( ) => handleTypeFilter ( 'publisher' ) }
543+ size = "slim"
544+ >
545+ Publishers
546+ { typeCounts . publisher !== undefined && (
547+ < span className = "text-xs ml-1" >
548+ ({ typeCounts . publisher || 0 } )
549+ </ span >
550+ ) }
551+ </ Button >
528552 </ div >
529553
530554 < div className = "flex flex-wrap items-center justify-between gap-5 rounded-2 py-2 lg:flex-nowrap" >
@@ -664,15 +688,22 @@ const UnifiedListingComponent: React.FC<UnifiedListingProps> = ({
664688 item . is_individual_dataset ||
665689 item . is_individual_usecase ||
666690 item . is_individual_model ||
667- item . is_individual_collaborative ;
668-
669- const image = isIndividual
670- ? item ?. user ?. profile_picture
671- ? `${ process . env . NEXT_PUBLIC_BACKEND_URL } /${ item . user . profile_picture } `
672- : '/profile.png'
673- : item ?. organization ?. logo
674- ? `${ process . env . NEXT_PUBLIC_BACKEND_URL } /${ item . organization . logo } `
675- : '/org.png' ;
691+ item . is_individual_collaborative ||
692+ ( item . type === 'publisher' && item . publisher_type === 'user' ) ;
693+
694+ const image = item . type === 'publisher'
695+ ? item . logo
696+ ? `${ process . env . NEXT_PUBLIC_BACKEND_URL } /${ item . logo } `
697+ : item . publisher_type === 'user'
698+ ? '/profile.png'
699+ : '/org.png'
700+ : isIndividual
701+ ? item ?. user ?. profile_picture
702+ ? `${ process . env . NEXT_PUBLIC_BACKEND_URL } /${ item . user . profile_picture } `
703+ : '/profile.png'
704+ : item ?. organization ?. logo
705+ ? `${ process . env . NEXT_PUBLIC_BACKEND_URL } /${ item . organization . logo } `
706+ : '/org.png' ;
676707
677708 const geographies =
678709 item . geographies && item . geographies . length > 0
@@ -685,7 +716,39 @@ const UnifiedListingComponent: React.FC<UnifiedListingProps> = ({
685716 const MetadataContent = [ ] ;
686717
687718 // Type-specific metadata
688- if ( item . type === 'collaborative' ) {
719+ if ( item . type === 'publisher' ) {
720+ // Publisher-specific metadata
721+ MetadataContent . push ( {
722+ icon : Icons . calendar as any ,
723+ label : 'Joined' ,
724+ value : formatDate ( item . created ) ,
725+ tooltip : 'Date joined' ,
726+ } ) ;
727+
728+ MetadataContent . push ( {
729+ icon : Icons . dataset as any ,
730+ label : 'Datasets' ,
731+ value : item . published_datasets_count ?. toString ( ) || '0' ,
732+ tooltip : 'Published datasets' ,
733+ } ) ;
734+
735+ MetadataContent . push ( {
736+ icon : Icons . usecase as any ,
737+ label : 'Use Cases' ,
738+ value : item . published_usecases_count ?. toString ( ) || '0' ,
739+ tooltip : 'Published use cases' ,
740+ } ) ;
741+
742+ // Add members count for organizations
743+ if ( item . publisher_type === 'organization' && item . members_count > 0 ) {
744+ MetadataContent . push ( {
745+ icon : Icons . users as any ,
746+ label : 'Members' ,
747+ value : item . members_count ?. toString ( ) || '0' ,
748+ tooltip : 'Organization members' ,
749+ } ) ;
750+ }
751+ } else if ( item . type === 'collaborative' ) {
689752 MetadataContent . push ( {
690753 icon : Icons . calendar as any ,
691754 label : 'Started' ,
@@ -774,8 +837,15 @@ const UnifiedListingComponent: React.FC<UnifiedListingProps> = ({
774837
775838 const FooterContent = [ ] ;
776839
777- // Add sector icon - handle collaborative format vs other types
778- if ( item . type === 'collaborative' ) {
840+ // Add sector icon - handle different types
841+ if ( item . type === 'publisher' ) {
842+ // For publishers, show publisher type badge
843+ FooterContent . push ( {
844+ icon : item . publisher_type === 'organization' ? '/org.png' : '/profile.png' ,
845+ label : item . publisher_type === 'organization' ? 'Organization' : 'Individual Publisher' ,
846+ tooltip : item . publisher_type === 'organization' ? 'Organization Publisher' : 'Individual Publisher' ,
847+ } ) ;
848+ } else if ( item . type === 'collaborative' ) {
779849 // For collaboratives, match listing page format exactly
780850 if ( item . sectors && item . sectors . length > 0 ) {
781851 const sectorName = typeof item . sectors [ 0 ] === 'string' ? item . sectors [ 0 ] : item . sectors [ 0 ] ?. name ;
@@ -809,38 +879,109 @@ const UnifiedListingComponent: React.FC<UnifiedListingProps> = ({
809879 } ) ;
810880 }
811881
812- // Add published by info
813- FooterContent . push ( {
814- icon : image as any ,
815- label : 'Published by' ,
816- tooltip : `${ isIndividual ? item . user ?. name : item . organization ?. name } ` ,
817- } ) ;
882+ // Add published by info (skip for publishers since they are the publishers themselves)
883+ if ( item . type !== 'publisher' ) {
884+ FooterContent . push ( {
885+ icon : image as any ,
886+ label : 'Published by' ,
887+ tooltip : `${ isIndividual ? item . user ?. name : item . organization ?. name } ` ,
888+ } ) ;
889+ }
818890
819891 const commonProps = {
820- title : item . title ,
821- description : stripMarkdown ( item . description || '' ) ,
892+ title : item . title || item . name || '' ,
893+ description : stripMarkdown ( item . description || item . bio || '' ) ,
822894 metadataContent : MetadataContent ,
823- tag : item . tags ,
824- formats : item . type === 'dataset' ? item . formats : [ ] ,
895+ tag : item . tags || [ ] ,
896+ formats : item . type === 'dataset' ? item . formats || [ ] : [ ] ,
825897 footerContent : FooterContent ,
826898 imageUrl : '' ,
827899 } ;
828900
829- if ( item . logo ) {
901+ // Handle different image sources for publishers vs other types
902+ if ( item . type === 'publisher' ) {
903+ if ( item . logo ) {
904+ commonProps . imageUrl = `${ process . env . NEXT_PUBLIC_BACKEND_URL } /${ item . logo } ` ;
905+ } else if ( item . profile_picture ) {
906+ commonProps . imageUrl = `${ process . env . NEXT_PUBLIC_BACKEND_URL } /${ item . profile_picture } ` ;
907+ }
908+ } else if ( item . logo ) {
830909 commonProps . imageUrl = `${ process . env . NEXT_PUBLIC_BACKEND_URL } /${ item . logo } ` ;
831910 }
832911
833- return (
834- < Card
835- { ...commonProps }
836- key = { `${ item . type } -${ item . id } ` }
837- variation = {
838- view === 'expanded' ? 'expanded' : 'collapsed'
839- }
840- iconColor = "warning"
841- href = { getRedirectUrl ( item ) }
842- />
843- ) ;
912+ // Use different rendering for publishers vs other types
913+ if ( item . type === 'publisher' ) {
914+ return (
915+ < Link
916+ href = { getRedirectUrl ( item ) }
917+ key = { item . type === 'publisher' ? `${ item . type } -${ item . publisher_type } -${ item . id } ` : `${ item . type } -${ item . id } ` }
918+ className = "flex flex-col gap-4 rounded-4 p-6 shadow-card"
919+ >
920+ < div className = "flex items-center gap-4" >
921+ < img
922+ height = { 80 }
923+ width = { 80 }
924+ src = {
925+ item . publisher_type === 'user'
926+ ? item . profile_picture
927+ ? `${ process . env . NEXT_PUBLIC_BACKEND_URL } /${ item . profile_picture } `
928+ : '/profile.png'
929+ : item . logo
930+ ? `${ process . env . NEXT_PUBLIC_BACKEND_URL } /${ item . logo } `
931+ : '/org.png'
932+ }
933+ alt = "publisher logo"
934+ className = "rounded-2 border-2 border-solid border-greyExtralight object-contain p-2"
935+ />
936+ < div className = "flex flex-col gap-2" >
937+ < Text className = "text-primaryBlue" fontWeight = "semibold" >
938+ { item . name || item . title }
939+ </ Text >
940+ < div className = "flex w-fit rounded-full border-1 border-solid border-[#D5E1EA] bg-[#E9EFF4] px-3 py-1" >
941+ < Text variant = "bodySm" >
942+ { item . publisher_type === 'user'
943+ ? 'Individual Publisher'
944+ : 'Organization' }
945+ </ Text >
946+ </ div >
947+ </ div >
948+ </ div >
949+ < div className = "flex flex-wrap gap-3" >
950+ < div className = "flex w-fit rounded-full border-1 border-solid border-[#D5E1EA] px-3 py-1" >
951+ < Text variant = "bodySm" className = "text-primaryBlue" >
952+ { item . published_usecases_count || 0 } Use Cases
953+ </ Text >
954+ </ div >
955+ < div className = "flex w-fit rounded-full border-1 border-solid border-[#D5E1EA] px-3 py-1" >
956+ < Text variant = "bodySm" className = "text-primaryBlue" >
957+ { item . published_datasets_count || 0 } Datasets
958+ </ Text >
959+ </ div >
960+ </ div >
961+ { ( item . bio || item . description ) && (
962+ < div >
963+ < Text className = "line-clamp-2" >
964+ { ( item . bio || item . description ) ?. length > 220
965+ ? ( item . bio || item . description ) . slice ( 0 , 220 ) + '...'
966+ : ( item . bio || item . description ) }
967+ </ Text >
968+ </ div >
969+ ) }
970+ </ Link >
971+ ) ;
972+ } else {
973+ return (
974+ < Card
975+ { ...commonProps }
976+ key = { item . type === 'publisher' ? `${ item . type } -${ item . publisher_type } -${ item . id } ` : `${ item . type } -${ item . id } ` }
977+ variation = {
978+ view === 'expanded' ? 'expanded' : 'collapsed'
979+ }
980+ iconColor = "warning"
981+ href = { getRedirectUrl ( item ) }
982+ />
983+ ) ;
984+ }
844985 } ) }
845986 </ GraphqlPagination >
846987 ) : (
0 commit comments