diff --git a/packages/lib-user/src/components/GroupStats/GroupStats.js b/packages/lib-user/src/components/GroupStats/GroupStats.js
index 828a3060b7..2e6d711860 100644
--- a/packages/lib-user/src/components/GroupStats/GroupStats.js
+++ b/packages/lib-user/src/components/GroupStats/GroupStats.js
@@ -1,5 +1,13 @@
+import { Grid } from 'grommet'
import { arrayOf, func, number, shape, string } from 'prop-types'
+import {
+ ContentBox,
+ Layout,
+ MainContent,
+ ProjectCard
+} from '@components/shared'
+
import DeleteGroup from './DeleteGroup'
import EditGroup from './EditGroup'
@@ -10,6 +18,7 @@ const DEFAULT_GROUP = {
const DEFAULT_HANDLER = () => true
const DEFAULT_STATS = {
active_users: 0,
+ data: [],
project_contributions: [
{
count: 0,
@@ -18,54 +27,140 @@ const DEFAULT_STATS = {
}
],
time_spent: 0,
+ top_contributors: [
+ {
+ count: 0,
+ session_time: 0,
+ user_id: 0
+ }
+ ],
total_count: 0
}
function GroupStats({
+ allProjectsStats = DEFAULT_STATS,
group = DEFAULT_GROUP,
- groupStats = DEFAULT_STATS,
+ handleDateRangeSelect = DEFAULT_HANDLER,
handleGroupDelete = DEFAULT_HANDLER,
- handleGroupUpdate = DEFAULT_HANDLER
+ handleGroupUpdate = DEFAULT_HANDLER,
+ handleProjectSelect = DEFAULT_HANDLER,
+ projectStats = DEFAULT_STATS,
+ projects = [],
+ selectedDateRange = 'Last7Days',
+ selectedProject = 'AllProjects'
}) {
+ // set stats based on selected project or all projects
+ const stats = selectedProject === 'AllProjects' ? allProjectsStats : projectStats
+
+ // set top projects based on selected date range and all project stats
+ let topProjects = []
+ const topProjectContributions = allProjectsStats.project_contributions
+ .sort((a, b) => b.count - a.count)
+
+ topProjects = topProjectContributions
+ .map(projectContribution => {
+ const projectData = projects?.find(project => project.id === projectContribution.project_id.toString())
+ return projectData
+ })
+ .filter(project => project)
+ .slice(0, 6)
+
return (
-
-
Hi group with ID {group?.id}! 🙌
-
Your group display_name is {group?.display_name}.
-
Members: {group?.links?.users?.toString()}
-
Here are your group stats:
-
{JSON.stringify(groupStats, null, 2)}
-
+
+
+
+
+ Top contributors go here.
+
+
+
+ {topProjects.map(topProject => {
+ return (
+
+ )
+ })}
+
+
+
-
-
-
+
)
}
+const statsShape = shape({
+ active_users: number,
+ data: arrayOf(shape({
+ count: number,
+ period: string,
+ session_time: number
+ })),
+ project_contributions: arrayOf(shape({
+ count: number,
+ project_id: number,
+ session_time: number
+ })),
+ time_spent: number,
+ top_contributors: arrayOf(shape({
+ count: number,
+ session_time: number,
+ user_id: number
+ })),
+ total_count: number
+})
+
GroupStats.propTypes = {
+ allProjectsStats: statsShape,
group: shape({
display_name: string,
id: string
}),
- groupStats: shape({
- active_users: number,
- project_contributions: arrayOf(shape({
- count: number,
- project_id: number,
- session_time: number
- })),
- time_spent: number,
- total_count: number
- }),
+ handleDateRangeSelect: func,
handleGroupDelete: func,
- handleGroupUpdate: func
+ handleGroupUpdate: func,
+ handleProjectSelect: func,
+ projectStats: statsShape,
+ projects: arrayOf(shape({
+ id: string,
+ display_name: string
+ })),
+ selectedDateRange: string,
+ selectedProject: string
}
export default GroupStats
diff --git a/packages/lib-user/src/components/GroupStats/GroupStatsContainer.js b/packages/lib-user/src/components/GroupStats/GroupStatsContainer.js
index 768a2511c9..352eb4bb47 100644
--- a/packages/lib-user/src/components/GroupStats/GroupStatsContainer.js
+++ b/packages/lib-user/src/components/GroupStats/GroupStatsContainer.js
@@ -1,11 +1,11 @@
'use client'
-// This component is a work in progress. It is not intended to be imported as-is, but is currently being used for initial GroupStats local development.
-
import { object, string } from 'prop-types'
+import { useState } from 'react'
import {
usePanoptesAuthUser,
+ usePanoptesProjects,
usePanoptesUserGroup,
useStats
} from '@hooks'
@@ -13,6 +13,7 @@ import {
import {
deletePanoptesUserGroup,
getBearerToken,
+ getDateInterval,
updatePanoptesUserGroup
} from '@utils'
@@ -24,10 +25,15 @@ function GroupStatsContainer({
authClient,
groupId
}) {
+ const [selectedProject, setSelectedProject] = useState('AllProjects')
+ const [selectedDateRange, setSelectedDateRange] = useState('Last7Days')
+
+ // fetch authenticated user
const {
data: authUser
} = usePanoptesAuthUser(authClient)
+ // fetch user_group
const {
data,
error: groupError,
@@ -37,17 +43,57 @@ function GroupStatsContainer({
authUserId: authUser?.id,
groupId
})
+ const group = data?.body?.user_groups?.[0]
+
+ // fetch all projects stats, used by projects select and top projects regardless of selected project
+ const allProjectsStatsQuery = getDateInterval(selectedDateRange)
+ allProjectsStatsQuery.top_contributors = 10
const {
- data: groupStats,
- error: groupStatsError,
- isLoading: groupStatsLoading
+ data: allProjectsStats,
+ error: statsError,
+ isLoading: statsLoading
} = useStats({
authClient,
authUserId: authUser?.id,
endpoint: STATS_ENDPOINT,
- sourceId: groupId
+ sourceId: group?.id,
+ query: allProjectsStatsQuery
})
+
+ // fetch individual project stats
+ const projectStatsQuery = getDateInterval(selectedDateRange)
+ projectStatsQuery.project_id = parseInt(selectedProject)
+ projectStatsQuery.top_contributors = 10
+
+ const {
+ data: projectStats,
+ error: projectStatsError,
+ isLoading: projectStatsLoading
+ } = useStats({
+ authClient,
+ authUserId: authUser?.id,
+ endpoint: STATS_ENDPOINT,
+ sourceId: group?.id,
+ query: projectStatsQuery
+ })
+
+ // fetch projects
+ const projectIDs = allProjectsStats?.project_contributions?.map(project => project.project_id)
+
+ const {
+ data: projects,
+ error: projectsError,
+ isLoading: projectsLoading
+ } = usePanoptesProjects(projectIDs)
+
+ function handleProjectSelect (project) {
+ setSelectedProject(project.value)
+ }
+
+ function handleDateRangeSelect (dateRange) {
+ setSelectedDateRange(dateRange.value)
+ }
async function getRequestHeaders() {
const authorization = await getBearerToken(authClient)
@@ -80,14 +126,18 @@ function GroupStatsContainer({
}
}
- const group = data?.body?.user_groups?.[0]
-
return (
)
}
diff --git a/packages/lib-user/src/components/UserStats/UserStats.js b/packages/lib-user/src/components/UserStats/UserStats.js
index fa9c6e6838..b034f7df50 100644
--- a/packages/lib-user/src/components/UserStats/UserStats.js
+++ b/packages/lib-user/src/components/UserStats/UserStats.js
@@ -1,10 +1,10 @@
import { arrayOf, func, number, shape, string } from 'prop-types'
import {
- Layout
+ Layout,
+ MainContent,
} from '@components/shared'
-import MainContent from './components/MainContent'
import TopProjects from './components/TopProjects'
const DEFAULT_HANDLER = () => true
diff --git a/packages/lib-user/src/components/UserStats/components/MainContent/index.js b/packages/lib-user/src/components/UserStats/components/MainContent/index.js
deleted file mode 100644
index e37d264f99..0000000000
--- a/packages/lib-user/src/components/UserStats/components/MainContent/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from './MainContent'
diff --git a/packages/lib-user/src/components/shared/Layout/Layout.js b/packages/lib-user/src/components/shared/Layout/Layout.js
index 2631d0aa5e..de874466b6 100644
--- a/packages/lib-user/src/components/shared/Layout/Layout.js
+++ b/packages/lib-user/src/components/shared/Layout/Layout.js
@@ -128,7 +128,7 @@ function Layout ({ children }) {
dark: 'dark-3',
light: 'neutral-6'
}}
- gap='32px'
+ gap='30px'
>
{children}
diff --git a/packages/lib-user/src/components/UserStats/components/MainContent/MainContent.js b/packages/lib-user/src/components/shared/MainContent/MainContent.js
similarity index 100%
rename from packages/lib-user/src/components/UserStats/components/MainContent/MainContent.js
rename to packages/lib-user/src/components/shared/MainContent/MainContent.js
diff --git a/packages/lib-user/src/components/UserStats/components/MainContent/MainContent.spec.js b/packages/lib-user/src/components/shared/MainContent/MainContent.spec.js
similarity index 93%
rename from packages/lib-user/src/components/UserStats/components/MainContent/MainContent.spec.js
rename to packages/lib-user/src/components/shared/MainContent/MainContent.spec.js
index 1dcab43758..4bba0dd08f 100644
--- a/packages/lib-user/src/components/UserStats/components/MainContent/MainContent.spec.js
+++ b/packages/lib-user/src/components/shared/MainContent/MainContent.spec.js
@@ -1,8 +1,8 @@
import { composeStory } from '@storybook/react'
import { render, screen } from '@testing-library/react'
-import { USER } from '../../../../../test/mocks/panoptes'
-import { STATS } from '../../../../../test/mocks/stats.mock.js'
+import { USER } from '../../../../test/mocks/panoptes'
+import { STATS } from '../../../../test/mocks/stats.mock.js'
import Meta, { Default } from './MainContent.stories.js'
diff --git a/packages/lib-user/src/components/UserStats/components/MainContent/MainContent.stories.js b/packages/lib-user/src/components/shared/MainContent/MainContent.stories.js
similarity index 78%
rename from packages/lib-user/src/components/UserStats/components/MainContent/MainContent.stories.js
rename to packages/lib-user/src/components/shared/MainContent/MainContent.stories.js
index e67d399f2b..ae71d9c2dd 100644
--- a/packages/lib-user/src/components/UserStats/components/MainContent/MainContent.stories.js
+++ b/packages/lib-user/src/components/shared/MainContent/MainContent.stories.js
@@ -1,12 +1,12 @@
import { Box } from 'grommet'
-import { PROJECTS, USER } from '../../../../../test/mocks/panoptes'
-import { STATS } from '../../../../../test/mocks/stats.mock.js'
+import { PROJECTS, USER } from '../../../../test/mocks/panoptes'
+import { STATS } from '../../../../test/mocks/stats.mock'
import MainContent from './MainContent'
export default {
- title: 'Components/UserStats/MainContent',
+ title: 'Components/shared/MainContent',
component: MainContent,
decorators: [ComponentDecorator]
}
diff --git a/packages/lib-user/src/components/shared/MainContent/index.js b/packages/lib-user/src/components/shared/MainContent/index.js
new file mode 100644
index 0000000000..cc6f70e46b
--- /dev/null
+++ b/packages/lib-user/src/components/shared/MainContent/index.js
@@ -0,0 +1 @@
+export { default } from './MainContent.js'
diff --git a/packages/lib-user/src/components/shared/index.js b/packages/lib-user/src/components/shared/index.js
index dd2aa5b858..f1b39a7693 100644
--- a/packages/lib-user/src/components/shared/index.js
+++ b/packages/lib-user/src/components/shared/index.js
@@ -1,6 +1,7 @@
export { default as BarChart } from './BarChart'
export { default as ContentBox } from './ContentBox'
export { default as Layout } from './Layout'
+export { default as MainContent } from './MainContent'
export { default as ProfileHeader } from './ProfileHeader'
export { default as ProjectCard } from './ProjectCard'
export { default as Select } from './Select'
diff --git a/packages/lib-user/src/utils/getDateInterval.js b/packages/lib-user/src/utils/getDateInterval.js
index 5dcc4cdfc4..8f24c2024d 100644
--- a/packages/lib-user/src/utils/getDateInterval.js
+++ b/packages/lib-user/src/utils/getDateInterval.js
@@ -12,7 +12,7 @@ function getPeriodFromDateDifference(difference) {
}
}
-function getDateInterval(dateRange) {
+export function getDateInterval(dateRange) {
const endDate = new Date()
const end_date = endDate.toISOString().substring(0, 10)
@@ -81,5 +81,3 @@ function getDateInterval(dateRange) {
}
}
}
-
-export { getDateInterval }