+
+ {/* Search Bar with stable minimum width */}
+
@@ -304,28 +301,32 @@ export const AssetsPage = () => {
/>
-
- {CATEGORIES.map((cat) => {
- const isGroup = assignedGroups.some(g => g.toLowerCase() === cat.toLowerCase());
- return (
-
- );
- })}
-
+ {/* Toggle Controls: All Assets vs Recommended */}
+ {user?.role === "PARTNER_USER" && recommendedAssets.length > 0 && (
+
+
+
+
+ )}
@@ -383,28 +384,6 @@ export const AssetsPage = () => {
);
- // Find recommended assets based on user's partnerGroup matching any AssetGroup.name (supports comma-separated multiple groups)
- const partnerGroupStrings = user?.partnerGroup && user.role === "PARTNER_USER"
- ? user.partnerGroup.split(',').map(s => s.trim().toLowerCase())
- : [];
-
- // Only recommend assets that the partner actually has permission to access, and deduplicate
- const recommendedAssets = partnerGroupStrings.length > 0
- ? groups
- .filter(g => partnerGroupStrings.includes(g.name.trim().toLowerCase()))
- .flatMap(g => g.assets)
- .filter((recAsset, index, self) =>
- self.findIndex(a => a.id === recAsset.id) === index &&
- assets.some(allAsset => allAsset.id === recAsset.id)
- )
- : [];
-
- const showRecommendations =
- user?.role === "PARTNER_USER" &&
- recommendedAssets.length > 0 &&
- searchQuery === "" &&
- selectedCategory === "ALL";
-
return (
@@ -414,65 +393,29 @@ export const AssetsPage = () => {
) : (
<>
- {showRecommendations && (
-
-
-
-
-
-
+ {selectedCategory === "RECOMMENDED" && (
+
+ {/* Background decorative elements */}
+
+
+
+
+
+
+
- Curated for You
-
- {(user?.partnerGroup ? user.partnerGroup.split(',').map(s => s.trim()) : []).map(g => (
-
- {g}
-
- ))}
+
Curated Catalog
+
+
+ {recommendedAssets.length} {recommendedAssets.length === 1 ? 'Asset' : 'Assets'}
+
-
Recommended for You
-
- Hand-picked digital assets, guides, and templates selected specifically for your partner category.
+
Recommended for You
+
+ These resources have been hand-picked by our team to match your partner profile and accelerate your integration.
-
- {/* Grid of Recommended Assets */}
-
- {recommendedAssets.map((asset) => (
-
- setExpandedAssetId(expandedAssetId === asset.id ? null : asset.id)}
- isRecommended={true}
- />
-
- ))}
-
-
- )}
-
- {showRecommendations && (
-
-
All Resources
)}
diff --git a/Channel-Frontend/src/pages/admin/DirectoryPage.tsx b/Channel-Frontend/src/pages/admin/DirectoryPage.tsx
index 08406b9..f118b33 100644
--- a/Channel-Frontend/src/pages/admin/DirectoryPage.tsx
+++ b/Channel-Frontend/src/pages/admin/DirectoryPage.tsx
@@ -219,7 +219,8 @@ export const DirectoryPage: React.FC = () => {
setSelectedIds: React.Dispatch
>,
searchQuery: string,
setSearchQuery: React.Dispatch>,
- onToggleGroup?: (groupName: string, select: boolean) => void
+ onToggleGroup?: (groupName: string, select: boolean) => void,
+ activeGroupsString: string = ""
) => {
const filtered = allAssets.filter(asset =>
asset.title.toLowerCase().includes(searchQuery.toLowerCase())
@@ -258,31 +259,23 @@ export const DirectoryPage: React.FC = () => {
{assetGroups.length > 0 && (
- Apply Group:
+ Apply Recommendation Group:
{assetGroups.map((g) => {
- const hasAll = g.assets.length > 0 && g.assets.every(a => selectedIds.includes(a.id));
+ const activeGroupNames = activeGroupsString
+ ? activeGroupsString.split(',').map(s => s.trim().toLowerCase())
+ : [];
+ const isGroupActive = activeGroupNames.includes(g.name.trim().toLowerCase());
return (
{inviteResult?.error && (
@@ -1489,10 +1480,10 @@ export const DirectoryPage: React.FC = () => {
className="rounded border-ink-300 text-ink-900 focus:ring-ink-950 w-4 h-4 cursor-pointer"
/>
- {renderAssetSelector(editAssetIds, handleSetEditAssetIds, editAssetSearch, setEditAssetSearch, handleToggleEditGroup)}
+ {renderAssetSelector(editAssetIds, handleSetEditAssetIds, editAssetSearch, setEditAssetSearch, handleToggleEditGroup, editGroup)}
diff --git a/Channel-Frontend/src/services/auth-api.ts b/Channel-Frontend/src/services/auth-api.ts
index f07bb4e..5442c07 100644
--- a/Channel-Frontend/src/services/auth-api.ts
+++ b/Channel-Frontend/src/services/auth-api.ts
@@ -85,6 +85,23 @@ export const updatePartner = async (partnerId: string, params: UpdatePartnerPara
return response.data;
};
+export interface UpdateProfileParams {
+ password?: string;
+ companyName?: string;
+ website?: string;
+ sector?: string;
+ companySize?: string;
+ defaultTheme?: string;
+}
+
+export const updateProfile = async (params: UpdateProfileParams): Promise
=> {
+ const response = await axiosInstance.put(
+ '/auth/profile',
+ params
+ );
+ return response.data;
+};
+
export const resendInvitePartner = async (partnerId: string): Promise<{ success: boolean }> => {
const response = await axiosInstance.post<{ success: boolean }>(
`/auth/partners/${partnerId}/resend-invite`
diff --git a/Channel-Frontend/src/services/blog-api.ts b/Channel-Frontend/src/services/blog-api.ts
deleted file mode 100644
index 3c2640a..0000000
--- a/Channel-Frontend/src/services/blog-api.ts
+++ /dev/null
@@ -1,40 +0,0 @@
-import { axiosInstance } from './axios';
-import type { BlogPost } from '../types';
-
-export const getBlogPosts = async (params?: {
- status?: string;
- tag?: string;
- search?: string;
-}): Promise => {
- const response = await axiosInstance.get('/blog', { params });
- return response.data;
-};
-
-export const getBlogPostById = async (id: string): Promise => {
- const response = await axiosInstance.get(`/blog/${id}`);
- return response.data;
-};
-
-export const createBlogPost = async (payload: {
- title: string;
- content: string;
- tags?: string[];
- thumbnailUrl?: string;
- status: 'draft' | 'published';
- author?: string;
-}): Promise => {
- const response = await axiosInstance.post('/blog/new', payload);
- return response.data;
-};
-
-export const updateBlogPost = async (
- id: string,
- payload: Partial
-): Promise => {
- const response = await axiosInstance.patch(`/blog/${id}`, payload);
- return response.data;
-};
-
-export const deleteBlogPost = async (id: string): Promise => {
- await axiosInstance.delete(`/blog/${id}`);
-};
diff --git a/Channel-Frontend/src/types/auth.ts b/Channel-Frontend/src/types/auth.ts
index 76c8f0e..326f6bd 100644
--- a/Channel-Frontend/src/types/auth.ts
+++ b/Channel-Frontend/src/types/auth.ts
@@ -5,6 +5,13 @@ export interface User {
organizationId: string | null;
onboardingStatus?: string;
partnerGroup?: string | null;
+ companyName?: string | null;
+ website?: string | null;
+ sector?: string | null;
+ companySize?: string | null;
+ defaultTheme?: string | null;
+ organization?: { id: string; name: string } | null;
+ passwordHash?: string;
}
export interface AuthResponse {
diff --git a/Channel-Frontend/src/types/index.ts b/Channel-Frontend/src/types/index.ts
index 952cd37..842a7cb 100644
--- a/Channel-Frontend/src/types/index.ts
+++ b/Channel-Frontend/src/types/index.ts
@@ -32,6 +32,8 @@ export interface User {
date: string;
};
createdAt: string;
+ passwordHash?: string;
+ defaultTheme?: string | null;
}
export interface Category {
@@ -57,17 +59,7 @@ export interface Asset {
downloadsCount: number;
}
-export interface BlogPost {
- id: string;
- title: string;
- content: string;
- author: string;
- publishDate: string;
- thumbnailUrl: string;
- readTime: string;
- tags: string[];
- status: 'draft' | 'published';
-}
+
export interface Announcement {
id: string;