Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/member breakdown filter by overview boxes #182

Merged
merged 3 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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