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:

centralized 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 ( <> +