diff --git a/.env.local.example b/.env.local.example
index fbf5658f..7381629e 100644
--- a/.env.local.example
+++ b/.env.local.example
@@ -25,7 +25,18 @@ SENTRY_DSN_URL=https://sentrydsnurl
NEXT_PUBLIC_SENTRY_DSN_URL=https://sentrydsnurl
SENTRY_ORG_NAME='orgname'
SENTRY_PROJECT_NAME='projectname'
-NEXT_PUBLIC_PLATFORM_URL = 'https://platformurl'
+NEXT_PUBLIC_PLATFORM_URL=https://platformurl
+
+# Domain used for slug subdomains (recommended to set explicitly)
+# Local : localhost
+# Dev : dev.civicdataspace.in
+# Prod : civicdataspace.in
+NEXT_PUBLIC_PLATFORM_DOMAIN=platformdomain
+
+# Optional: set protocol/port explicitly for slug subdomain URLs
+NEXT_PUBLIC_PLATFORM_PROTOCOL=https
+NEXT_PUBLIC_PLATFORM_PORT=3000
+
# Google Analytics
NEXT_PUBLIC_GA_ID='G-XXXXXXXXXX'
diff --git a/.github/workflows/deploy-Dataspace.yml b/.github/workflows/deploy-Dataspace.yml
index 2575604e..65985553 100644
--- a/.github/workflows/deploy-Dataspace.yml
+++ b/.github/workflows/deploy-Dataspace.yml
@@ -26,6 +26,8 @@ jobs:
NEXT_PUBLIC_ENABLE_ACCESSMODEL: ${{ vars.NEXT_PUBLIC_ENABLE_ACCESSMODEL }}
NEXT_PUBLIC_ANALYTICS_URL: ${{ vars.NEXT_PUBLIC_ANALYTICS_URL }}
NEXT_PUBLIC_PLATFORM_URL: ${{ vars.NEXT_PUBLIC_PLATFORM_URL }}
+ NEXT_PUBLIC_PLATFORM_PROTOCOL: ${{ vars.NEXT_PUBLIC_PLATFORM_PROTOCOL }}
+ NEXT_PUBLIC_PLATFORM_DOMAIN: ${{ vars.NEXT_PUBLIC_PLATFORM_DOMAIN }}
steps:
- name: Checkout code
diff --git a/app/[locale]/(user)/collaboratives/CollaborativesListingClient.tsx b/app/[locale]/(user)/collaboratives/CollaborativesListingClient.tsx
index 3e5c4904..f7cefb3a 100644
--- a/app/[locale]/(user)/collaboratives/CollaborativesListingClient.tsx
+++ b/app/[locale]/(user)/collaboratives/CollaborativesListingClient.tsx
@@ -8,6 +8,7 @@ import { useQuery } from '@tanstack/react-query';
import { Button, Card, Icon, SearchInput, Select, Text } from 'opub-ui';
import { GraphQLPublic } from '@/lib/api';
+import { getCollaborativeDetailUrl } from '@/lib/collaborativesRouting';
import { cn, formatDate, generateJsonLd } from '@/lib/utils';
import BreadCrumbs from '@/components/BreadCrumbs';
import { Icons } from '@/components/icons';
@@ -97,7 +98,7 @@ const CollaborativesListingClient = () => {
try {
// @ts-expect-error - Query has no variables
const result = await GraphQLPublic(PublishedCollaboratives as any, {});
- console.log('Collaboratives result:', result);
+ // console.log('Collaboratives result:', result);
return result as { publishedCollaboratives: TypeCollaborative[] };
} catch (err) {
console.error('Error fetching collaboratives:', err);
@@ -336,7 +337,7 @@ const CollaborativesListingClient = () => {
stroke: 1.2,
},
]}
- href={`/collaboratives/${collaborative.slug}`}
+ href={getCollaborativeDetailUrl(collaborative.slug)}
leftFooterChips={[
{
icon: collaborative.sectors?.[0]?.name
diff --git a/app/[locale]/(user)/collaboratives/[collaborativeSlug]/CollaborativeDetailsClient.tsx b/app/[locale]/(user)/collaboratives/[collaborativeSlug]/CollaborativeDetailsClient.tsx
index 5112b762..6e1665de 100644
--- a/app/[locale]/(user)/collaboratives/[collaborativeSlug]/CollaborativeDetailsClient.tsx
+++ b/app/[locale]/(user)/collaboratives/[collaborativeSlug]/CollaborativeDetailsClient.tsx
@@ -1,6 +1,6 @@
'use client';
-import { useEffect } from 'react';
+import { useEffect, useState } from 'react';
import Image from 'next/image';
import Link from 'next/link';
import { useParams } from 'next/navigation';
@@ -15,6 +15,7 @@ import { useQuery } from '@tanstack/react-query';
import { Card, Text } from 'opub-ui';
import { GraphQLPublic } from '@/lib/api';
+import { isCollaborativeSubdomainHost as isCollaborativeSubdomainHostname } from '@/lib/collaborativesRouting';
import { formatDate, generateJsonLd } from '@/lib/utils';
import BreadCrumbs from '@/components/BreadCrumbs';
import { Icons } from '@/components/icons';
@@ -217,9 +218,41 @@ const CollaborativeDetails = graphql(`
}
`);
+const getPlatformEntityUrl = (
+ entityPath: 'usecases' | 'datasets',
+ entityId: string | number,
+ locale?: string
+) => {
+ //Removes trailing slash
+ const platformBaseUrl = (process.env.NEXT_PUBLIC_PLATFORM_URL || '').replace(
+ /\/$/,
+ ''
+ );
+ const localeSegment = locale ? `/${locale}` : '';
+
+ if (!platformBaseUrl) {
+ return `/${entityPath}/${entityId}`;
+ }
+
+ return `${platformBaseUrl}${localeSegment}/${entityPath}/${entityId}`;
+};
+
const CollaborativeDetailClient = () => {
const params = useParams();
const { trackCollaborative } = useAnalytics();
+ const locale =
+ typeof (params as any)?.locale === 'string'
+ ? (params as any).locale
+ : undefined;
+ const [isCollaborativeSubdomainHost, setIsCollaborativeSubdomainHost] =
+ useState(false);
+
+ useEffect(() => {
+ if (typeof window === 'undefined') return;
+ setIsCollaborativeSubdomainHost(
+ isCollaborativeSubdomainHostname(window.location.hostname)
+ );
+ }, []);
const {
data: CollaborativeDetailsData,
@@ -250,12 +283,6 @@ const CollaborativeDetailClient = () => {
}
);
- console.log('Collaborative details query state:', {
- isLoading,
- error,
- data: CollaborativeDetailsData,
- });
-
// Track collaborative view when data is loaded
useEffect(() => {
if (CollaborativeDetailsData?.collaborativeBySlug) {
@@ -328,20 +355,23 @@ const CollaborativeDetailClient = () => {
) : (
<>
-