diff --git a/src/components/Activity/ActivityStream.tsx b/src/components/Activity/ActivityStream.tsx index e83550295..d4a4bdd5d 100644 --- a/src/components/Activity/ActivityStream.tsx +++ b/src/components/Activity/ActivityStream.tsx @@ -3,7 +3,8 @@ import { getRelativeTimeString } from '../../lib/date'; import type { ResourceType } from '../../lib/resource-progress'; import { EmptyStream } from './EmptyStream'; import { ActivityTopicsModal } from './ActivityTopicsModal.tsx'; -import {Book, BookOpen, ChevronsDown, ChevronsDownUp, ChevronsUp, ChevronsUpDown} from 'lucide-react'; +import { ChevronsDown, ChevronsUp } from 'lucide-react'; +import { ActivityTopicTitles } from './ActivityTopicTitles.tsx'; export const allowedActivityActionType = [ 'in_progress', @@ -21,7 +22,7 @@ export type UserStreamActivity = { resourceSlug?: string; isCustomResource?: boolean; actionType: AllowedActivityActionType; - topicIds?: string[]; + topicTitles?: string[]; createdAt: Date; updatedAt: Date; }; @@ -38,7 +39,9 @@ export function ActivityStream(props: ActivityStreamProps) { useState(null); const sortedActivities = activities - .filter((activity) => activity?.topicIds && activity.topicIds.length > 0) + .filter( + (activity) => activity?.topicTitles && activity.topicTitles.length > 0, + ) .sort((a, b) => { return new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime(); }) @@ -57,8 +60,8 @@ export function ActivityStream(props: ActivityStreamProps) { resourceId={selectedActivity.resourceId} resourceType={selectedActivity.resourceType} isCustomResource={selectedActivity.isCustomResource} - topicIds={selectedActivity.topicIds || []} - topicCount={selectedActivity.topicIds?.length || 0} + topicTitles={selectedActivity.topicTitles || []} + topicCount={selectedActivity.topicTitles?.length || 0} actionType={selectedActivity.actionType} /> )} @@ -73,7 +76,7 @@ export function ActivityStream(props: ActivityStreamProps) { resourceTitle, actionType, updatedAt, - topicIds, + topicTitles, isCustomResource, } = activity; @@ -96,7 +99,7 @@ export function ActivityStream(props: ActivityStreamProps) { ); - const topicCount = topicIds?.length || 0; + const topicCount = topicTitles?.length || 0; const timeAgo = ( @@ -109,24 +112,20 @@ export function ActivityStream(props: ActivityStreamProps) { {actionType === 'in_progress' && ( <> Started{' '} - {' '} + setSelectedActivity(activity)} + />{' '} in {resourceLinkComponent} {timeAgo} )} {actionType === 'done' && ( <> Completed{' '} - {' '} + setSelectedActivity(activity)} + />{' '} in {resourceLinkComponent} {timeAgo} )} @@ -146,16 +145,20 @@ export function ActivityStream(props: ActivityStreamProps) { {activities.length > 10 && ( )} diff --git a/src/components/Activity/ActivityTopicTitles.tsx b/src/components/Activity/ActivityTopicTitles.tsx new file mode 100644 index 000000000..94ea1f1cd --- /dev/null +++ b/src/components/Activity/ActivityTopicTitles.tsx @@ -0,0 +1,41 @@ +type ActivityTopicTitlesProps = { + topicTitles: string[]; + onSelectActivity?: () => void; +}; + +export function ActivityTopicTitles(props: ActivityTopicTitlesProps) { + const { topicTitles, onSelectActivity } = props; + const firstThreeTopics = topicTitles?.slice(0, 3); + const remainingTopics = topicTitles?.slice(3); + + return ( + <> + {firstThreeTopics.map((topicTitle, index) => { + return ( + + <> + {index > 0 && ', '} + {index === firstThreeTopics.length - 1 && + firstThreeTopics.length > 1 && + 'and '} + {topicTitle} + + + ); + })} + + {remainingTopics?.length > 0 && ( + <> +  and  + + + )} + + ); +} diff --git a/src/components/Activity/ActivityTopicsModal.tsx b/src/components/Activity/ActivityTopicsModal.tsx index ff353a616..b23ead5b2 100644 --- a/src/components/Activity/ActivityTopicsModal.tsx +++ b/src/components/Activity/ActivityTopicsModal.tsx @@ -11,7 +11,7 @@ type ActivityTopicDetailsProps = { resourceId: string; resourceType: ResourceType | 'question'; isCustomResource?: boolean; - topicIds: string[]; + topicTitles: string[]; topicCount: number; actionType: AllowedActivityActionType; onClose: () => void; @@ -22,56 +22,12 @@ export function ActivityTopicsModal(props: ActivityTopicDetailsProps) { resourceId, resourceType, isCustomResource, - topicIds = [], + topicTitles = [], topicCount, actionType, onClose, } = props; - const [isLoading, setIsLoading] = useState(true); - const [topicTitles, setTopicTitles] = useState>({}); - const [error, setError] = useState(null); - - const loadTopicTitles = async () => { - setIsLoading(true); - setError(null); - - const { response, error } = await httpPost( - `${import.meta.env.PUBLIC_API_URL}/v1-get-topic-titles`, - { - resourceId, - resourceType, - isCustomResource, - topicIds, - }, - ); - - if (error || !response) { - setError(error?.message || 'Failed to load topic titles'); - setIsLoading(false); - return; - } - - setTopicTitles(response); - setIsLoading(false); - }; - - useEffect(() => { - loadTopicTitles().finally(() => { - setIsLoading(false); - }); - }, []); - - if (isLoading || error) { - return ( - - ); - } - let pageUrl = ''; if (resourceType === 'roadmap') { pageUrl = isCustomResource ? `/r/${resourceId}` : `/${resourceId}`; @@ -85,8 +41,6 @@ export function ActivityTopicsModal(props: ActivityTopicDetailsProps) { { onClose(); - setError(null); - setIsLoading(false); }} >
@@ -108,9 +62,7 @@ export function ActivityTopicsModal(props: ActivityTopicDetailsProps) {
    - {topicIds.map((topicId) => { - const topicTitle = topicTitles[topicId] || 'Unknown Topic'; - + {topicTitles.map((topicTitle) => { const ActivityIcon = actionType === 'done' ? Check @@ -119,7 +71,7 @@ export function ActivityTopicsModal(props: ActivityTopicDetailsProps) { : Check; return ( -
  • +
  • void; @@ -72,8 +73,8 @@ export function TeamActivityItem(props: TeamActivityItemProps) { if (activities.length === 1) { const activity = activities[0]; - const { actionType, topicIds } = activity; - const topicCount = topicIds?.length || 0; + const { actionType, topicTitles } = activity; + const topicCount = topicTitles?.length || 0; return (
  • {username} started{' '} - {' '} + onTopicClick?.(activity)} + />{' '} in {resourceLink(activity)} {timeAgo(activity.updatedAt)} )} @@ -96,12 +95,10 @@ export function TeamActivityItem(props: TeamActivityItemProps) { {actionType === 'done' && ( <> {username} completed{' '} - {' '} + onTopicClick?.(activity)} + />{' '} in {resourceLink(activity)} {timeAgo(activity.updatedAt)} )} @@ -131,32 +128,28 @@ export function TeamActivityItem(props: TeamActivityItemProps) {
      {activities.slice(0, activityLimit).map((activity) => { - const { actionType, topicIds } = activity; - const topicCount = topicIds?.length || 0; + const { actionType, topicTitles } = activity; + const topicCount = topicTitles?.length || 0; return (
    • {actionType === 'in_progress' && ( <> Started{' '} - {' '} + onTopicClick?.(activity)} + />{' '} in {resourceLink(activity)} {timeAgo(activity.updatedAt)} )} {actionType === 'done' && ( <> Completed{' '} - {' '} + onTopicClick?.(activity)} + />{' '} in {resourceLink(activity)} {timeAgo(activity.updatedAt)} )} diff --git a/src/components/TeamActivity/TeamActivityPage.tsx b/src/components/TeamActivity/TeamActivityPage.tsx index 2b4a4a4ce..29df4e3f0 100644 --- a/src/components/TeamActivity/TeamActivityPage.tsx +++ b/src/components/TeamActivity/TeamActivityPage.tsx @@ -18,7 +18,7 @@ export type TeamStreamActivity = { resourceSlug?: string; isCustomResource?: boolean; actionType: AllowedActivityActionType; - topicIds?: string[]; + topicTitles?: string[]; createdAt: Date; updatedAt: Date; }; @@ -102,7 +102,7 @@ export function TeamActivityPage() { return activities?.filter((activity) => { return ( activity.activity.length > 0 && - activity.activity.some((t) => (t?.topicIds?.length || 0) > 0) + activity.activity.some((t) => (t?.topicTitles?.length || 0) > 0) ); }); }, [activities]); @@ -137,7 +137,7 @@ export function TeamActivityPage() { const userActivities = uniqueActivities .filter((activity) => activity.userId === user._id) .flatMap((activity) => activity.activity) - .filter((activity) => (activity?.topicIds?.length || 0) > 0) + .filter((activity) => (activity?.topicTitles?.length || 0) > 0) .sort((a, b) => { return ( new Date(b.updatedAt).getTime() - diff --git a/src/components/TeamActivity/TeamActivityTopicsModal.tsx b/src/components/TeamActivity/TeamActivityTopicsModal.tsx index 76b147f16..d73c1eb17 100644 --- a/src/components/TeamActivity/TeamActivityTopicsModal.tsx +++ b/src/components/TeamActivity/TeamActivityTopicsModal.tsx @@ -16,54 +16,10 @@ export function TeamActivityTopicsModal(props: TeamActivityTopicsModalProps) { resourceId, resourceType, isCustomResource, - topicIds = [], + topicTitles = [], actionType, } = activity; - const [isLoading, setIsLoading] = useState(true); - const [topicTitles, setTopicTitles] = useState>({}); - const [error, setError] = useState(null); - - const loadTopicTitles = async () => { - setIsLoading(true); - setError(null); - - const { response, error } = await httpPost( - `${import.meta.env.PUBLIC_API_URL}/v1-get-topic-titles`, - { - resourceId, - resourceType, - isCustomResource, - topicIds, - }, - ); - - if (error || !response) { - setError(error?.message || 'Failed to load topic titles'); - setIsLoading(false); - return; - } - - setTopicTitles(response); - setIsLoading(false); - }; - - useEffect(() => { - loadTopicTitles().finally(() => { - setIsLoading(false); - }); - }, []); - - if (isLoading || error) { - return ( - - ); - } - let pageUrl = ''; if (resourceType === 'roadmap') { pageUrl = isCustomResource ? `/r/${resourceId}` : `/${resourceId}`; @@ -77,8 +33,6 @@ export function TeamActivityTopicsModal(props: TeamActivityTopicsModalProps) { { onClose(); - setError(null); - setIsLoading(false); }} >
      @@ -100,9 +54,7 @@ export function TeamActivityTopicsModal(props: TeamActivityTopicsModalProps) {
        - {topicIds.map((topicId) => { - const topicTitle = topicTitles[topicId] || 'Unknown Topic'; - + {topicTitles.map((topicTitle) => { const ActivityIcon = actionType === 'done' ? Check @@ -111,7 +63,7 @@ export function TeamActivityTopicsModal(props: TeamActivityTopicsModalProps) { : Check; return ( -
      • +