diff --git a/package-lock.json b/package-lock.json
index 9709f409..4afdbb6f 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -41,6 +41,7 @@
"moment": "^2.29.4",
"moment-timezone": "^0.5.38",
"next": "13.0.2",
+ "next-router-mock": "^0.9.9",
"papaparse": "^5.4.1",
"prettier": "^2.8.2",
"react": "^18.2.0",
@@ -9613,6 +9614,15 @@
}
}
},
+ "node_modules/next-router-mock": {
+ "version": "0.9.9",
+ "resolved": "https://registry.npmjs.org/next-router-mock/-/next-router-mock-0.9.9.tgz",
+ "integrity": "sha512-2o50zr+5pWj0zzcvBEWNHDlmWmlDExPdX5OuXKW2aCxV85XUA6MlELr0n0f0wtXj5dUVZ8qspHj6YwF7KZHrbA==",
+ "peerDependencies": {
+ "next": ">=10.0.0",
+ "react": ">=17.0.0"
+ }
+ },
"node_modules/next/node_modules/postcss": {
"version": "8.4.14",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.14.tgz",
@@ -19142,6 +19152,12 @@
}
}
},
+ "next-router-mock": {
+ "version": "0.9.9",
+ "resolved": "https://registry.npmjs.org/next-router-mock/-/next-router-mock-0.9.9.tgz",
+ "integrity": "sha512-2o50zr+5pWj0zzcvBEWNHDlmWmlDExPdX5OuXKW2aCxV85XUA6MlELr0n0f0wtXj5dUVZ8qspHj6YwF7KZHrbA==",
+ "requires": {}
+ },
"ngraph.events": {
"version": "1.2.2",
"resolved": "https://registry.npmjs.org/ngraph.events/-/ngraph.events-1.2.2.tgz",
diff --git a/package.json b/package.json
index f3b65d94..28b6dfe6 100644
--- a/package.json
+++ b/package.json
@@ -45,6 +45,7 @@
"moment": "^2.29.4",
"moment-timezone": "^0.5.38",
"next": "13.0.2",
+ "next-router-mock": "^0.9.9",
"papaparse": "^5.4.1",
"prettier": "^2.8.2",
"react": "^18.2.0",
diff --git a/src/components/global/SafaryClubScript.tsx b/src/components/global/SafaryClubScript.tsx
new file mode 100644
index 00000000..fba0c863
--- /dev/null
+++ b/src/components/global/SafaryClubScript.tsx
@@ -0,0 +1,21 @@
+import { useEffect } from 'react';
+
+const SafaryClubScript = () => {
+ useEffect(() => {
+ if (process.env.NODE_ENV === 'production') {
+ const script = document.createElement('script');
+ script.src = 'https://tag.safary.club/stag.js?id=prd_3F8QxipEOt';
+ script.async = true;
+ document.head.appendChild(script);
+
+ // Cleanup on component unmount
+ return () => {
+ document.head.removeChild(script);
+ };
+ }
+ }, []);
+
+ return null;
+};
+
+export default SafaryClubScript;
diff --git a/src/components/pages/communityHealth/Decentralization.tsx b/src/components/pages/communityHealth/Decentralization.tsx
index a09cab21..4ca21d49 100644
--- a/src/components/pages/communityHealth/Decentralization.tsx
+++ b/src/components/pages/communityHealth/Decentralization.tsx
@@ -196,8 +196,8 @@ function Decentralization({ scoreData }: DecentralizationProps) {
- Shows how much members are divided into informal cliques ranging
- from:
+ Shows how much conversations depend on one (or very few) key
+ members. Influence exists in a continuum between:
diff --git a/src/components/pages/statistics/ActiveMembersComposition.tsx b/src/components/pages/statistics/ActiveMembersComposition.tsx
index b84fdfc9..852f83e2 100644
--- a/src/components/pages/statistics/ActiveMembersComposition.tsx
+++ b/src/components/pages/statistics/ActiveMembersComposition.tsx
@@ -8,6 +8,7 @@ import { SeriesData, StatisticsProps } from '../../../utils/interfaces';
import { communityActiveDates } from '../../../lib/data/dateRangeValues';
import ActiveMemberBreakdown from './memberBreakdowns/activeMembers/ActiveMemberBreakdown';
import Loading from '../../global/Loading';
+import { useRouter } from 'next/router';
export interface ActiveMembersComposition {
activePeriod: number;
@@ -60,6 +61,8 @@ export default function ActiveMembersComposition({
activePeriod,
handleDateRange,
}: ActiveMembersComposition) {
+ const router = useRouter();
+
const { activeMembers, activeMembersLoading } = useAppStore();
const [options, setOptions] = useState(defaultOptions);
@@ -130,7 +133,7 @@ export default function ActiveMembersComposition({
value: activeMembers.totActiveMembers,
colorBadge: 'bg-green',
hasTooltip: true,
- customBackground: true,
+ customBackground: false,
tooltipText: (
<>
Interactions are all messages that:
@@ -195,6 +198,56 @@ export default function ActiveMembersComposition({
]);
}, [activeMembers]);
+ const handleSelectedOption = (label: string) => {
+ const currentPath = router.pathname;
+ const currentQuery = router.query;
+
+ let existingFilters: any[] = [];
+
+ // Check if we already have some filters
+ if (currentQuery.filter && typeof currentQuery.filter === 'string') {
+ try {
+ existingFilters = JSON.parse(currentQuery.filter);
+ } catch (e) {
+ console.error('Error parsing filters:', e);
+ }
+ }
+
+ // Check if the filterType already exists in the array
+ const existingFilterIndex = existingFilters.findIndex(
+ (filter) => filter.filterType === 'activeMemberComposition'
+ );
+
+ const newFilter = {
+ filterType: 'activeMemberComposition',
+ label: label,
+ };
+
+ if (existingFilterIndex !== -1) {
+ // If it exists, replace the existing filter's label with the new label
+ if (existingFilters[existingFilterIndex].label !== label) {
+ existingFilters[existingFilterIndex].label = label;
+ } else {
+ existingFilters.splice(existingFilterIndex, 1); // remove the item
+ }
+ } else {
+ // If it doesn't exist, add the new filter to the array
+ existingFilters.push(newFilter);
+ }
+
+ router.replace(
+ {
+ pathname: currentPath,
+ query: {
+ ...currentQuery,
+ filter: JSON.stringify(existingFilters),
+ },
+ },
+ undefined,
+ { shallow: true }
+ );
+ };
+
return (
<>
@@ -208,7 +261,12 @@ export default function ActiveMembersComposition({
-
+
diff --git a/src/components/pages/statistics/DisengagedMembersComposition.tsx b/src/components/pages/statistics/DisengagedMembersComposition.tsx
index c46da10b..fb4211a1 100644
--- a/src/components/pages/statistics/DisengagedMembersComposition.tsx
+++ b/src/components/pages/statistics/DisengagedMembersComposition.tsx
@@ -8,6 +8,7 @@ import { SeriesData, StatisticsProps } from '../../../utils/interfaces';
import { communityActiveDates } from '../../../lib/data/dateRangeValues';
import DisengagedMembersCompositionBreakdown from './memberBreakdowns/disengagedMembersComposition/DisengagedMembersCompositionBreakdown';
import Loading from '../../global/Loading';
+import router from 'next/router';
export interface DisengagedMembersComposition {
activePeriod: number;
@@ -125,7 +126,7 @@ export default function DisengagedMembersComposition({
value: disengagedMembers.becameDisengaged,
colorBadge: 'bg-error-500',
hasTooltip: false,
- customBackground: true,
+ customBackground: false,
},
{
label: 'Were Newly Active',
@@ -182,6 +183,55 @@ export default function DisengagedMembersComposition({
]);
}, [disengagedMembers]);
+ const handleSelectedOption = (label: string) => {
+ const currentPath = router.pathname;
+ const currentQuery = router.query;
+
+ let existingFilters: any[] = [];
+
+ // Check if we already have some filters
+ if (currentQuery.filter && typeof currentQuery.filter === 'string') {
+ try {
+ existingFilters = JSON.parse(currentQuery.filter);
+ } catch (e) {
+ console.error('Error parsing filters:', e);
+ }
+ }
+
+ // Check if the filterType already exists in the array
+ const existingFilterIndex = existingFilters.findIndex(
+ (filter) => filter.filterType === 'disengagedMemberComposition'
+ );
+
+ const newFilter = {
+ filterType: 'disengagedMemberComposition',
+ label: label,
+ };
+
+ if (existingFilterIndex !== -1) {
+ // If it exists, replace the existing filter's label with the new label
+ if (existingFilters[existingFilterIndex].label !== label) {
+ existingFilters[existingFilterIndex].label = label;
+ } else {
+ existingFilters.splice(existingFilterIndex, 1); // remove the item
+ }
+ } else {
+ // If it doesn't exist, add the new filter to the array
+ existingFilters.push(newFilter);
+ }
+
+ router.replace(
+ {
+ pathname: currentPath,
+ query: {
+ ...currentQuery,
+ filter: JSON.stringify(existingFilters),
+ },
+ },
+ undefined,
+ { shallow: true }
+ );
+ };
return (
<>
@@ -195,7 +245,12 @@ export default function DisengagedMembersComposition({
-
+
diff --git a/src/components/pages/statistics/Onboarding.spec.tsx b/src/components/pages/statistics/Onboarding.spec.tsx
index e140efa7..3cce1606 100644
--- a/src/components/pages/statistics/Onboarding.spec.tsx
+++ b/src/components/pages/statistics/Onboarding.spec.tsx
@@ -1,6 +1,7 @@
import { render, screen } from '@testing-library/react';
import Onboarding from './Onboarding';
import { communityActiveDates } from '../../../lib/data/dateRangeValues';
+jest.mock('next/router', () => require('next-router-mock'));
describe('Onboarding component', () => {
const mockActivePeriod = 1;
diff --git a/src/components/pages/statistics/Onboarding.tsx b/src/components/pages/statistics/Onboarding.tsx
index 9145e32d..8df069cb 100644
--- a/src/components/pages/statistics/Onboarding.tsx
+++ b/src/components/pages/statistics/Onboarding.tsx
@@ -8,6 +8,7 @@ import { SeriesData, StatisticsProps } from '../../../utils/interfaces';
import RangeSelect from '../../global/RangeSelect';
import OnboardingMembersBreakdown from './memberBreakdowns/onboardingMembers/OnboardingMembersBreakdown';
import Loading from '../../global/Loading';
+import router from 'next/router';
export interface OnboardingProps {
activePeriod: number;
@@ -127,7 +128,7 @@ export default function Onboarding({
value: onboardingMembers.joined,
colorBadge: 'bg-info',
hasTooltip: false,
- customBackground: true,
+ customBackground: false,
},
{
label: 'Newly Active',
@@ -159,6 +160,56 @@ export default function Onboarding({
]);
}, [onboardingMembers]);
+ const handleSelectedOption = (label: string) => {
+ const currentPath = router.pathname;
+ const currentQuery = router.query;
+
+ let existingFilters: any[] = [];
+
+ // Check if we already have some filters
+ if (currentQuery.filter && typeof currentQuery.filter === 'string') {
+ try {
+ existingFilters = JSON.parse(currentQuery.filter);
+ } catch (e) {
+ console.error('Error parsing filters:', e);
+ }
+ }
+
+ // Check if the filterType already exists in the array
+ const existingFilterIndex = existingFilters.findIndex(
+ (filter) => filter.filterType === 'onboardingMemberComposition'
+ );
+
+ const newFilter = {
+ filterType: 'onboardingMemberComposition',
+ label: label,
+ };
+
+ if (existingFilterIndex !== -1) {
+ // If it exists, replace the existing filter's label with the new label
+ if (existingFilters[existingFilterIndex].label !== label) {
+ existingFilters[existingFilterIndex].label = label;
+ } else {
+ existingFilters.splice(existingFilterIndex, 1); // remove the item
+ }
+ } else {
+ // If it doesn't exist, add the new filter to the array
+ existingFilters.push(newFilter);
+ }
+
+ router.replace(
+ {
+ pathname: currentPath,
+ query: {
+ ...currentQuery,
+ filter: JSON.stringify(existingFilters),
+ },
+ },
+ undefined,
+ { shallow: true }
+ );
+ };
+
return (
<>
@@ -172,7 +223,12 @@ export default function Onboarding({
-
+
diff --git a/src/components/pages/statistics/StatisticalData.tsx b/src/components/pages/statistics/StatisticalData.tsx
index 31280250..db698baa 100644
--- a/src/components/pages/statistics/StatisticalData.tsx
+++ b/src/components/pages/statistics/StatisticalData.tsx
@@ -1,19 +1,60 @@
import { Tooltip } from '@mui/material';
import clsx from 'clsx';
-import React from 'react';
+import React, { useEffect, useState } from 'react';
import { RxArrowTopRight, RxArrowBottomRight } from 'react-icons/rx';
import { AiOutlineExclamationCircle } from 'react-icons/ai';
import { StatisticsProps } from '../../../utils/interfaces';
+import router from 'next/router';
type StatisticalDataProps = {
statistics: StatisticsProps[];
+ ableToFilter?: boolean;
+ overviewType?:
+ | 'activeMemberComposition'
+ | 'onboardingMemberComposition'
+ | 'disengagedMemberComposition';
hideInformationText?: boolean;
+ handleSelectedOption?: (label: string) => void;
};
const StatisticalData: React.FC = ({
statistics,
+ ableToFilter,
+ overviewType,
hideInformationText,
+ handleSelectedOption,
}) => {
+ const [activeState, setActiveState] = useState();
+
+ useEffect(() => {
+ const queries = router.query;
+
+ if (queries.filter && typeof queries.filter === 'string') {
+ const filter = JSON.parse(queries?.filter);
+
+ if (filter) {
+ // Search for the first element that matches the 'filterType'
+ const matchedFilter = filter.find(
+ (el: any) => el.filterType === overviewType
+ );
+
+ // Check if matchedFilter exists
+ if (matchedFilter) {
+ // Check if matchedFilter has keys
+ if (Object.keys(matchedFilter).length > 0) {
+ setActiveState(matchedFilter.label);
+ } else {
+ setActiveState('');
+ }
+ } else {
+ setActiveState('');
+ }
+ } else {
+ setActiveState('');
+ }
+ }
+ }, [router.query]);
+
return (
<>
= ({
statistics.length > 3 ? 'justify-between' : 'justify-start'
)}
>
- {statistics.map((stat) => (
+ {statistics.map((stat, index) => (
{
+ if (handleSelectedOption) {
+ handleSelectedOption(stat.label);
+ }
+ }}
key={stat.label}
>
void;
handleActivityOptionSelectionChange: (selectedRoles: string[]) => void;
@@ -51,6 +53,7 @@ const CustomTable: React.FC = ({
data,
columns,
isLoading,
+ breakdownName,
handleRoleSelectionChange,
handleActivityOptionSelectionChange,
handleJoinedAtChange,
@@ -126,11 +129,11 @@ const CustomTable: React.FC = ({
useEffect(() => {
handleRoleSelectionChange(selectedRoles);
- }, [selectedRoles, handleRoleSelectionChange]);
+ }, [selectedRoles]);
useEffect(() => {
handleActivityOptionSelectionChange(selectedActivityOptions);
- }, [selectedActivityOptions, handleActivityOptionSelectionChange]);
+ }, [selectedActivityOptions]);
const handleSelectAllActivityOptions = (
event: React.ChangeEvent
@@ -143,6 +146,7 @@ const CustomTable: React.FC = ({
setSelectedActivityOptions([]);
}
setSelectAllActivityOptions(event.target.checked);
+ handleUpdateRouterQueries();
};
const handleSelectActivityOption = (
@@ -157,6 +161,31 @@ const CustomTable: React.FC = ({
setSelectAllActivityOptions(
updatedSelectedOptions.length === activityCompositionOptions.length
);
+ handleUpdateRouterQueries();
+ };
+
+ const handleUpdateRouterQueries = () => {
+ const queries = router.query;
+
+ if (queries.filter && typeof queries.filter === 'string') {
+ const filters = JSON.parse(queries?.filter);
+ const updatedFilters = filters.filter(
+ (el: any) => el.filterType !== breakdownName
+ );
+ router.replace(
+ {
+ pathname: router.pathname,
+ query: {
+ ...router.query,
+ filter: JSON.stringify(updatedFilters),
+ },
+ },
+ undefined,
+ {
+ shallow: true,
+ }
+ );
+ }
};
const formatDate = (date: string) => {
@@ -205,6 +234,36 @@ const CustomTable: React.FC = ({
setOpen(false);
};
+ useEffect(() => {
+ const queries = router.query;
+ if (queries.filter && typeof queries.filter === 'string') {
+ const filter = JSON.parse(queries?.filter);
+ if (filter) {
+ // Search for the first element that matches the 'filterType'
+ const matchedFilter = filter.find(
+ (el: any) => el.filterType === breakdownName
+ );
+
+ if (matchedFilter) {
+ const matchedLabel = matchedFilter.label.toLowerCase();
+
+ // Search for the first 'option' that matches the 'label' in 'matchedFilter'
+ const matchedOption = activityCompositionOptions.find(
+ (activityCompositionOption) =>
+ activityCompositionOption.name.toLowerCase() === matchedLabel
+ );
+
+ if (matchedOption) {
+ const matchedValue = matchedOption.value;
+
+ setSelectedActivityOptions([matchedValue]);
+ }
+ setSelectAllActivityOptions(false);
+ }
+ }
+ }
+ }, [router.query]);
+
return (
<>
diff --git a/src/components/pages/statistics/memberBreakdowns/activeMembers/ActiveMemberBreakdown.spec.tsx b/src/components/pages/statistics/memberBreakdowns/activeMembers/ActiveMemberBreakdown.spec.tsx
index 1d21b973..e175707b 100644
--- a/src/components/pages/statistics/memberBreakdowns/activeMembers/ActiveMemberBreakdown.spec.tsx
+++ b/src/components/pages/statistics/memberBreakdowns/activeMembers/ActiveMemberBreakdown.spec.tsx
@@ -1,5 +1,6 @@
import { render, screen } from '@testing-library/react';
import ActiveMemberBreakdown from './ActiveMemberBreakdown';
+jest.mock('next/router', () => require('next-router-mock'));
describe('ActiveMemberBreakdown', () => {
it('renders the component', () => {
diff --git a/src/components/pages/statistics/memberBreakdowns/activeMembers/ActiveMemberBreakdown.tsx b/src/components/pages/statistics/memberBreakdowns/activeMembers/ActiveMemberBreakdown.tsx
index e681917e..9cee797f 100644
--- a/src/components/pages/statistics/memberBreakdowns/activeMembers/ActiveMemberBreakdown.tsx
+++ b/src/components/pages/statistics/memberBreakdowns/activeMembers/ActiveMemberBreakdown.tsx
@@ -16,6 +16,7 @@ import {
convertToCSV,
downloadCSVFile,
} from '../../../../../helpers/csvHelper';
+import router from 'next/router';
const columns: Column[] = [
{ id: 'username', label: 'Name' },
@@ -28,14 +29,13 @@ const options: IActivityCompositionOptions[] = [
{ name: 'Active members', value: 'all_active', color: '#3AAE2B' },
{ name: 'Newly active', value: 'all_new_active', color: '#FF9022' },
{ name: 'Consistently active', value: 'all_consistent', color: '#804EE1' },
- { name: 'Vital member', value: 'all_vital', color: '#313671' },
+ { name: 'Vital members', value: 'all_vital', color: '#313671' },
{ name: 'Became disengaged', value: 'all_new_disengaged', color: '#EB3E56' },
{ name: 'Others', value: 'others', color: '#AAAAAA' },
];
export default function ActiveMemberBreakdown() {
- const { getActiveMemberCompositionTable, isActiveMembersBreakdownLoading } =
- useAppStore();
+ const { getActiveMemberCompositionTable } = useAppStore();
const tableTopRef = useRef(null);
@@ -94,6 +94,37 @@ export default function ActiveMemberBreakdown() {
setPage(1);
}, [activityComposition, roles, username, sortBy]);
+ useEffect(() => {
+ const queries = router.query;
+ if (queries.filter && typeof queries.filter === 'string') {
+ const filter = JSON.parse(queries?.filter);
+ if (filter) {
+ // Search for the first element that matches the 'filterType'
+ const matchedFilter = filter.find(
+ (el: any) => el.filterType === 'activeMemberComposition'
+ );
+
+ if (matchedFilter) {
+ const matchedLabel = matchedFilter.label.toLowerCase();
+
+ // Search for the first 'option' that matches the 'label' in 'matchedFilter'
+ const matchedOption = options.find(
+ (option) => option.name.toLowerCase() === matchedLabel
+ );
+
+ if (matchedOption) {
+ const matchedValue = matchedOption.value;
+ handleActivityOptionSelectionChange([matchedValue]);
+ }
+ } else {
+ handleActivityOptionSelectionChange(
+ options.map((option) => option.value)
+ );
+ }
+ }
+ }
+ }, [router.query]);
+
const handleRoleSelectionChange = (selectedRoles: string[]) => {
setRoles(selectedRoles);
};
@@ -188,6 +219,7 @@ export default function ActiveMemberBreakdown() {
handleUsernameChange={handleUsernameChange}
isLoading={loading}
activityCompositionOptions={options}
+ breakdownName="activeMemberComposition"
/>
diff --git a/src/components/pages/statistics/memberBreakdowns/disengagedMembersComposition/DisengagedMembersCompositionBreakdown.spec.tsx b/src/components/pages/statistics/memberBreakdowns/disengagedMembersComposition/DisengagedMembersCompositionBreakdown.spec.tsx
index 5d0ca59f..1ec85f55 100644
--- a/src/components/pages/statistics/memberBreakdowns/disengagedMembersComposition/DisengagedMembersCompositionBreakdown.spec.tsx
+++ b/src/components/pages/statistics/memberBreakdowns/disengagedMembersComposition/DisengagedMembersCompositionBreakdown.spec.tsx
@@ -1,5 +1,6 @@
import { render, screen } from '@testing-library/react';
import DisengagedMembersCompositionBreakdown from './DisengagedMembersCompositionBreakdown';
+jest.mock('next/router', () => require('next-router-mock'));
describe('ActiveMemberBreakdown', () => {
it('renders the component', () => {
diff --git a/src/components/pages/statistics/memberBreakdowns/disengagedMembersComposition/DisengagedMembersCompositionBreakdown.tsx b/src/components/pages/statistics/memberBreakdowns/disengagedMembersComposition/DisengagedMembersCompositionBreakdown.tsx
index ed8b8cbb..f4622493 100644
--- a/src/components/pages/statistics/memberBreakdowns/disengagedMembersComposition/DisengagedMembersCompositionBreakdown.tsx
+++ b/src/components/pages/statistics/memberBreakdowns/disengagedMembersComposition/DisengagedMembersCompositionBreakdown.tsx
@@ -16,6 +16,7 @@ import {
convertToCSV,
downloadCSVFile,
} from '../../../../../helpers/csvHelper';
+import router from 'next/router';
const columns: Column[] = [
{ id: 'username', label: 'Name' },
@@ -45,10 +46,7 @@ const options: IActivityCompositionOptions[] = [
];
export default function DisengagedMembersCompositionBreakdown() {
- const {
- getDisengagedMembersCompositionTable,
- isDisengagedMembersCompositionBreakdownLoading,
- } = useAppStore();
+ const { getDisengagedMembersCompositionTable } = useAppStore();
const tableTopRef = useRef(null);
@@ -107,6 +105,37 @@ export default function DisengagedMembersCompositionBreakdown() {
setPage(1);
}, [disengagedComposition, roles, username, sortBy]);
+ useEffect(() => {
+ const queries = router.query;
+ if (queries.filter && typeof queries.filter === 'string') {
+ const filter = JSON.parse(queries?.filter);
+ if (filter) {
+ // Search for the first element that matches the 'filterType'
+ const matchedFilter = filter.find(
+ (el: any) => el.filterType === 'disengagedMemberComposition'
+ );
+
+ if (matchedFilter) {
+ const matchedLabel = matchedFilter.label.toLowerCase();
+
+ // Search for the first 'option' that matches the 'label' in 'matchedFilter'
+ const matchedOption = options.find(
+ (option) => option.name.toLowerCase() === matchedLabel
+ );
+
+ if (matchedOption) {
+ const matchedValue = matchedOption.value;
+ handleActivityOptionSelectionChange([matchedValue]);
+ }
+ } else {
+ handleActivityOptionSelectionChange(
+ options.map((option) => option.value)
+ );
+ }
+ }
+ }
+ }, [router.query]);
+
const handleRoleSelectionChange = (selectedRoles: string[]) => {
setRoles(selectedRoles);
};
@@ -201,6 +230,7 @@ export default function DisengagedMembersCompositionBreakdown() {
handleUsernameChange={handleUsernameChange}
isLoading={loading}
activityCompositionOptions={options}
+ breakdownName="disengagedMemberComposition"
/>
diff --git a/src/components/pages/statistics/memberBreakdowns/onboardingMembers/OnboardingMembersBreakdown.spec.tsx b/src/components/pages/statistics/memberBreakdowns/onboardingMembers/OnboardingMembersBreakdown.spec.tsx
index 4053135f..34274109 100644
--- a/src/components/pages/statistics/memberBreakdowns/onboardingMembers/OnboardingMembersBreakdown.spec.tsx
+++ b/src/components/pages/statistics/memberBreakdowns/onboardingMembers/OnboardingMembersBreakdown.spec.tsx
@@ -1,5 +1,6 @@
import { render, screen } from '@testing-library/react';
import OnboardingMembersBreakdown from './OnboardingMembersBreakdown';
+jest.mock('next/router', () => require('next-router-mock'));
describe('ActiveMemberBreakdown', () => {
it('renders the component', () => {
diff --git a/src/components/pages/statistics/memberBreakdowns/onboardingMembers/OnboardingMembersBreakdown.tsx b/src/components/pages/statistics/memberBreakdowns/onboardingMembers/OnboardingMembersBreakdown.tsx
index dd0237b5..82652b62 100644
--- a/src/components/pages/statistics/memberBreakdowns/onboardingMembers/OnboardingMembersBreakdown.tsx
+++ b/src/components/pages/statistics/memberBreakdowns/onboardingMembers/OnboardingMembersBreakdown.tsx
@@ -16,6 +16,7 @@ import {
convertToCSV,
downloadCSVFile,
} from '../../../../../helpers/csvHelper';
+import router from 'next/router';
const columns: Column[] = [
{ id: 'username', label: 'Name' },
@@ -33,10 +34,7 @@ const options: IActivityCompositionOptions[] = [
];
export default function OnboardingMembersBreakdown() {
- const {
- getOnboardingMemberCompositionTable,
- isOnboardingMembersBreakdownLoading,
- } = useAppStore();
+ const { getOnboardingMemberCompositionTable } = useAppStore();
const tableTopRef = useRef(null);
@@ -95,6 +93,36 @@ export default function OnboardingMembersBreakdown() {
setPage(1);
}, [onboardingComposition, roles, username, sortBy]);
+ useEffect(() => {
+ const queries = router.query;
+ if (queries.filter && typeof queries.filter === 'string') {
+ const filter = JSON.parse(queries?.filter);
+ if (filter) {
+ // Search for the first element that matches the 'filterType'
+ const matchedFilter = filter.find(
+ (el: any) => el.filterType === 'onboardingMemberComposition'
+ );
+
+ if (matchedFilter) {
+ const matchedLabel = matchedFilter.label.toLowerCase();
+
+ // Search for the first 'option' that matches the 'label' in 'matchedFilter'
+ const matchedOption = options.find(
+ (option) => option.name.toLowerCase() === matchedLabel
+ );
+
+ if (matchedOption) {
+ const matchedValue = matchedOption.value;
+ handleActivityOptionSelectionChange([matchedValue]);
+ }
+ } else {
+ handleActivityOptionSelectionChange(
+ options.map((option) => option.value)
+ );
+ }
+ }
+ }
+ }, [router.query]);
const handleRoleSelectionChange = (selectedRoles: string[]) => {
setRoles(selectedRoles);
};
@@ -189,6 +217,7 @@ export default function OnboardingMembersBreakdown() {
handleUsernameChange={handleUsernameChange}
isLoading={loading}
activityCompositionOptions={options}
+ breakdownName="onboardingMemberComposition"
/>
diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx
index 48cbb4ac..cd49631d 100644
--- a/src/pages/_app.tsx
+++ b/src/pages/_app.tsx
@@ -23,6 +23,7 @@ import { conf } from '../configs';
import AmplitudeAnalytics from '../components/global/AmplitudeAnalytics';
import Script from 'next/script';
import { usePageViewTracking } from '../helpers/amplitudeHelper';
+import SafaryClubScript from '../components/global/SafaryClubScript';
export default function App({ Component, pageProps }: ComponentWithPageLayout) {
usePageViewTracking();
@@ -41,6 +42,7 @@ export default function App({ Component, pageProps }: ComponentWithPageLayout) {
return (
<>
+