Skip to content

Commit a82b4fc

Browse files
committed
include publishers in unified listing page
1 parent c076812 commit a82b4fc

1 file changed

Lines changed: 184 additions & 43 deletions

File tree

app/[locale]/(user)/search/components/UnifiedListingComponent.tsx

Lines changed: 184 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
'use client';
22

33
import GraphqlPagination from '@/app/[locale]/dashboard/components/GraphqlPagination/graphqlPagination';
4+
import Link from 'next/link';
45
import { useRouter } from 'next/navigation';
56
import {
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

Comments
 (0)