diff --git a/app/[locale]/(user)/collaboratives/[collaborativeSlug]/CollaborativeDetailsClient.tsx b/app/[locale]/(user)/collaboratives/[collaborativeSlug]/CollaborativeDetailsClient.tsx index a6667481..f7a84cad 100644 --- a/app/[locale]/(user)/collaboratives/[collaborativeSlug]/CollaborativeDetailsClient.tsx +++ b/app/[locale]/(user)/collaboratives/[collaborativeSlug]/CollaborativeDetailsClient.tsx @@ -323,7 +323,8 @@ const CollaborativeDetailClient = () => { }); const organizationPublisherHref = (org: any) => { - const path = `/publishers/organization/${org.slug + '_' + org.id}`; + const path = `/publishers/organization/${org.id}`; + // Original: `/publishers/organization/${org.slug + '_' + org.id}`; // Match getPlatformEntityUrl() behavior (absolute to platform host + locale) const platformBaseUrl = ( process.env.NEXT_PUBLIC_PLATFORM_URL || '' diff --git a/app/[locale]/(user)/collaboratives/components/Metadata.tsx b/app/[locale]/(user)/collaboratives/components/Metadata.tsx index 9265857c..bd7ea924 100644 --- a/app/[locale]/(user)/collaboratives/components/Metadata.tsx +++ b/app/[locale]/(user)/collaboratives/components/Metadata.tsx @@ -33,7 +33,7 @@ const Metadata = ({ data, setOpen }: { data: any; setOpen?: any }) => { const metadata = [ { - label: 'Platform URL', + label: 'External Link', value: data.collaborativeBySlug.platformUrl === null ? ( 'N/A' @@ -46,7 +46,7 @@ const Metadata = ({ data, setOpen }: { data: any; setOpen?: any }) => { className="text-primaryBlue underline lg:text-white" variant="bodyLg" > - {platformTitle?.trim() ? platformTitle : 'Visit Platform'} + {platformTitle?.trim() ? platformTitle : 'Open Link'} ), @@ -119,12 +119,12 @@ const Metadata = ({ data, setOpen }: { data: any; setOpen?: any }) => { return match ? `/${match[1].toLowerCase()}` : ''; }; const contributorHref = (contributor: any) => { - const path = `/publishers/${contributor.fullName + '_' + contributor.id}`; + const path = `/publishers/${contributor.id}`; + // Original: `/publishers/${contributor.fullName + '_' + contributor.id}`; // Match getPlatformEntityUrl() behavior (absolute to NEXT_PUBLIC_PLATFORM_URL + locale) - const platformBaseUrl = (process.env.NEXT_PUBLIC_PLATFORM_URL || '').replace( - /\/$/, - '' - ); + const platformBaseUrl = ( + process.env.NEXT_PUBLIC_PLATFORM_URL || '' + ).replace(/\/$/, ''); const localeSegment = getLocaleSegment(); if (platformBaseUrl) return `${platformBaseUrl}${localeSegment}${path}`; diff --git a/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/assign/page.tsx b/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/assign/page.tsx index 4d31e0d8..6b5a7784 100644 --- a/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/assign/page.tsx +++ b/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/assign/page.tsx @@ -4,13 +4,14 @@ import React, { useEffect, useState } from 'react'; import { useParams, useRouter } from 'next/navigation'; import { fetchDatasets } from '@/fetch'; import { graphql } from '@/gql'; -import { useMutation, useQuery } from '@tanstack/react-query'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { Button, DataTable, Text, toast } from 'opub-ui'; import { GraphQL } from '@/lib/api'; import { formatDate } from '@/lib/utils'; import { Loading } from '@/components/loading'; +// prettier-ignore const FetchCollaborativeDetails: any = graphql(` query CollaborativeDetails($filters: CollaborativeFilter) { collaboratives(filters: $filters) { @@ -28,6 +29,7 @@ const FetchCollaborativeDetails: any = graphql(` } `); +// prettier-ignore const AssignCollaborativeDatasets: any = graphql(` mutation assignCollaborativeDatasets($collaborativeId: String!, $datasetIds: [UUID!]!) { updateCollaborativeDatasets(collaborativeId: $collaborativeId, datasetIds: $datasetIds) { @@ -48,6 +50,7 @@ const Assign = () => { id: string; }>(); const router = useRouter(); + const queryClient = useQueryClient(); const COLLAB_ASSIGN_TOAST_ID = 'collaboratives-assign-toast'; const [data, setData] = useState([]); // Ensure `data` is an array @@ -128,13 +131,25 @@ const Assign = () => { { onSuccess: () => { toast('Dataset Assigned Successfully', { id: COLLAB_ASSIGN_TOAST_ID }); - CollaborativeDetails.refetch(); + queryClient.invalidateQueries({ + queryKey: [`Collaborative_Details`, params.id], + }); + queryClient.invalidateQueries({ + queryKey: [ + `fetch_CollaborativeDetails`, + params.entityType, + params.entitySlug, + params.id, + ], + }); router.push( `/dashboard/${params.entityType}/${params.entitySlug}/collaboratives/edit/${params.id}/usecases` ); }, onError: (err: any) => { - toast(`Received ${err} on dataset publish `, { id: COLLAB_ASSIGN_TOAST_ID }); + toast(`Received ${err} on dataset publish `, { + id: COLLAB_ASSIGN_TOAST_ID, + }); }, } ); diff --git a/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/contributors/page.tsx b/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/contributors/page.tsx index f92c2034..be8fd911 100644 --- a/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/contributors/page.tsx +++ b/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/contributors/page.tsx @@ -1,6 +1,6 @@ 'use client'; -import { useMutation, useQuery } from '@tanstack/react-query'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import Image from 'next/image'; import { useParams } from 'next/navigation'; import { Button, Icon, Text, toast } from 'opub-ui'; @@ -26,6 +26,7 @@ import { const Details = () => { const params = useParams<{ entityType: string; entitySlug: string; id: string }>(); + const queryClient = useQueryClient(); const [searchValue, setSearchValue] = useState(''); const [formData, setFormData] = useState({ contributors: [] as { label: string; value: string }[], @@ -114,7 +115,17 @@ const Details = () => { { onSuccess: () => { toast('Contributor added successfully', { id: COLLAB_CONTRIBUTORS_TOAST_ID }); - CollaborativeData.refetch(); + queryClient.invalidateQueries({ + queryKey: [`fetch_collaborative_${params.id}`], + }); + queryClient.invalidateQueries({ + queryKey: [ + `fetch_CollaborativeDetails`, + params.entityType, + params.entitySlug, + params.id, + ], + }); }, onError: (error: any) => { toast(`Error: ${error.message}`, { id: COLLAB_CONTRIBUTORS_TOAST_ID }); @@ -131,7 +142,17 @@ const Details = () => { { onSuccess: () => { toast('Contributor removed successfully', { id: COLLAB_CONTRIBUTORS_TOAST_ID }); - CollaborativeData.refetch(); + queryClient.invalidateQueries({ + queryKey: [`fetch_collaborative_${params.id}`], + }); + queryClient.invalidateQueries({ + queryKey: [ + `fetch_CollaborativeDetails`, + params.entityType, + params.entitySlug, + params.id, + ], + }); }, onError: (error: any) => { toast(`Error: ${error.message}`, { id: COLLAB_CONTRIBUTORS_TOAST_ID }); @@ -147,7 +168,17 @@ const Details = () => { { onSuccess: () => { toast('Supporter added successfully', { id: COLLAB_CONTRIBUTORS_TOAST_ID }); - CollaborativeData.refetch(); + queryClient.invalidateQueries({ + queryKey: [`fetch_collaborative_${params.id}`], + }); + queryClient.invalidateQueries({ + queryKey: [ + `fetch_CollaborativeDetails`, + params.entityType, + params.entitySlug, + params.id, + ], + }); }, onError: (error: any) => { toast(`Error: ${error.message}`, { id: COLLAB_CONTRIBUTORS_TOAST_ID }); @@ -164,7 +195,17 @@ const Details = () => { { onSuccess: () => { toast('Supporter removed successfully', { id: COLLAB_CONTRIBUTORS_TOAST_ID }); - CollaborativeData.refetch(); + queryClient.invalidateQueries({ + queryKey: [`fetch_collaborative_${params.id}`], + }); + queryClient.invalidateQueries({ + queryKey: [ + `fetch_CollaborativeDetails`, + params.entityType, + params.entitySlug, + params.id, + ], + }); }, onError: (error: any) => { toast(`Error: ${error.message}`, { id: COLLAB_CONTRIBUTORS_TOAST_ID }); @@ -180,7 +221,17 @@ const Details = () => { { onSuccess: () => { toast('Partner added successfully', { id: COLLAB_CONTRIBUTORS_TOAST_ID }); - CollaborativeData.refetch(); + queryClient.invalidateQueries({ + queryKey: [`fetch_collaborative_${params.id}`], + }); + queryClient.invalidateQueries({ + queryKey: [ + `fetch_CollaborativeDetails`, + params.entityType, + params.entitySlug, + params.id, + ], + }); }, onError: (error: any) => { toast(`Error: ${error.message}`, { id: COLLAB_CONTRIBUTORS_TOAST_ID }); @@ -197,7 +248,17 @@ const Details = () => { { onSuccess: () => { toast('Partner removed successfully', { id: COLLAB_CONTRIBUTORS_TOAST_ID }); - CollaborativeData.refetch(); + queryClient.invalidateQueries({ + queryKey: [`fetch_collaborative_${params.id}`], + }); + queryClient.invalidateQueries({ + queryKey: [ + `fetch_CollaborativeDetails`, + params.entityType, + params.entitySlug, + params.id, + ], + }); }, onError: (error: any) => { toast(`Error: ${error.message}`, { id: COLLAB_CONTRIBUTORS_TOAST_ID }); diff --git a/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/details/page.tsx b/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/details/page.tsx index 702a794c..d3f9e720 100644 --- a/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/details/page.tsx +++ b/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/details/page.tsx @@ -4,14 +4,15 @@ import React, { useCallback, useEffect, useState } from 'react'; import { useParams, useRouter } from 'next/navigation'; import { graphql } from '@/gql'; import { CollaborativeInputPartial } from '@/gql/generated/graphql'; -import { useMutation, useQuery } from '@tanstack/react-query'; -import { DropZone, Select, TextField, toast } from 'opub-ui'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { DropZone, Select, Text, TextField, toast } from 'opub-ui'; import { GraphQL } from '@/lib/api'; import { RichTextEditor } from '@/components/RichTextEditor'; import { useEditStatus } from '../../context'; import Metadata from '../metadata/page'; +// prettier-ignore const UpdateCollaborativeMutation: any = graphql(` mutation updateCollaborative($data: CollaborativeInputPartial!) { updateCollaborative(data: $data) { @@ -40,6 +41,7 @@ const UpdateCollaborativeMutation: any = graphql(` } `); +//prettier-ignore const FetchCollaborative: any = graphql(` query CollaborativeData($filters: CollaborativeFilter) { collaboratives(filters: $filters) { @@ -73,11 +75,17 @@ const Details = () => { }>(); const router = useRouter(); + const queryClient = useQueryClient(); const COLLAB_DETAILS_TOAST_ID = 'collaboratives-details-toast'; const CollaborativeData: { data: any; isLoading: boolean; refetch: any } = useQuery( - [`fetch_CollaborativeData_details`], + [ + `fetch_CollaborativeData_details`, + params.entityType, + params.entitySlug, + params.id, + ], () => GraphQL( FetchCollaborative, @@ -117,6 +125,19 @@ const Details = () => { const [formData, setFormData] = useState(initialFormData); const [previousFormData, setPreviousFormData] = useState(initialFormData); + const [slugError, setSlugError] = useState(null); + + const validateSlug = (value: string) => { + const v = (value ?? '').trim(); + if (!v) return 'URL subdomain is required.'; + if (v.length > 80) return 'URL subdomain must be 80 characters or less.'; + if (v !== v.toLowerCase()) return 'Use lowercase letters only.'; + // lowercase letters, digits, hyphens; no leading/trailing hyphen; no consecutive hyphens + if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(v)) { + return 'URL subdomain can contain only lowercase letters, numbers, and single hyphens (no spaces).'; + } + return null; + }; useEffect(() => { if (CollaborativesData) { @@ -147,7 +168,9 @@ const Details = () => { ), { onSuccess: (res: any) => { - toast('Collaborative updated successfully', { id: COLLAB_DETAILS_TOAST_ID }); + toast('Collaborative updated successfully', { + id: COLLAB_DETAILS_TOAST_ID, + }); setFormData((prev) => ({ ...prev, ...res.updateCollaborative, @@ -156,6 +179,15 @@ const Details = () => { ...prev, ...res.updateCollaborative, })); + + queryClient.invalidateQueries({ + queryKey: [ + `fetch_CollaborativeData_details`, + params.entityType, + params.entitySlug, + params.id, + ], + }); }, onError: (error: any) => { toast(`Error: ${error.message}`, { id: COLLAB_DETAILS_TOAST_ID }); @@ -195,6 +227,11 @@ const Details = () => { ); const handleSave = (updatedData: any) => { + const slugErr = validateSlug(updatedData?.slug || ''); + if (slugErr) { + return; + } + if (JSON.stringify(updatedData) !== JSON.stringify(previousFormData)) { setPreviousFormData(updatedData); @@ -206,6 +243,7 @@ const Details = () => { startedOn: (updatedData.startedOn as Date) || null, completedOn: (updatedData.completedOn as Date) || null, platformUrl: updatedData.platformUrl || '', + slug: updatedData.slug || '', }, }); } @@ -239,10 +277,10 @@ const Details = () => { helpText={`Character limit: ${formData?.summary?.length || 0}/10000`} /> -
-
+
+
{ onBlur={() => handleSave(formData)} />
+
+
+ { + setSlugError(null); + handleChange('slug', e); + }} + onBlur={() => { + const slugErr = validateSlug(formData.slug || ''); + setSlugError(slugErr); + // if (slugErr) { + // toast(`Error: ${slugErr}`, { id: COLLAB_DETAILS_TOAST_ID }); + // return; + // } + handleSave(formData); + }} + /> + {slugError ? ( + + {slugError} + + ) : null} +
+ + + . + {process.env.NEXT_PUBLIC_PLATFORM_DOMAIN?.includes('localhost') + ? `${process.env.NEXT_PUBLIC_PLATFORM_DOMAIN}:${process.env.NEXT_PUBLIC_PLATFORM_PORT}` + : process.env.NEXT_PUBLIC_PLATFORM_DOMAIN} + +
diff --git a/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/metadata/page.tsx b/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/metadata/page.tsx index 0619ae61..becc12db 100644 --- a/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/metadata/page.tsx +++ b/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/metadata/page.tsx @@ -4,12 +4,13 @@ import { useEffect, useState } from 'react'; import { useParams } from 'next/navigation'; import { graphql } from '@/gql'; import { MetadataModels } from '@/gql/generated/graphql'; -import { useMutation, useQuery } from '@tanstack/react-query'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { Combobox, Spinner, toast } from 'opub-ui'; import { GraphQL } from '@/lib/api'; import { useEditStatus } from '../../context'; +// prettier-ignore const FetchCollaborativeMetadata: any = graphql(` query CollaborativeMetadata($filters: CollaborativeFilter) { collaboratives(filters: $filters) { @@ -47,6 +48,7 @@ const FetchCollaborativeMetadata: any = graphql(` } `); +// prettier-ignore const metadataQueryDoc = graphql(` query CollaborativeMetaDataList($filters: MetadataFilter) { metadata(filters: $filters) { @@ -61,6 +63,7 @@ const metadataQueryDoc = graphql(` } `); +// prettier-ignore const sectorsListQueryDoc: any = graphql(` query SectorList { sectors { @@ -70,6 +73,7 @@ const sectorsListQueryDoc: any = graphql(` } `); +// prettier-ignore const sdgsListQueryDoc: any = graphql(` query SDGList { sdgs { @@ -81,6 +85,7 @@ const sdgsListQueryDoc: any = graphql(` } `); +// prettier-ignore const tagsListQueryDoc: any = graphql(` query TagsList { tags { @@ -90,6 +95,7 @@ const tagsListQueryDoc: any = graphql(` } `); +// prettier-ignore const geographiesListQueryDoc: any = graphql(` query GeographiesList { geographies { @@ -105,6 +111,7 @@ const geographiesListQueryDoc: any = graphql(` } `); +// prettier-ignore const UpdateCollaborativeMetadata: any = graphql(` mutation addUpdateCollaborativeMetadata($updateMetadataInput: UpdateCollaborativeMetadataInput!) { addUpdateCollaborativeMetadata(updateMetadataInput: $updateMetadataInput) { @@ -153,9 +160,15 @@ const Metadata = () => { }>(); const { setStatus } = useEditStatus(); + const queryClient = useQueryClient(); const collaborativeData: { data: any; isLoading: boolean } = useQuery( - [`fetch_CollaborativeData_Metadata`], + [ + `fetch_CollaborativeData_Metadata`, + params.entityType, + params.entitySlug, + params.id, + ], () => GraphQL( FetchCollaborativeMetadata, @@ -217,7 +230,7 @@ const Metadata = () => { defaultVal['sdgs'] = data?.sdgs?.map((sdg: any) => { - const num = sdg.number + const num = sdg.number ? String(sdg.number).padStart(2, '0') : sdg.code.replace('SDG', '').padStart(2, '0'); return { @@ -252,7 +265,9 @@ const Metadata = () => { useEffect(() => { if (collaborativeData.data?.collaboratives?.[0]) { - const updatedData = defaultValuesPrepFn(collaborativeData.data.collaboratives[0]); + const updatedData = defaultValuesPrepFn( + collaborativeData.data.collaboratives[0] + ); setFormData(updatedData); setPreviousFormData(updatedData); } @@ -269,8 +284,9 @@ const Metadata = () => { ) ); - const getSDGsList: { data: any; isLoading: boolean; error: any } = - useQuery([`sdgs_list_query`], () => + const getSDGsList: { data: any; isLoading: boolean; error: any } = useQuery( + [`sdgs_list_query`], + () => GraphQL( sdgsListQueryDoc, { @@ -278,7 +294,7 @@ const Metadata = () => { }, [] ) - ); + ); const getTagsList: { data: any; @@ -312,19 +328,53 @@ const Metadata = () => { // Update mutation const updateCollaborative = useMutation( (data: { updateMetadataInput: any }) => - GraphQL(UpdateCollaborativeMetadata, { - [params.entityType]: params.entitySlug, - }, data), + GraphQL( + UpdateCollaborativeMetadata, + { + [params.entityType]: params.entitySlug, + }, + data + ), { onSuccess: (res: any) => { - toast('Collaborative updated successfully', { id: COLLAB_METADATA_TOAST_ID }); - const updatedData = defaultValuesPrepFn(res.addUpdateCollaborativeMetadata); + toast('Collaborative updated successfully', { + id: COLLAB_METADATA_TOAST_ID, + }); + const updatedData = defaultValuesPrepFn( + res.addUpdateCollaborativeMetadata + ); if (isTagsListUpdated) { getTagsList.refetch(); setIsTagsListUpdated(false); } setFormData(updatedData); setPreviousFormData(updatedData); + + // Keep other edit tabs in sync (Details/Publish) without requiring a full reload. + queryClient.invalidateQueries({ + queryKey: [ + `fetch_CollaborativeData_details`, + params.entityType, + params.entitySlug, + params.id, + ], + }); + queryClient.invalidateQueries({ + queryKey: [ + `fetch_CollaborativeDetails`, + params.entityType, + params.entitySlug, + params.id, + ], + }); + queryClient.invalidateQueries({ + queryKey: [ + `fetch_CollaborativeData_Metadata`, + params.entityType, + params.entitySlug, + params.id, + ], + }); }, onError: (error: any) => { toast(`Error: ${error.message}`, { id: COLLAB_METADATA_TOAST_ID }); @@ -355,13 +405,18 @@ const Metadata = () => { .map((key) => ({ id: key, value: Array.isArray(updatedData[key]) - ? updatedData[key].map((item: any) => item.value || item).join(', ') + ? updatedData[key] + .map((item: any) => item.value || item) + .join(', ') : updatedData[key], })), sectors: updatedData.sectors?.map((item: any) => item.value) || [], sdgs: updatedData.sdgs?.map((item: any) => item.value) || [], tags: updatedData.tags?.map((item: any) => item.label) || [], - geographies: updatedData.geographies?.map((item: any) => parseInt(item.value, 10)) || [], + geographies: + updatedData.geographies?.map((item: any) => + parseInt(item.value, 10) + ) || [], }, }); } @@ -442,7 +497,7 @@ const Metadata = () => { name="sdgs" list={ getSDGsList?.data?.sdgs?.map((item: any) => { - const num = item.number + const num = item.number ? String(item.number).padStart(2, '0') : item.code.replace('SDG', '').padStart(2, '0'); return { @@ -518,9 +573,7 @@ const Metadata = () => {
- {metadataFields?.metadata?.map((item: any) => - renderInputField(item) - )} + {metadataFields?.metadata?.map((item: any) => renderInputField(item))}
diff --git a/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/publish/Details.tsx b/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/publish/Details.tsx index f15f34ce..72ef6b66 100644 --- a/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/publish/Details.tsx +++ b/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/publish/Details.tsx @@ -1,13 +1,14 @@ import { useEffect, useState } from 'react'; import Image from 'next/image'; import Link from 'next/link'; -import { Text } from 'opub-ui'; +import { Tag, Text } from 'opub-ui'; import { getWebsiteTitle } from '@/lib/utils'; import { RichTextRenderer } from '@/components/RichTextRenderer'; const Details = ({ data }: { data: any }) => { const [platformTitle, setPlatformTitle] = useState(null); + const collaborative = data?.collaboratives?.[0]; useEffect(() => { const fetchTitle = async () => { @@ -31,20 +32,48 @@ const Details = ({ data }: { data: any }) => { }, [data?.collaboratives[0]?.platformUrl]); const PrimaryDetails = [ - { label: 'Collaborative Name', value: data?.collaboratives[0]?.title }, - { label: 'Summary', value: data?.collaboratives[0]?.summary }, + { label: 'Collaborative Name', value: collaborative?.title }, + { label: 'Summary', value: collaborative?.summary }, { label: 'Running Status', - value: data?.collaboratives[0]?.runningStatus, + value: collaborative?.runningStatus, }, - { label: 'Started On', value: data?.collaboratives[0]?.startedOn }, + { label: 'Started On', value: collaborative?.startedOn }, { label: 'Completed On', - value: data?.collaboratives[0]?.completedOn, + value: collaborative?.completedOn, }, - { label: 'Sector', value: data?.collaboratives[0]?.sectors[0]?.name }, - { label: 'Tags', value: data?.collaboratives[0]?.tags[0]?.value }, - ...(data?.collaboratives[0]?.metadata?.map((meta: any) => ({ + { + label: 'Sectors', + value: collaborative?.sectors?.length ? ( +
+ {collaborative.sectors.map((s: any, idx: number) => ( + {s?.name} + ))} +
+ ) : null, + }, + { + label: 'SDG Goals', + value: collaborative?.sdgs?.length ? ( +
+ {collaborative.sdgs.map((s: any, idx: number) => ( + {s?.name || s?.code} + ))} +
+ ) : null, + }, + { + label: 'Tags', + value: collaborative?.tags?.length ? ( +
+ {collaborative.tags.map((t: any, idx: number) => ( + {t?.value} + ))} +
+ ) : null, + }, + ...(collaborative?.metadata?.map((meta: any) => ({ label: meta.metadataItem?.label, value: meta.value, })) || []), @@ -53,48 +82,60 @@ const Details = ({ data }: { data: any }) => {
<> - {PrimaryDetails.map( - (item, index) => - item.value && ( -
-
- {item.label}: -
-
- {item.label === 'Summary' ? ( - - ) : ( - {item.value} - )} -
+ {PrimaryDetails.map((item, index) => + item.value ? ( +
+
+ {item.label}: +
+
+ {item.label === 'Summary' ? ( + + ) : ( + <> + {typeof item.value === 'string' || + typeof item.value === 'number' ? ( + {item.value} + ) : ( + item.value + )} + + )}
- ) +
+ ) : null )} -
-
- Platform URL: -
-
- - - {platformTitle?.trim() ? platformTitle : 'Visit Platform'} - - + {data.collaboratives[0].platformUrl && ( +
+
+ External Link: +
+
+ + + {platformTitle?.trim() ? platformTitle : 'Open Link'} + + +
-
+ )} {data?.collaboratives[0]?.logo && (
- Image: + Logo:
{ />
)} + {data?.collaboratives[0]?.coverImage && ( +
+
+ + Cover Image: + +
+ {data?.collaboratives[0]?.title} +
+ )}
diff --git a/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/publish/page.tsx b/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/publish/page.tsx index 395a656a..6e317d3e 100644 --- a/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/publish/page.tsx +++ b/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/publish/page.tsx @@ -21,6 +21,7 @@ import Assign from './Assign'; import Contributors from './Contributors'; import Details from './Details'; +// prettier-ignore const CollaborativeDetails: any = graphql(` query CollabDetails($filters: CollaborativeFilter) { collaboratives(filters: $filters) { @@ -130,7 +131,12 @@ const Publish = () => { }>(); const CollaborativeData: { data: any; isLoading: boolean; refetch: any } = useQuery( - [`fetch_CollaborativeDetails`], + [ + `fetch_CollaborativeDetails`, + params.entityType, + params.entitySlug, + params.id, + ], () => GraphQL( CollaborativeDetails, @@ -144,8 +150,9 @@ const Publish = () => { } ), { - refetchOnMount: true, - refetchOnReconnect: true, + // We navigate between tabs via routing; always refetch to avoid showing stale cached data. + refetchOnMount: 'always', + refetchOnReconnect: 'always', } ); const router = useRouter(); @@ -208,11 +215,11 @@ const Publish = () => { data: CollaborativeData?.data?.collaboratives[0]?.useCases, error: '', }, - { - name: 'Dashboards', - data: CollaborativeData?.data?.collaboratives[0]?.length > 0, - error: '', - }, + // { + // name: 'Dashboards', + // data: CollaborativeData?.data?.collaboratives[0]?.length > 0, + // error: '', + // }, { name: 'Contributors', data: CollaborativeData?.data?.collaboratives[0]?.length > 0, diff --git a/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/usecases/page.tsx b/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/usecases/page.tsx index 6f334a84..395d8eb8 100644 --- a/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/usecases/page.tsx +++ b/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/[id]/usecases/page.tsx @@ -4,13 +4,14 @@ import React, { useEffect, useState } from 'react'; import { useParams, useRouter } from 'next/navigation'; import { fetchData } from '@/fetch'; import { graphql } from '@/gql'; -import { useMutation, useQuery } from '@tanstack/react-query'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { Button, DataTable, Text, toast } from 'opub-ui'; import { GraphQL } from '@/lib/api'; import { formatDate } from '@/lib/utils'; import { Loading } from '@/components/loading'; +// prettier-ignore const FetchCollaborativeDetails: any = graphql(` query CollaborativeUseCaseDetails($filters: CollaborativeFilter) { collaboratives(filters: $filters) { @@ -29,6 +30,7 @@ const FetchCollaborativeDetails: any = graphql(` } `); +// prettier-ignore const AssignCollaborativeUseCases: any = graphql(` mutation assignCollaborativeUseCases($collaborativeId: String!, $useCaseIds: [String!]!) { updateCollaborativeUseCases(collaborativeId: $collaborativeId, useCaseIds: $useCaseIds) { @@ -50,6 +52,7 @@ const UseCases = () => { id: string; }>(); const router = useRouter(); + const queryClient = useQueryClient(); const COLLAB_USECASES_TOAST_ID = 'collaboratives-usecases-toast'; const [data, setData] = useState([]); // Ensure `data` is an array @@ -98,10 +101,7 @@ const UseCases = () => { return { title: item.title, id: String(item.id), - category: - typeof sector === 'string' - ? sector - : sector?.name || 'N/A', + category: typeof sector === 'string' ? sector : sector?.name || 'N/A', modified: formatDate(item.modified) || '', }; }); @@ -113,7 +113,9 @@ const UseCases = () => { (item: any) => String(item.id) ) ); - const defaultSelectedRows = rows.filter((row) => assignedUseCaseIds.has(row.id)); + const defaultSelectedRows = rows.filter((row) => + assignedUseCaseIds.has(row.id) + ); const { mutate } = useMutation( () => @@ -131,14 +133,28 @@ const UseCases = () => { ), { onSuccess: () => { - toast('Use Cases Assigned Successfully', { id: COLLAB_USECASES_TOAST_ID }); - CollaborativeDetails.refetch(); + toast('Use Cases Assigned Successfully', { + id: COLLAB_USECASES_TOAST_ID, + }); + queryClient.invalidateQueries({ + queryKey: [`Collaborative_UseCase_Details`, params.id], + }); + queryClient.invalidateQueries({ + queryKey: [ + `fetch_CollaborativeDetails`, + params.entityType, + params.entitySlug, + params.id, + ], + }); router.push( `/dashboard/${params.entityType}/${params.entitySlug}/collaboratives/edit/${params.id}/contributors` ); }, onError: (err: any) => { - toast(`Received ${err} on use case assignment`, { id: COLLAB_USECASES_TOAST_ID }); + toast(`Received ${err} on use case assignment`, { + id: COLLAB_USECASES_TOAST_ID, + }); }, } ); diff --git a/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/layout.tsx b/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/layout.tsx index 82249336..d2e747b6 100644 --- a/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/layout.tsx +++ b/app/[locale]/dashboard/[entityType]/[entitySlug]/collaboratives/edit/layout.tsx @@ -3,7 +3,7 @@ import { useParams, usePathname, useRouter } from 'next/navigation'; import { graphql } from '@/gql'; import { CollaborativeInputPartial } from '@/gql/generated/graphql'; -import { useMutation, useQuery } from '@tanstack/react-query'; +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { Tab, TabList, Tabs, toast } from 'opub-ui'; import { GraphQL } from '@/lib/api'; @@ -38,6 +38,7 @@ const TabsAndChildren = ({ children }: { children: React.ReactNode }) => { entitySlug: string; id: string; }>(); + const queryClient = useQueryClient(); const layoutList = [ 'details', @@ -51,7 +52,12 @@ const TabsAndChildren = ({ children }: { children: React.ReactNode }) => { return pathName.indexOf(v) >= 0; }); - const CollaborativeData: { data: any; isLoading: boolean; error: any; refetch: any } = useQuery( + const CollaborativeData: { + data: any; + isLoading: boolean; + error: any; + refetch: any; + } = useQuery( [`fetch_CollaborativeData_${params.id}`], () => GraphQL( @@ -73,14 +79,37 @@ const TabsAndChildren = ({ children }: { children: React.ReactNode }) => { const { mutate, isLoading: editMutationLoading } = useMutation( (data: { data: CollaborativeInputPartial }) => - GraphQL(UpdateCollaborativeTitleMutation, { - [params.entityType]: params.entitySlug, - }, data), + GraphQL( + UpdateCollaborativeTitleMutation, + { + [params.entityType]: params.entitySlug, + }, + data + ), { onSuccess: () => { - toast('Collaborative updated successfully', { id: COLLAB_EDIT_TOAST_ID }); - // Optionally, reset form or perform other actions - CollaborativeData.refetch(); + toast('Collaborative updated successfully', { + id: COLLAB_EDIT_TOAST_ID, + }); + queryClient.invalidateQueries({ + queryKey: [`fetch_CollaborativeData_${params.id}`], + }); + queryClient.invalidateQueries({ + queryKey: [ + `fetch_CollaborativeData_details`, + params.entityType, + params.entitySlug, + params.id, + ], + }); + queryClient.invalidateQueries({ + queryKey: [ + `fetch_CollaborativeDetails`, + params.entityType, + params.entitySlug, + params.id, + ], + }); }, onError: (error: any) => { toast(`Error: ${error.message}`, { id: COLLAB_EDIT_TOAST_ID }); @@ -125,17 +154,9 @@ const TabsAndChildren = ({ children }: { children: React.ReactNode }) => { const { status, setStatus } = useEditStatus(); - // Debug logging - console.log('Layout - params:', params); - console.log('Layout - CollaborativeData:', CollaborativeData); - console.log('Layout - isLoading:', CollaborativeData.isLoading); - console.log('Layout - error:', CollaborativeData.error); - console.log('Layout - data:', CollaborativeData.data); - // Safely extract collaborative title - now using direct collaborative object - const collaborativeTitle = CollaborativeData?.data?.collaborative?.title || ''; - - console.log('Layout - collaborativeTitle:', collaborativeTitle); + const collaborativeTitle = + CollaborativeData?.data?.collaborative?.title || ''; // Show loading state while fetching if (CollaborativeData.isLoading) {