Skip to content

Commit

Permalink
Merge pull request #182 from TogetherCrew/feat/member-breakdown-filte…
Browse files Browse the repository at this point in the history
…r-overview

Feat/member breakdown filter by overview boxes
  • Loading branch information
cyri113 authored Sep 14, 2023
2 parents 009834c + 52b1114 commit 9c1eb91
Show file tree
Hide file tree
Showing 14 changed files with 380 additions and 15 deletions.
16 changes: 16 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
57 changes: 55 additions & 2 deletions src/components/pages/statistics/ActiveMembersComposition.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -60,6 +61,8 @@ export default function ActiveMembersComposition({
activePeriod,
handleDateRange,
}: ActiveMembersComposition) {
const router = useRouter();

const { activeMembers, activeMembersLoading } = useAppStore();

const [options, setOptions] = useState(defaultOptions);
Expand Down Expand Up @@ -130,7 +133,7 @@ export default function ActiveMembersComposition({
value: activeMembers.totActiveMembers,
colorBadge: 'bg-green',
hasTooltip: true,
customBackground: true,
customBackground: false,
tooltipText: (
<>
<span>Interactions are all messages that:</span>
Expand Down Expand Up @@ -195,6 +198,52 @@ 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
existingFilters[existingFilterIndex].label = label;
} 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 (
<>
<div className="flex flex-row justify-between">
Expand All @@ -208,7 +257,11 @@ export default function ActiveMembersComposition({
</div>
</div>
<div className="overflow-x-scroll overflow-y-hidden md:overflow-hidden">
<StatisticalData statistics={[...statistics]} />
<StatisticalData
overviewType="activeMemberComposition"
statistics={[...statistics]}
handleSelectedOption={handleSelectedOption}
/>
</div>

<ActiveMemberBreakdown />
Expand Down
54 changes: 52 additions & 2 deletions src/components/pages/statistics/DisengagedMembersComposition.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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',
Expand Down Expand Up @@ -182,6 +183,51 @@ 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
existingFilters[existingFilterIndex].label = label;
} 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 (
<>
<div className="flex flex-row justify-between">
Expand All @@ -195,7 +241,11 @@ export default function DisengagedMembersComposition({
</div>
</div>
<div className="overflow-x-scroll overflow-y-hidden md:overflow-hidden">
<StatisticalData statistics={[...statistics]} />
<StatisticalData
overviewType="disengagedMemberComposition"
statistics={[...statistics]}
handleSelectedOption={handleSelectedOption}
/>
</div>

<DisengagedMembersCompositionBreakdown />
Expand Down
1 change: 1 addition & 0 deletions src/components/pages/statistics/Onboarding.spec.tsx
Original file line number Diff line number Diff line change
@@ -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;
Expand Down
55 changes: 53 additions & 2 deletions src/components/pages/statistics/Onboarding.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -127,7 +128,7 @@ export default function Onboarding({
value: onboardingMembers.joined,
colorBadge: 'bg-info',
hasTooltip: false,
customBackground: true,
customBackground: false,
},
{
label: 'Newly Active',
Expand Down Expand Up @@ -159,6 +160,52 @@ 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
existingFilters[existingFilterIndex].label = label;
} 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 (
<>
<div className="flex flex-row justify-between">
Expand All @@ -172,7 +219,11 @@ export default function Onboarding({
</div>
</div>
<div className="overflow-x-scroll overflow-y-hidden md:overflow-hidden">
<StatisticalData statistics={[...statistics]} />
<StatisticalData
overviewType="onboardingMemberComposition"
statistics={[...statistics]}
handleSelectedOption={handleSelectedOption}
/>
</div>

<OnboardingMembersBreakdown />
Expand Down
54 changes: 50 additions & 4 deletions src/components/pages/statistics/StatisticalData.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,58 @@
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[];
overviewType?:
| 'activeMemberComposition'
| 'onboardingMemberComposition'
| 'disengagedMemberComposition';
hideInformationText?: boolean;
handleSelectedOption?: (label: string) => void;
};

const StatisticalData: React.FC<StatisticalDataProps> = ({
statistics,
overviewType,
hideInformationText,
handleSelectedOption,
}) => {
const [activeState, setActiveState] = useState<string | string[]>();

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 (
<>
<div
Expand All @@ -22,15 +61,22 @@ const StatisticalData: React.FC<StatisticalDataProps> = ({
statistics.length > 3 ? 'justify-between' : 'justify-start'
)}
>
{statistics.map((stat) => (
{statistics.map((stat, index) => (
<div
className={clsx(
'flex flex-col flex-1 text-center justify-center relative rounded-2xl',
'flex flex-col flex-1 text-center justify-center relative rounded-2xl hover:bg-gray-background ease-in delay-75 cursor-pointer',
stat.description
? 'min-w-full h-[200px] md:min-w-[100px] xl:min-w-[220px] md:max-w-[280px] md:h-[200px]'
: 'min-w-full h-[170px] md:min-w-[100px] xl:min-w-[280px] md:max-w-[280px] md:h-[180px]',
stat.customBackground ? 'bg-gray-hover' : ''
stat.customBackground || stat.label === activeState
? 'bg-gray-hover'
: ''
)}
onClick={() => {
if (handleSelectedOption) {
handleSelectedOption(stat.label);
}
}}
key={stat.label}
>
<span
Expand Down
Loading

0 comments on commit 9c1eb91

Please sign in to comment.