@@ -51,9 +51,6 @@ import {
5151 useActivityNotification ,
5252 useChallengeSummary ,
5353} from "./challenge-realtime-context" ;
54- import { ActivityShareDialog } from "@/components/activity-share-dialog" ;
55- import type { ShareCardData } from "@/lib/share-card-renderer" ;
56- import { getOptimizedMediaUrl } from "@/lib/media-optimizer" ;
5754import { UserChallengeDisplay } from "@/components/user-challenge-display" ;
5855import { Button } from "@/components/ui/button" ;
5956import {
@@ -184,14 +181,12 @@ function mapAlgoItem(item: AlgoFeedItem): ActivityFeedItem {
184181 comments : item . comments ,
185182 likedByUser : item . likedByUser ,
186183 mediaUrls : item . mediaUrls ,
187- cloudinaryPublicIds : item . cloudinaryPublicIds ,
188184 recentLikers : item . recentLikers ?? [ ] ,
189185 } ;
190186}
191187
192188interface ActivityFeedProps {
193189 challengeId : string ;
194- challengeName ?: string ;
195190 currentUserId ?: string ;
196191 initialItems ?: ActivityFeedItem [ ] ;
197192 initialAlgoItems ?: AlgoFeedItem [ ] ;
@@ -208,7 +203,6 @@ interface FeedPageResponse {
208203
209204export function ActivityFeed ( {
210205 challengeId,
211- challengeName,
212206 currentUserId,
213207 initialItems = [ ] ,
214208 initialAlgoItems = [ ] ,
@@ -544,7 +538,7 @@ export function ActivityFeed({
544538 < button
545539 onClick = { ( ) => setFeedFilter ( "for_you" ) }
546540 className = { cn (
547- "relative flex-1 py-4 text-center text-sm font-medium transition-colors hover:bg-zinc-900/50" ,
541+ "relative min-h-[44px] flex-1 py-4 text-center text-sm font-medium transition-colors hover:bg-zinc-900/50 active:bg-zinc-800 /50" ,
548542 feedFilter === "for_you" ? "text-white" : "text-zinc-500" ,
549543 ) }
550544 >
@@ -556,7 +550,7 @@ export function ActivityFeed({
556550 < button
557551 onClick = { ( ) => setFeedFilter ( "all" ) }
558552 className = { cn (
559- "relative flex-1 py-4 text-center text-sm font-medium transition-colors hover:bg-zinc-900/50" ,
553+ "relative min-h-[44px] flex-1 py-4 text-center text-sm font-medium transition-colors hover:bg-zinc-900/50 active:bg-zinc-800 /50" ,
560554 feedFilter === "all" ? "text-white" : "text-zinc-500" ,
561555 ) }
562556 >
@@ -568,7 +562,7 @@ export function ActivityFeed({
568562 < button
569563 onClick = { ( ) => setFeedFilter ( "following" ) }
570564 className = { cn (
571- "relative flex-1 py-4 text-center text-sm font-medium transition-colors hover:bg-zinc-900/50" ,
565+ "relative min-h-[44px] flex-1 py-4 text-center text-sm font-medium transition-colors hover:bg-zinc-900/50 active:bg-zinc-800 /50" ,
572566 feedFilter === "following" ? "text-white" : "text-zinc-500" ,
573567 ) }
574568 >
@@ -637,7 +631,6 @@ export function ActivityFeed({
637631 < ActivityCard
638632 key = { item . activity . _id }
639633 challengeId = { challengeId }
640- challengeName = { challengeName }
641634 showEngagementCounts = { ! lightweightFeedMode }
642635 item = { {
643636 ...item ,
@@ -646,7 +639,6 @@ export function ActivityFeed({
646639 id : item . activity . _id ,
647640 } ,
648641 mediaUrls : item . mediaUrls ?? [ ] ,
649- cloudinaryPublicIds : item . cloudinaryPublicIds ,
650642 } }
651643 mentionOptions = { mentionUsers }
652644 currentUserId = { currentUserId }
@@ -777,7 +769,6 @@ function ActivityStats({ item }: { item: ActivityFeedItem }) {
777769
778770interface ActivityCardProps {
779771 challengeId : string ;
780- challengeName ?: string ;
781772 item : ActivityFeedItem ;
782773 showEngagementCounts : boolean ;
783774 mentionOptions : MentionableUser [ ] ;
@@ -787,7 +778,6 @@ interface ActivityCardProps {
787778
788779export const ActivityCard = memo ( function ActivityCard ( {
789780 challengeId,
790- challengeName,
791781 item,
792782 showEngagementCounts,
793783 mentionOptions,
@@ -797,46 +787,27 @@ export const ActivityCard = memo(function ActivityCard({
797787 const activityId = item . activity . id ?? item . activity . _id ;
798788 const router = useRouter ( ) ;
799789 const [ isLiking , setIsLiking ] = useState ( false ) ;
800- const [ optimisticLike , setOptimisticLike ] = useState < boolean | null > ( null ) ;
801- const [ optimisticLikeDelta , setOptimisticLikeDelta ] = useState ( 0 ) ;
802790 const [ showComments , setShowComments ] = useState ( false ) ;
803791 const [ showFlagDialog , setShowFlagDialog ] = useState ( false ) ;
804792 const [ flagCategory , setFlagCategory ] = useState ( "" ) ;
805793 const [ flagReason , setFlagReason ] = useState ( "" ) ;
806794 const [ flagSubmitting , setFlagSubmitting ] = useState ( false ) ;
807795 const [ flagError , setFlagError ] = useState < string | null > ( null ) ;
808796 const [ flagSuccess , setFlagSuccess ] = useState ( false ) ;
809- const [ showShareDialog , setShowShareDialog ] = useState ( false ) ;
810-
811- const { summary } = useChallengeSummary ( ) ;
812-
813- const displayLiked = optimisticLike ?? item . likedByUser ;
814- const displayLikes = item . likes + optimisticLikeDelta ;
815797
816798 const toggleLike = useMutation ( api . mutations . likes . toggle ) ;
817799 const flagActivity = useMutation ( api . mutations . activities . flagActivity ) ;
818800
819801 const handleToggleLike = useCallback ( async ( ) => {
820- if ( isLiking ) return ;
821802 setIsLiking ( true ) ;
822- const wasLiked = displayLiked ;
823- // Optimistic update
824- setOptimisticLike ( ! wasLiked ) ;
825- setOptimisticLikeDelta ( ( prev ) => prev + ( wasLiked ? - 1 : 1 ) ) ;
826803 try {
827804 await toggleLike ( { activityId : activityId as Id < "activities" > } ) ;
828- // Clear optimistic state — Convex reactive sync will provide the real values
829- setOptimisticLike ( null ) ;
830- setOptimisticLikeDelta ( 0 ) ;
831805 } catch ( error ) {
832806 console . error ( "Failed to toggle like" , error ) ;
833- // Revert optimistic update
834- setOptimisticLike ( wasLiked ) ;
835- setOptimisticLikeDelta ( ( prev ) => prev + ( wasLiked ? 1 : - 1 ) ) ;
836807 } finally {
837808 setIsLiking ( false ) ;
838809 }
839- } , [ activityId , toggleLike , isLiking , displayLiked ] ) ;
810+ } , [ activityId , toggleLike ] ) ;
840811
841812 const activityUrl = `/challenges/${ challengeId } /activities/${ activityId } ` ;
842813
@@ -892,38 +863,22 @@ export const ActivityCard = memo(function ActivityCard({
892863 }
893864 } ;
894865
895- const shareCardData : ShareCardData = useMemo ( ( ) => {
896- // Pick the first non-video image for the share card background
897- let mediaUrl : string | null = null ;
898- if ( item . cloudinaryPublicIds ?. length ) {
899- const imageId = item . cloudinaryPublicIds . find ( ( id ) => ! id . startsWith ( "v/" ) ) ;
900- if ( imageId ) {
901- mediaUrl = getOptimizedMediaUrl ( imageId , "full" ) ;
866+ const handleShare = async ( ) => {
867+ const url = `${ window . location . origin } ${ activityUrl } ` ;
868+
869+ try {
870+ if ( navigator . share ) {
871+ await navigator . share ( {
872+ title : "Check out this activity" ,
873+ url,
874+ } ) ;
875+ } else if ( navigator . clipboard ) {
876+ await navigator . clipboard . writeText ( url ) ;
902877 }
878+ } catch ( error ) {
879+ console . error ( "Share failed" , error ) ;
903880 }
904- if ( ! mediaUrl && item . mediaUrls . length > 0 ) {
905- mediaUrl = item . mediaUrls [ 0 ] ;
906- }
907-
908- return {
909- activityTypeName : item . activityType ?. name ?? "Activity" ,
910- pointsEarned : item . activity . pointsEarned ,
911- loggedDate : new Date ( item . activity . loggedDate ) . toLocaleDateString ( "en-US" , {
912- month : "short" ,
913- day : "numeric" ,
914- year : "numeric" ,
915- } ) ,
916- metrics : item . activity . metrics ,
917- userName : item . user . name ?? item . user . username ,
918- challengeName : challengeName ?? "Challenge" ,
919- mediaUrl,
920- triggeredBonuses : item . activity . triggeredBonuses ,
921- rank : summary . stats . userRank ,
922- totalParticipants : summary . stats . totalParticipants ,
923- totalPoints : summary . stats . userPoints ,
924- currentStreak : summary . stats . userStreak ,
925- } ;
926- } , [ item , challengeName , summary . stats ] ) ;
881+ } ;
927882
928883 const actionBar = (
929884 < div
@@ -935,19 +890,19 @@ export const ActivityCard = memo(function ActivityCard({
935890 onClick = { handleToggleLike }
936891 className = { cn (
937892 "flex items-center gap-1.5 text-sm transition-colors" ,
938- displayLiked
893+ item . likedByUser
939894 ? "text-red-500"
940895 : "hover:text-red-500" ,
941896 ) }
942897 >
943898 < Heart
944899 className = { cn (
945900 "h-[18px] w-[18px]" ,
946- displayLiked && "fill-current" ,
901+ item . likedByUser && "fill-current" ,
947902 ) }
948903 />
949- { showEngagementCounts && displayLikes > 0 && (
950- < span > { displayLikes } </ span >
904+ { showEngagementCounts && item . likes > 0 && (
905+ < span > { item . likes } </ span >
951906 ) }
952907 </ button >
953908 < button
@@ -963,7 +918,7 @@ export const ActivityCard = memo(function ActivityCard({
963918 ) }
964919 </ button >
965920 < button
966- onClick = { ( ) => setShowShareDialog ( true ) }
921+ onClick = { handleShare }
967922 className = "flex items-center gap-1.5 text-sm transition-colors hover:text-foreground"
968923 >
969924 < Share2 className = "h-[18px] w-[18px]" />
@@ -1141,38 +1096,37 @@ export const ActivityCard = memo(function ActivityCard({
11411096 className = "text-sm text-muted-foreground"
11421097 />
11431098 ) : null }
1144- < MediaGallery urls = { item . mediaUrls } optimizedMediaIds = { item . cloudinaryPublicIds } variant = "feed" />
1099+ < MediaGallery urls = { item . mediaUrls } variant = "feed" />
11451100 < ActivityStats item = { item } />
11461101 </ >
11471102 ) ;
11481103
1149- const likesDisplay = showEngagementCounts && displayLikes > 0 ? (
1104+ const likesDisplay = showEngagementCounts && item . likes > 0 ? (
11501105 < div onClick = { ( e ) => e . stopPropagation ( ) } >
11511106 < LikesDisplay
11521107 activityId = { activityId }
11531108 challengeId = { challengeId }
1154- likes = { displayLikes }
1155- likedByUser = { displayLiked }
1109+ likes = { item . likes }
1110+ likedByUser = { item . likedByUser }
11561111 recentLikers = { item . recentLikers ?? [ ] }
11571112 currentUserId = { currentUserId }
11581113 />
11591114 </ div >
11601115 ) : null ;
11611116
11621117 return (
1163- < div className = "cursor-pointer" onClick = { handleCardClick } >
1118+ < article
1119+ className = "cursor-pointer transition-colors active:bg-zinc-900/50"
1120+ style = { { contentVisibility : "auto" , containIntrinsicSize : "auto 200px" } }
1121+ onClick = { handleCardClick }
1122+ >
11641123 < div className = "px-4 pt-3 pb-1" onClick = { ( e ) => e . stopPropagation ( ) } > { headerContent } </ div >
11651124 < div className = "space-y-2 px-4" > { bodyContent } </ div >
11661125 { likesDisplay && < div className = "px-4 pt-2" > { likesDisplay } </ div > }
11671126 < div className = "px-4 py-2" > { actionBar } </ div >
11681127 < div className = "px-4 pb-3" > { commentsSection } </ div >
11691128 < div className = "border-b border-zinc-800" />
1170- < ActivityShareDialog
1171- open = { showShareDialog }
1172- onOpenChange = { setShowShareDialog }
1173- data = { shareCardData }
1174- />
1175- </ div >
1129+ </ article >
11761130 ) ;
11771131} ) ;
11781132
0 commit comments