@ -36,12 +36,12 @@ import {
Description ,
TableChart ,
AutoAwesome ,
AccountTree ,
TrendingUp ,
LocationOn ,
ExpandMore ,
ExpandLess ,
Info ,
Dashboard ,
Fullscreen ,
FullscreenExit ,
} from '@mui/icons-material' ;
import { dataService } from '../services/dataService' ;
import type { Group , GroupPost , GroupLink } from '../types/group' ;
@ -75,7 +75,7 @@ const GroupDetailPage = () => {
const [ group , setGroup ] = useState < Group | null > ( null ) ;
const [ posts , setPosts ] = useState < GroupPost [ ] > ( [ ] ) ;
const [ links , setLinks ] = useState < GroupLink [ ] > ( [ ] ) ;
const [ tabValue , setTabValue ] = useState ( 0 ) ; // Default to Network tab
const [ tabValue , setTabValue ] = useState ( 0 ) ; // Default to combined view
const [ isLoading , setIsLoading ] = useState ( true ) ;
const [ showAIAssistant , setShowAIAssistant ] = useState ( false ) ;
const [ showGroupTour , setShowGroupTour ] = useState ( false ) ;
@ -89,6 +89,7 @@ const GroupDetailPage = () => {
const [ selectedPersonFilter , setSelectedPersonFilter ] = useState < string > ( 'all' ) ;
const [ selectedTopicFilter , setSelectedTopicFilter ] = useState < string > ( 'all' ) ;
const [ expandedPosts , setExpandedPosts ] = useState < Set < string > > ( new Set ( ) ) ;
const [ fullscreenSection , setFullscreenSection ] = useState < 'activity' | 'network' | 'map' | null > ( null ) ;
useEffect ( ( ) = > {
const loadGroupData = async ( ) = > {
@ -374,6 +375,14 @@ const GroupDetailPage = () => {
// TODO: Implement group post creation logic
} ;
const handleFullscreenToggle = ( section : 'activity' | 'network' | 'map' ) = > {
if ( fullscreenSection === section ) {
setFullscreenSection ( null ) ; // Exit fullscreen
} else {
setFullscreenSection ( section ) ; // Enter fullscreen
}
} ;
const formatDate = ( date : Date ) = > {
return new Intl . DateTimeFormat ( 'en-US' , {
year : 'numeric' ,
@ -661,12 +670,9 @@ const GroupDetailPage = () => {
}
] ;
const renderNetworkTab = ( ) = > {
const renderCombinedView = ( ) = > {
const members = getMockMembers ( ) ;
return renderNetworkView ( members ) ;
} ;
const renderActivityTab = ( ) = > {
// Get all unique people and topics for filters
const allPeople = [ 'all' , . . . Array . from ( new Set ( posts . map ( ( p : any ) = > p . authorName ) ) ) ] ;
const allTopics = [ 'all' , . . . Array . from ( new Set ( posts . map ( ( p : any ) = > p . topic ) . filter ( Boolean ) ) ) ] ;
@ -823,110 +829,458 @@ const GroupDetailPage = () => {
) ;
} ;
// Handle fullscreen rendering
if ( fullscreenSection ) {
return (
< Box sx = { {
width : '100%' ,
height : 'calc(100vh - 180px)' ,
px : { xs : 2 , md : 0 }
} } >
{ fullscreenSection === 'activity' && (
< Box sx = { { height : '100%' , display : 'flex' , flexDirection : 'column' } } >
< Box sx = { { display : 'flex' , alignItems : 'center' , justifyContent : 'space-between' , mb : 2 } } >
< Typography variant = "h6" sx = { { fontWeight : 600 , color : 'primary.main' } } >
Activity Feed - Fullscreen
< / Typography >
< IconButton onClick = { ( ) = > handleFullscreenToggle ( 'activity' ) } >
< FullscreenExit / >
< / IconButton >
< / Box >
{ /* Filter Controls */ }
< Box sx = { { mb : 3 , flexShrink : 0 } } >
< Box sx = { { display : 'flex' , gap : 1 , flexWrap : 'wrap' } } >
< FormControl sx = { { minWidth : 140 } } size = "small" >
< InputLabel id = "person-filter-label-fs" > Filter by Person < / InputLabel >
< Select
labelId = "person-filter-label-fs"
value = { selectedPersonFilter }
label = "Filter by Person"
onChange = { ( e ) = > setSelectedPersonFilter ( e . target . value ) }
>
{ allPeople . map ( person = > (
< MenuItem key = { person } value = { person } >
{ person === 'all' ? 'All People' : person }
< / MenuItem >
) ) }
< / Select >
< / FormControl >
< FormControl sx = { { minWidth : 140 } } size = "small" >
< InputLabel id = "topic-filter-label-fs" > Filter by Topic < / InputLabel >
< Select
labelId = "topic-filter-label-fs"
value = { selectedTopicFilter }
label = "Filter by Topic"
onChange = { ( e ) = > setSelectedTopicFilter ( e . target . value ) }
>
{ allTopics . map ( topic = > (
< MenuItem key = { topic } value = { topic } >
{ topic === 'all' ? 'All Topics' : topic }
< / MenuItem >
) ) }
< / Select >
< / FormControl >
< / Box >
< / Box >
< Box sx = { {
flex : 1 ,
overflowY : 'auto' ,
border : 1 ,
borderColor : 'divider' ,
borderRadius : 2 ,
backgroundColor : 'grey.50' ,
p : 2
} } >
{ filteredPosts . length === 0 ? (
< Card sx = { { textAlign : 'center' , py : 6 } } >
< CardContent >
< Typography variant = "h6" color = "text.secondary" gutterBottom >
No posts match your filters
< / Typography >
< Typography variant = "body2" color = "text.secondary" >
Try adjusting your filter selection to see more posts .
< / Typography >
< / CardContent >
< / Card >
) : (
< Box >
{ filteredPosts . map ( renderPost ) }
< / Box >
) }
< / Box >
< / Box >
) }
{ fullscreenSection === 'network' && (
< Box sx = { { height : '100%' , display : 'flex' , flexDirection : 'column' } } >
< Box sx = { { display : 'flex' , alignItems : 'center' , justifyContent : 'space-between' , mb : 2 } } >
< Typography variant = "h6" sx = { { fontWeight : 600 , color : 'primary.main' } } >
Network - Fullscreen
< / Typography >
< IconButton onClick = { ( ) = > handleFullscreenToggle ( 'network' ) } >
< FullscreenExit / >
< / IconButton >
< / Box >
< Box sx = { {
flex : 1 ,
border : 1 ,
borderColor : 'divider' ,
borderRadius : 2 ,
overflow : 'hidden' ,
display : 'flex' ,
alignItems : 'center' ,
justifyContent : 'center'
} } >
{ renderNetworkView ( members , '100%' ) }
< / Box >
< / Box >
) }
{ fullscreenSection === 'map' && (
< Box sx = { { height : '100%' , display : 'flex' , flexDirection : 'column' } } >
< Box sx = { { display : 'flex' , alignItems : 'center' , justifyContent : 'space-between' , mb : 2 } } >
< Typography variant = "h6" sx = { { fontWeight : 600 , color : 'primary.main' } } >
Member Locations - Fullscreen
< / Typography >
< IconButton onClick = { ( ) = > handleFullscreenToggle ( 'map' ) } >
< FullscreenExit / >
< / IconButton >
< / Box >
< Box sx = { {
flex : 1 ,
border : 1 ,
borderColor : 'divider' ,
borderRadius : 2 ,
overflow : 'hidden'
} } >
{ renderMapView ( members , true ) }
< / Box >
< / Box >
) }
< / Box >
) ;
}
return (
< Box >
{ /* Filter Controls */ }
< Box sx = { {
width : '100%' ,
maxWidth : '100%' ,
px : { xs : 2 , md : 0 }
} } >
{ /* Desktop Layout: Activity left, Network top-right, Map bottom-right */ }
< Box sx = { {
mb : 3 ,
mt : { xs : 0 , md : 0 } ,
pt : { xs : '16px' , md : 0 } ,
display : { xs : 'none' , md : 'flex' } ,
gap : 4 ,
width : '100%' ,
overflow : 'visible' , // Change to visible so labels can show
backgroundColor : 'white' ,
zIndex : 10 , // Ensure it's above other elements
position : 'relative' // Required for z-index
maxWidth : '100%' ,
height : 'calc(100vh - 180px)' // Full height minus header and tabs
} } >
{ /* Activity Feed - Left Column (60% width) */ }
< Box sx = { {
width : '60%' ,
display : 'flex' ,
gap : { xs : 1 , md : 2 } ,
flexWrap : 'wrap' ,
alignItems : 'flex-start' , // Change to flex-start so labels have room
width : '100%' ,
position : 'relative' ,
zIndex : 10
flexDirection : 'column' ,
height : '100%' ,
position : 'relative' // Add position relative for the + button
} } >
{ /* Person Filter */ }
< FormControl sx = { {
minWidth : { xs : 100 , md : 200 } ,
flex : { xs : 1 , md : 'none' } ,
maxWidth : { xs : 'calc(50% - 8px)' , md : 'none' } ,
width : { xs : 'calc(50% - 8px)' , md : 'auto' } ,
zIndex : 20 ,
position : 'relative'
} } size = "small" >
< InputLabel id = "person-filter-label" > Filter by Person < / InputLabel >
< Select
labelId = "person-filter-label"
value = { selectedPersonFilter }
label = "Filter by Person"
onChange = { ( e ) = > setSelectedPersonFilter ( e . target . value ) }
>
{ allPeople . map ( person = > (
< MenuItem key = { person } value = { person } >
{ person === 'all' ? 'All People' : person }
< / MenuItem >
) ) }
< / Select >
< / FormControl >
{ /* Topic Filter */ }
< FormControl sx = { {
minWidth : { xs : 100 , md : 200 } ,
flex : { xs : 1 , md : 'none' } ,
maxWidth : { xs : 'calc(50% - 8px)' , md : 'none' } ,
width : { xs : 'calc(50% - 8px)' , md : 'auto' } ,
zIndex : 20 ,
< Typography variant = "h6" sx = { { fontWeight : 600 , mb : 2 , color : 'primary.main' , flexShrink : 0 } } >
Activity Feed
< / Typography >
{ /* Filter Controls */ }
< Box sx = { { mb : 3 , flexShrink : 0 } } >
< Box sx = { { display : 'flex' , gap : 1 , flexWrap : 'wrap' } } >
< FormControl sx = { { minWidth : 140 } } size = "small" >
< InputLabel id = "person-filter-label" > Filter by Person < / InputLabel >
< Select
labelId = "person-filter-label"
value = { selectedPersonFilter }
label = "Filter by Person"
onChange = { ( e ) = > setSelectedPersonFilter ( e . target . value ) }
>
{ allPeople . map ( person = > (
< MenuItem key = { person } value = { person } >
{ person === 'all' ? 'All People' : person }
< / MenuItem >
) ) }
< / Select >
< / FormControl >
< FormControl sx = { { minWidth : 140 } } size = "small" >
< InputLabel id = "topic-filter-label" > Filter by Topic < / InputLabel >
< Select
labelId = "topic-filter-label"
value = { selectedTopicFilter }
label = "Filter by Topic"
onChange = { ( e ) = > setSelectedTopicFilter ( e . target . value ) }
>
{ allTopics . map ( topic = > (
< MenuItem key = { topic } value = { topic } >
{ topic === 'all' ? 'All Topics' : topic }
< / MenuItem >
) ) }
< / Select >
< / FormControl >
< / Box >
< / Box >
{ /* Posts Feed - Takes remaining height */ }
< Box sx = { {
flex : 1 ,
overflowY : 'auto' ,
pr : 1 ,
border : 1 ,
borderColor : 'divider' ,
borderRadius : 2 ,
backgroundColor : 'grey.50' ,
position : 'relative'
} } size = "small" >
< InputLabel id = "topic-filter-label" > Filter by Topic < / InputLabel >
< Select
labelId = "topic-filter-label"
value = { selectedTopicFilter }
label = "Filter by Topic"
onChange = { ( e ) = > setSelectedTopicFilter ( e . target . value ) }
} } >
{ filteredPosts . length === 0 ? (
< Card sx = { { textAlign : 'center' , py : 6 , m : 2 } } >
< CardContent >
< Typography variant = "h6" color = "text.secondary" gutterBottom >
No posts match your filters
< / Typography >
< Typography variant = "body2" color = "text.secondary" >
Try adjusting your filter selection to see more posts .
< / Typography >
< / CardContent >
< / Card >
) : (
< Box sx = { { p : 2 } } >
{ filteredPosts . map ( renderPost ) }
< / Box >
) }
{ /* Fullscreen expand icon - positioned to not conflict with + button */ }
< IconButton
size = "small"
onClick = { ( ) = > handleFullscreenToggle ( 'activity' ) }
sx = { {
position : 'absolute' ,
bottom : 8 ,
left : 8 ,
backgroundColor : 'rgba(255, 255, 255, 0.9)' ,
'&:hover' : {
backgroundColor : 'rgba(255, 255, 255, 1)' ,
} ,
zIndex : 10
} }
>
{ allTopics . map ( topic = > (
< MenuItem key = { topic } value = { topic } >
{ topic === 'all' ? 'All Topics' : topic }
< / MenuItem >
) ) }
< / Select >
< / FormControl >
< Fullscreen fontSize = "small" / >
< / IconButton >
< / Box >
{ /* + Button positioned within Activity Feed */ }
< Box sx = { {
position : 'absolute' ,
bottom : 24 ,
right : 24 ,
zIndex : 1000 ,
'& .MuiFab-root' : {
position : 'relative !important' ,
bottom : 'auto !important' ,
right : 'auto !important'
}
} } >
< PostCreateButton
groupId = { groupId }
onCreatePost = { handleCreatePost }
/ >
< / Box >
< / Box >
< / Box >
{ /* Posts Feed */ }
{ filteredPosts . length === 0 ? (
< Card sx = { { textAlign : 'center' , py : 6 } } >
< CardContent >
< Typography variant = "h6" color = "text.secondary" gutterBottom >
No posts match your filters
{ /* Right Column (40% width) - Network and Map stacked */ }
< Box sx = { {
width : '40%' ,
display : 'flex' ,
flexDirection : 'column' ,
height : '100%' ,
gap : 3
} } >
{ /* Network View - Takes 60% of the height */ }
< Box sx = { { flex : 0.6 , display : 'flex' , flexDirection : 'column' } } >
< Typography variant = "h6" sx = { { fontWeight : 600 , mb : 2 , color : 'primary.main' , flexShrink : 0 } } >
Network
< / Typography >
< Typography variant = "body2" color = "text.secondary" >
Try adjusting your filter selection to see more posts .
< Box sx = { {
flex : 1 ,
border : 1 ,
borderColor : 'divider' ,
borderRadius : 2 ,
overflow : 'hidden' ,
display : 'flex' ,
alignItems : 'center' ,
justifyContent : 'center' ,
position : 'relative'
} } >
{ renderNetworkView ( members , '100%' ) }
{ /* Fullscreen expand icon */ }
< IconButton
size = "small"
onClick = { ( ) = > handleFullscreenToggle ( 'network' ) }
sx = { {
position : 'absolute' ,
bottom : 8 ,
right : 8 ,
backgroundColor : 'rgba(255, 255, 255, 0.9)' ,
'&:hover' : {
backgroundColor : 'rgba(255, 255, 255, 1)' ,
} ,
zIndex : 10
} }
>
< Fullscreen fontSize = "small" / >
< / IconButton >
< / Box >
< / Box >
{ /* Map View - Takes 40% of the height */ }
< Box sx = { { flex : 0.4 , display : 'flex' , flexDirection : 'column' } } >
< Typography variant = "h6" sx = { { fontWeight : 600 , mb : 2 , color : 'primary.main' , flexShrink : 0 } } >
Member Locations
< / Typography >
< / CardContent >
< / Card >
) : (
< Box >
{ filteredPosts . map ( renderPost ) }
< Box sx = { {
flex : 1 ,
border : 1 ,
borderColor : 'divider' ,
borderRadius : 2 ,
overflow : 'hidden' ,
position : 'relative'
} } >
{ renderMapView ( members , true ) }
{ /* Fullscreen expand icon */ }
< IconButton
size = "small"
onClick = { ( ) = > handleFullscreenToggle ( 'map' ) }
sx = { {
position : 'absolute' ,
bottom : 8 ,
right : 8 ,
backgroundColor : 'rgba(255, 255, 255, 0.9)' ,
'&:hover' : {
backgroundColor : 'rgba(255, 255, 255, 1)' ,
} ,
zIndex : 10
} }
>
< Fullscreen fontSize = "small" / >
< / IconButton >
< / Box >
< / Box >
< / Box >
) }
< / Box >
{ /* Mobile Layout: Activity first, then Network, then Map - all naturally scrollable */ }
< Box sx = { {
display : { xs : 'block' , md : 'none' }
} } >
{ /* Activity View - First on mobile */ }
< Typography variant = "h6" sx = { { fontWeight : 600 , mb : 2 , color : 'primary.main' } } >
Activity Feed
< / Typography >
{ /* Filter Controls */ }
< Box sx = { { mb : 3 } } >
< Box sx = { { display : 'flex' , gap : 1 , flexWrap : 'wrap' } } >
< FormControl sx = { { minWidth : 120 , flex : 1 } } size = "small" >
< InputLabel id = "person-filter-label-mobile" > Person < / InputLabel >
< Select
labelId = "person-filter-label-mobile"
value = { selectedPersonFilter }
label = "Person"
onChange = { ( e ) = > setSelectedPersonFilter ( e . target . value ) }
>
{ allPeople . map ( person = > (
< MenuItem key = { person } value = { person } >
{ person === 'all' ? 'All' : person . split ( ' ' ) [ 0 ] }
< / MenuItem >
) ) }
< / Select >
< / FormControl >
< FormControl sx = { { minWidth : 120 , flex : 1 } } size = "small" >
< InputLabel id = "topic-filter-label-mobile" > Topic < / InputLabel >
< Select
labelId = "topic-filter-label-mobile"
value = { selectedTopicFilter }
label = "Topic"
onChange = { ( e ) = > setSelectedTopicFilter ( e . target . value ) }
>
{ allTopics . map ( topic = > (
< MenuItem key = { topic } value = { topic } >
{ topic === 'all' ? 'All' : topic }
< / MenuItem >
) ) }
< / Select >
< / FormControl >
< / Box >
< / Box >
{ /* Posts Feed - Natural height, no scroll container */ }
< Box sx = { { mb : 4 } } >
{ filteredPosts . length === 0 ? (
< Card sx = { { textAlign : 'center' , py : 6 } } >
< CardContent >
< Typography variant = "h6" color = "text.secondary" gutterBottom >
No posts match your filters
< / Typography >
< Typography variant = "body2" color = "text.secondary" >
Try adjusting your filter selection .
< / Typography >
< / CardContent >
< / Card >
) : (
< Box >
{ filteredPosts . map ( renderPost ) }
< / Box >
) }
< / Box >
{ /* Network View - Fixed height on mobile */ }
< Typography variant = "h6" sx = { { fontWeight : 600 , mb : 2 , color : 'primary.main' } } >
Network
< / Typography >
< Box sx = { {
height : '300px' ,
overflow : 'hidden' ,
mb : 4 ,
border : 1 ,
borderColor : 'divider' ,
borderRadius : 2
} } >
{ renderNetworkView ( members , '300px' ) }
< / Box >
{ /* Map View - Fixed height on mobile */ }
< Typography variant = "h6" sx = { { fontWeight : 600 , mb : 2 , color : 'primary.main' } } >
Member Locations
< / Typography >
< Box sx = { {
height : '300px' ,
overflow : 'hidden' ,
mb : 4 ,
border : 1 ,
borderColor : 'divider' ,
borderRadius : 2
} } >
{ renderMapView ( members , true ) }
< / Box >
< / Box >
< / Box >
) ;
} ;
const renderMapTab = ( ) = > {
const members = getMockMembers ( ) ;
return renderMapView ( members ) ;
} ;
const renderNetworkView = ( members : any [ ] ) = > {
const renderNetworkView = ( members : any [ ] , height? : string ) = > {
// Shared position calculation function for perfect alignment
const getNodePosition = ( member : any ) = > {
const centerX = 290 ; // Moved 40px right from previous position (250 + 40 = 290)
const centerY = 375 ; // Moved 25px up from previous position (400 - 25 = 375)
const centerX = 400 ; // Center of 800px viewBox
const centerY = 400 ; // Center of 800px viewBox
const scale = 1.8 ; // Increased scale for better visibility
const x = centerX + member . position . x * scale ;
@ -939,19 +1293,22 @@ const GroupDetailPage = () => {
< Box
sx = { {
position : 'relative' ,
height : 'calc(100vh - 57px)' , // Full viewport height minus tabs header
height : '100%' ,
backgroundColor : 'grey.50' ,
overflow : 'visible ' ,
overflow : 'hidden ' ,
width : '100%' ,
display : 'flex' ,
alignItems : 'center' ,
justifyContent : 'center' ,
m : 0 ,
p : '5px 0 15px 0' // 5px top, 15px bottom padding
p : 1
} }
>
{ /* SVG Network Graph */ }
< svg
width = "100 %"
height = "calc(100vh - 77px)" // Full viewport height minus tabs header and padding
style = { { display : 'block' , paddingBottom : '60px' } }
width = "95 %"
height = "95%"
style = { { display : 'block' } }
viewBox = "0 0 800 800"
preserveAspectRatio = "xMidYMid meet"
>
@ -1129,22 +1486,23 @@ const GroupDetailPage = () => {
} ;
const renderMapView = ( members : any [ ] ) = > {
const renderMapView = ( members : any [ ] , compact? : boolean ) = > {
const visibleMembers = members . filter ( m = > m . location ? . visible ) ;
return (
< Box >
< Box sx = { { height : '100%' , width : '100%' } } >
{ /* World map view */ }
< Box
sx = { {
position : 'relative' ,
height : 'calc(100vh - 200px) ' ,
borderRadius : 2 ,
height : '100% ' ,
width : '100%' ,
overflow : 'hidden' ,
backgroundImage : ` url('/images/world-map.png') ` ,
backgroundSize : 'cover' ,
backgroundPosition : 'center' ,
backgroundRepeat : 'no-repeat'
backgroundRepeat : 'no-repeat' ,
backgroundColor : '#f5f5f5' // Light grey fallback to show container
} }
>
{ /* Member locations */ }
@ -1198,82 +1556,86 @@ const GroupDetailPage = () => {
< Avatar
src = { member . avatar }
sx = { {
width : 40 ,
height : 40 ,
border : 3 ,
width : compact ? 32 : 40 ,
height : compact ? 32 : 40 ,
border : compact ? 2 : 3 ,
borderColor : member.id === 'current-user' ? 'primary.main' : 'success.main' ,
boxShadow : member.id === 'current-user'
? ` 0 0 15px ${ alpha ( theme . palette . primary . main , 0.6 ) } `
: ` 0 0 10px ${ alpha ( theme . palette . success . main , 0.4 ) } ` ,
fontSize : '0.9rem' ,
fontWeight : 600
? ` 0 0 ${ compact ? 10 : 15 } px ${ alpha ( theme . palette . primary . main , 0.6 ) } `
: ` 0 0 ${ compact ? 6 : 10 } px ${ alpha ( theme . palette . success . main , 0.4 ) } ` ,
fontSize : compact ? '0.75rem' : '0.9rem' ,
fontWeight : 600 ,
backgroundSize : member.avatar ? getContactPhotoStyles ( member . name ) . backgroundSize : 'cover' ,
backgroundPosition : member.avatar ? getContactPhotoStyles ( member . name ) . backgroundPosition : 'center' ,
} }
>
{ member . initials }
< / Avatar >
{ /* Name tooltip */ }
{ /* Name tooltip - smaller in compact mode */ }
< Box
sx = { {
position : 'absolute' ,
top : - 40 ,
top : compact ? - 32 : - 40 ,
left : '50%' ,
transform : 'translateX(-50%)' ,
backgroundColor : 'white' ,
px : 1 ,
py : 0.5 ,
px : compact ? 0.5 : 1 ,
py : compact ? 0.25 : 0.5 ,
borderRadius : 1 ,
border : 1 ,
borderColor : 'divider' ,
boxShadow : 2 ,
fontSize : '0.75rem' ,
boxShadow : compact ? 1 : 2 ,
fontSize : compact ? '0.65rem' : '0.75rem' ,
fontWeight : 500 ,
whiteSpace : 'nowrap' ,
pointerEvents : 'none'
} }
>
{ member . name }
{ compact ? member . name . split ( ' ' ) [ 0 ] : member . name }
< / Box >
< / Box >
) ;
} ) }
{ /* Map legend */ }
{ /* Map legend - smaller in compact mode */ }
< Box
sx = { {
position : 'absolute' ,
bottom : 16 ,
left : 16 ,
bottom : compact ? 8 : 16 ,
left : compact ? 8 : 16 ,
backgroundColor : 'white' ,
p : 2 ,
p : compact ? 1 : 2 ,
borderRadius : 2 ,
border : 1 ,
borderColor : 'divider' ,
boxShadow : 2
} }
>
< Typography variant = "subtitle2" gutterBottom sx = { { fontWeight : 600 } } >
< Typography variant = { compact ? "caption" : "subtitle2"} gutterBottom sx = { { fontWeight : 600 } } >
Location Sharing
< / Typography >
< Box sx = { { display : 'flex' , flexDirection : 'column' , gap : 1 } } >
< Box sx = { { display : 'flex' , flexDirection : 'column' , gap : compact ? 0.5 : 1 } } >
< Box sx = { { display : 'flex' , alignItems : 'center' , gap : 1 } } >
< Box sx = { { width : 12 , height : 12 , backgroundColor : 'success.main' , borderRadius : '50%' } } / >
< Typography variant = "caption" > { visibleMembers . length } members visible < / Typography >
< Box sx = { { width : compact ? 8 : 12 , height : compact ? 8 : 12 , backgroundColor : 'success.main' , borderRadius : '50%' } } / >
< Typography variant = "caption" > { visibleMembers . length } visible < / Typography >
< / Box >
< Box sx = { { display : 'flex' , alignItems : 'center' , gap : 1 } } >
< Box sx = { { width : 12 , height : 12 , backgroundColor : 'grey.400' , borderRadius : '50%' } } / >
< Typography variant = "caption" > { members . length - visibleMembers . length } members private < / Typography >
< Box sx = { { width : compact ? 8 : 12 , height : compact ? 8 : 12 , backgroundColor : 'grey.400' , borderRadius : '50%' } } / >
< Typography variant = "caption" > { members . length - visibleMembers . length } private < / Typography >
< / Box >
< / Box >
< / Box >
< / Box >
{ /* Privacy notice */ }
< Box sx = { { mt : 2 , p : 2 , backgroundColor : alpha ( theme . palette . info . main , 0.1 ) , borderRadius : 2 } } >
< Typography variant = "body2" color = "info.main" sx = { { fontWeight : 500 } } >
📍 Location Privacy : Only members who have enabled location sharing are visible on the map .
< / Typography >
< / Box >
{ /* Privacy notice - hide in compact mode */ }
{ ! compact && (
< Box sx = { { mt : 2 , p : 2 , backgroundColor : alpha ( theme . palette . info . main , 0.1 ) , borderRadius : 2 } } >
< Typography variant = "body2" color = "info.main" sx = { { fontWeight : 500 } } >
📍 Location Privacy : Only members who have enabled location sharing are visible on the map .
< / Typography >
< / Box >
) }
< / Box >
) ;
} ;
@ -1420,21 +1782,18 @@ const GroupDetailPage = () => {
return (
< Box sx = { {
height : '100%' , // Normal height
width : '100%' ,
maxWidth : { xs : '100vw' , md : '100%' } ,
overflow : tabValue === 0 ? 'hidden' : 'hidden' , // Prevent scrolling for network tab
boxSizing : 'border-box' ,
pt : { xs : 1.5 , md : 2 } , // Reduced top padding
pb : 0 , // No bottom padding
mx : { xs : 0 , md : 'auto' }
mx : { xs : 0 , md : 'auto' } ,
minHeight : '100vh' // Ensure minimum height but allow scrolling
} } >
{ /* Header - Hidden for network tab to maximize space */ }
{ /* Header */ }
< Box sx = { {
mb : { xs : 1.5 , md : 2 } , // Reduced bottom margin to match top
pt : { xs : 1.5 , md : 2 } ,
pb : { xs : 1 , md : 1.5 } ,
width : '100%' ,
overflow : 'hidden' ,
display : 'block' // Always show header
overflow : 'hidden'
} } >
{ /* Top row with back button, avatar, and title/description */ }
< Box sx = { {
@ -1525,13 +1884,10 @@ const GroupDetailPage = () => {
{ /* Navigation Tabs */ }
< Box sx = { {
width : tabValue === 0 ? '100vw' : { xs : 'calc(100% + 20px)' , md : '100%' } ,
maxWidth : tabValue === 0 ? '100vw' : { xs : 'calc(100vw - 0px)' , md : '100%' } ,
width : '100%' ,
overflow : 'hidden' ,
mx : tabValue === 0 ? 0 : { xs : '-10px' , md : 0 } , // Full width for network tab
boxSizing : 'border-box' ,
backgroundColor : 'white' , // Force white background
height : 'auto' // Normal height
backgroundColor : 'white'
} } >
< Tabs
value = { tabValue }
@ -1562,9 +1918,7 @@ const GroupDetailPage = () => {
}
} }
>
< Tab icon = { < AccountTree / > } label = "Network" / >
< Tab icon = { < TrendingUp / > } label = "Activity" / >
< Tab icon = { < LocationOn / > } label = "Map" / >
< Tab icon = { < Dashboard / > } label = "Overview" / >
< Tab icon = { < Chat / > } label = "Chat" / >
< Tab icon = { < Folder / > } label = "Files" / >
< Tab icon = { < Link / > } label = "Links" / >
@ -1572,34 +1926,21 @@ const GroupDetailPage = () => {
{ /* Tab Content */ }
< Box sx = { {
pt : 3 , // Add top padding for space between tabs and content
px : 0 , // No horizontal padding
pb : 0 , // No bottom padding
pt : 3 ,
px : 0 ,
pb : 4 ,
width : '100%' ,
maxWidth : '100%' ,
overflow : 'visible' , // Let page scroll instead
boxSizing : 'border-box' ,
height : tabValue === 0 ? 'calc(100vh - 200px)' : 'auto' , // Use viewport height for network tab only
backgroundColor : 'white' , // Force white background
minHeight : tabValue === 1 ? 'calc(100vh - 200px)' : 'auto' // Normal min height
backgroundColor : 'white'
} } >
{ tabValue === 0 && renderNetworkTab ( ) }
{ tabValue === 1 && renderActivityTab ( ) }
{ tabValue === 2 && renderMapTab ( ) }
{ tabValue === 3 && renderChatTab ( ) }
{ tabValue === 4 && renderFilesTab ( ) }
{ tabValue === 5 && renderLinksTab ( ) }
{ tabValue === 0 && renderCombinedView ( ) }
{ tabValue === 1 && renderChatTab ( ) }
{ tabValue === 2 && renderFilesTab ( ) }
{ tabValue === 3 && renderLinksTab ( ) }
< / Box >
< / Box >
{ /* Show Post Create Button only on Activity tab */ }
{ tabValue === 1 && (
< PostCreateButton
groupId = { groupId }
onCreatePost = { handleCreatePost }
/ >
) }
{ /* Group Tour */ }
< GroupTour