From 4cda8ebb692a96f6e74131fdbc0b970178974bfd Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Thu, 14 Nov 2024 11:34:46 +0545 Subject: [PATCH 1/8] Fetch only published projects in Team Members page - Fixes #6629 --- frontend/src/views/teams.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/views/teams.js b/frontend/src/views/teams.js index 32a1b56b4e..8f2383e7e6 100644 --- a/frontend/src/views/teams.js +++ b/frontend/src/views/teams.js @@ -426,7 +426,7 @@ export function TeamDetail() { const [error, loading, team] = useFetch(`teams/${id}/`); // eslint-disable-next-line const [projectsError, projectsLoading, projects] = useFetch( - `projects/?teamId=${id}&omitMapResults=true&projectStatuses=PUBLISHED,DRAFT,ARCHIVED`, + `projects/?teamId=${id}&omitMapResults=true&projectStatuses=PUBLISHED`, id, ); const [isMember, setIsMember] = useState(false); From 9c04ab96fe2bc66e4f6579111e03cb0c90e98ae8 Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Thu, 14 Nov 2024 17:17:09 +0545 Subject: [PATCH 2/8] Do not allow Teams page without login - Fixes #6631 --- frontend/src/views/teams.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/frontend/src/views/teams.js b/frontend/src/views/teams.js index 8f2383e7e6..d3f73c6364 100644 --- a/frontend/src/views/teams.js +++ b/frontend/src/views/teams.js @@ -1,6 +1,6 @@ import { useState, useEffect } from 'react'; import { useSelector } from 'react-redux'; -import { Link, useNavigate, useParams } from 'react-router-dom'; +import { Link, useNavigate, useParams, useLocation } from 'react-router-dom'; import { FormattedMessage } from 'react-intl'; import { Form } from 'react-final-form'; import { @@ -421,6 +421,8 @@ export function EditTeam(props) { export function TeamDetail() { const { id } = useParams(); useSetTitleTag(`Team #${id}`); + const location = useLocation(); + const navigate = useNavigate(); const userDetails = useSelector((state) => state.auth.userDetails); const token = useSelector((state) => state.auth.token); const [error, loading, team] = useFetch(`teams/${id}/`); @@ -433,6 +435,16 @@ export function TeamDetail() { const [managers, setManagers] = useState([]); const [members, setMembers] = useState([]); + useEffect(() => { + if (!token) { + navigate('/login', { + state: { + from: location.pathname, + }, + }); + } + }, [location.pathname, navigate, token]); + useEffect(() => { if (team && team.members) { setManagers(filterActiveManagers(team.members)); From 197431f7e74128d0abf1c6ae74939c3de6775e84 Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Wed, 20 Nov 2024 13:52:45 +0545 Subject: [PATCH 3/8] Change `no_output_timeout` to 20m in circleci config - Fix frontend test case failure due to `context deadline exceeded` --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 733ec28069..c9cb775703 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -133,7 +133,7 @@ jobs: --output text) - run: name: Make Database Backup - no_output_timeout: 15m + no_output_timeout: 20m command: | aws rds wait db-instance-available \ --db-instance-identifier ${RDS_ID} @@ -211,7 +211,7 @@ jobs: /tmp/tasking-manager.cfn.json > "$tmpfile" && mv "$tmpfile" $CIRCLE_WORKING_DIRECTORY/cfn-config-<< parameters.stack_name >>.json - run: name: Deploy to << parameters.stack_name >> - no_output_timeout: 15m + no_output_timeout: 20m command: | export NODE_PATH=/usr/local/share/.config/yarn/global/node_modules/ validate-template $CIRCLE_WORKING_DIRECTORY/scripts/aws/cloudformation/tasking-manager.template.js From f5afb67bf29c0fc60d2a0a7c2e22bc3e679012de Mon Sep 17 00:00:00 2001 From: mahesh-naxa Date: Wed, 20 Nov 2024 17:45:52 +0545 Subject: [PATCH 4/8] edit: update circle ci frontend test worker freezing --- .circleci/config.yml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index c9cb775703..0674170b83 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -30,9 +30,10 @@ jobs: - env - run: name: Run yarn test + no_output_timeout: 20m command: | cd ${CIRCLE_WORKING_DIRECTORY}/frontend/ - CI=true yarn test -w 3 --silent + CI=true yarn test -w 1 --silent CI=true GENERATE_SOURCEMAP=false yarn build backend-code-check-PEP8: @@ -133,7 +134,6 @@ jobs: --output text) - run: name: Make Database Backup - no_output_timeout: 20m command: | aws rds wait db-instance-available \ --db-instance-identifier ${RDS_ID} @@ -211,7 +211,6 @@ jobs: /tmp/tasking-manager.cfn.json > "$tmpfile" && mv "$tmpfile" $CIRCLE_WORKING_DIRECTORY/cfn-config-<< parameters.stack_name >>.json - run: name: Deploy to << parameters.stack_name >> - no_output_timeout: 20m command: | export NODE_PATH=/usr/local/share/.config/yarn/global/node_modules/ validate-template $CIRCLE_WORKING_DIRECTORY/scripts/aws/cloudformation/tasking-manager.template.js From ed0e11dd7db57343efe78c58afe34f1e65971838 Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Mon, 30 Dec 2024 10:29:25 +0545 Subject: [PATCH 5/8] Add date filter to Mapswipe Statistics page - create `DateFilter` component - adjust UI spacings - add `fromDate` & `toDate` dynamically to api - add css `gap` property --- frontend/src/assets/styles/_extra.scss | 4 +- .../partnerMapswipeStats/contributionsGrid.js | 2 +- .../partnerMapswipeStats/dateFilter.js | 72 +++++++++++++++++++ .../partnerMapswipeStats/messages.js | 8 +++ frontend/src/views/partnersMapswipeStats.js | 30 ++++---- 5 files changed, 99 insertions(+), 17 deletions(-) create mode 100644 frontend/src/components/partnerMapswipeStats/dateFilter.js diff --git a/frontend/src/assets/styles/_extra.scss b/frontend/src/assets/styles/_extra.scss index 21dd10646e..afee4e75ca 100644 --- a/frontend/src/assets/styles/_extra.scss +++ b/frontend/src/assets/styles/_extra.scss @@ -611,8 +611,8 @@ a[href="https://www.mapbox.com/map-feedback/"] color: rgba($blue-dark, 0.9); } -.gap-0\.625 { - gap: 0.75rem; +.gap-0\.5 { + gap: 0.5rem; } .gap-0\.75 { diff --git a/frontend/src/components/partnerMapswipeStats/contributionsGrid.js b/frontend/src/components/partnerMapswipeStats/contributionsGrid.js index 691231e83e..648137c22d 100644 --- a/frontend/src/components/partnerMapswipeStats/contributionsGrid.js +++ b/frontend/src/components/partnerMapswipeStats/contributionsGrid.js @@ -71,7 +71,7 @@ export const ContributionsGrid = ({ contributionsByDate = [] }) => { return (
-

+

diff --git a/frontend/src/components/partnerMapswipeStats/dateFilter.js b/frontend/src/components/partnerMapswipeStats/dateFilter.js new file mode 100644 index 0000000000..8ca92fe706 --- /dev/null +++ b/frontend/src/components/partnerMapswipeStats/dateFilter.js @@ -0,0 +1,72 @@ +import { useEffect } from 'react'; +import { FormattedMessage } from 'react-intl'; +import DatePicker from 'react-datepicker'; +import { format, parse } from 'date-fns'; + +import { CalendarIcon } from '../svgIcons'; +import messages from './messages'; + +const today = new Date(); +const currentYear = today.getFullYear(); +const dateFormat = 'yyyy-MM-dd'; + +const initialState = { + fromDate: format(new Date(currentYear, 0, 1), dateFormat), + toDate: format(today, dateFormat), +}; + +export const DateFilter = ({ isLoading, filters, setFilters }) => { + // set initial date filter state + useEffect(() => { + setFilters((prev) => ({ + ...prev, + ...initialState, + })); + }, [setFilters]); + + const handleDateSelect = (key, date) => { + setFilters((prev) => ({ + ...prev, + [key]: date, + })); + }; + + if (isLoading) return <>; + + return ( +
+
+
+ + { + handleDateSelect('fromDate', format(date, dateFormat)); + }} + dateFormat={dateFormat} + className="w4 pv2 ph1 ba b--grey-light" + showYearDropdown + scrollableYearDropdown + /> + + to + + + { + handleDateSelect('toDate', format(date, dateFormat)); + }} + dateFormat={dateFormat} + className="w4 pv2 ph1 ba b--grey-light" + showYearDropdown + scrollableYearDropdown + /> +
+ + + +
+
+ ); +}; diff --git a/frontend/src/components/partnerMapswipeStats/messages.js b/frontend/src/components/partnerMapswipeStats/messages.js index 8f5a3d4a98..c9b06e5ae5 100644 --- a/frontend/src/components/partnerMapswipeStats/messages.js +++ b/frontend/src/components/partnerMapswipeStats/messages.js @@ -56,6 +56,14 @@ export default defineMessages({ id: 'management.partners.stats.mapswipe.groupMembers.error', defaultMessage: 'Something went wrong!', }, + groupStatsboard: { + id: 'management.partners.stats.mapswipe.groupStatsboard', + defaultMessage: 'Group Statsboard', + }, + dateFilterSubText: { + id: 'management.partners.stats.mapswipe.dateFilterSubText', + defaultMessage: 'All dates are calculated in UTC', + }, contributions: { id: 'management.partners.stats.mapswipe.contributions', defaultMessage: 'Contributions', diff --git a/frontend/src/views/partnersMapswipeStats.js b/frontend/src/views/partnersMapswipeStats.js index b3b097b804..ae1fe69b2f 100644 --- a/frontend/src/views/partnersMapswipeStats.js +++ b/frontend/src/views/partnersMapswipeStats.js @@ -1,3 +1,4 @@ +import { useState } from 'react'; import { FormattedMessage } from 'react-intl'; import { useParams } from 'react-router-dom'; import ReactPlaceholder from 'react-placeholder'; @@ -9,6 +10,7 @@ import { getShortNumber, formatSecondsToTwoUnits, } from '../components/partnerMapswipeStats/overview'; +import { DateFilter } from '../components/partnerMapswipeStats/dateFilter'; import { GroupMembers } from '../components/partnerMapswipeStats/groupMembers'; import { ContributionsGrid } from '../components/partnerMapswipeStats/contributionsGrid'; import { ContributionsHeatmap } from '../components/partnerMapswipeStats/contributionsHeatmap'; @@ -19,7 +21,10 @@ import { SwipesByProjectType } from '../components/partnerMapswipeStats/swipesBy import { SwipesByOrganization } from '../components/partnerMapswipeStats/swipesByOrganization'; import messages from './messages'; import { fetchLocalJSONAPI } from '../network/genericJSONRequest'; + import './partnersMapswipeStats.scss'; +import 'react-placeholder/lib/reactPlaceholder.css'; +import 'react-datepicker/dist/react-datepicker.css'; const PagePlaceholder = () => (
@@ -57,23 +62,18 @@ const InfoBanner = () => { export const PartnersMapswipeStats = () => { const { id: partnerPermalink } = useParams(); + const [filters, setFilters] = useState({}); // state for date filter const { isLoading, isError, data, isRefetching } = useQuery({ - queryKey: ['partners-mapswipe-filtered-statistics', partnerPermalink], + queryKey: [ + 'partners-mapswipe-filtered-statistics', + partnerPermalink, + filters.fromDate, + filters.toDate, + ], queryFn: async () => { - const today = new Date(); - const currentYear = today.getFullYear(); - - const formatDate = (date) => { - const offset = date.getTimezoneOffset(); - const adjustedDate = new Date(date.getTime() - offset * 60 * 1000); - return adjustedDate.toISOString().split('T')[0]; - }; - - const fromDate = formatDate(new Date(currentYear, 0, 1)); - const endDate = formatDate(today); - + const { fromDate, toDate } = filters; const response = await fetchLocalJSONAPI( - `partners/${partnerPermalink}/filtered-statistics/?fromDate=${fromDate}&toDate=${endDate}`, + `partners/${partnerPermalink}/filtered-statistics/?fromDate=${fromDate}&toDate=${toDate}`, ); return response; }, @@ -105,6 +105,8 @@ export const PartnersMapswipeStats = () => { + + } ready={!isLoading && !isRefetching}> {!isLoading && isError ? (
From 38c398bef8034ff7edaf0ccb2e17d18deee4a769 Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Tue, 31 Dec 2024 09:36:24 +0545 Subject: [PATCH 6/8] Make fonts consistent in Mapswipe Overview cards --- frontend/src/components/partnerMapswipeStats/overview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/components/partnerMapswipeStats/overview.js b/frontend/src/components/partnerMapswipeStats/overview.js index eb88287fa6..153781569d 100644 --- a/frontend/src/components/partnerMapswipeStats/overview.js +++ b/frontend/src/components/partnerMapswipeStats/overview.js @@ -59,7 +59,7 @@ export const getShortNumber = (value) => {   - {shortNumberValue.substr(-1)} + {shortNumberValue.substr(-1)} ); }; From caec397fc5e0fcc7e166ff5bd63761298b810c13 Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Thu, 2 Jan 2025 15:02:43 +0545 Subject: [PATCH 7/8] Make Contributions Grid dynamically take dates from the applied filter --- .../partnerMapswipeStats/contributionsGrid.js | 27 +++++++------------ frontend/src/views/partnersMapswipeStats.js | 6 ++++- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/frontend/src/components/partnerMapswipeStats/contributionsGrid.js b/frontend/src/components/partnerMapswipeStats/contributionsGrid.js index 648137c22d..18b5313d95 100644 --- a/frontend/src/components/partnerMapswipeStats/contributionsGrid.js +++ b/frontend/src/components/partnerMapswipeStats/contributionsGrid.js @@ -1,11 +1,13 @@ import CalendarHeatmap from 'react-calendar-heatmap'; import { Tooltip } from 'react-tooltip'; import { FormattedMessage, useIntl } from 'react-intl'; +import { format } from 'date-fns'; import PropTypes from 'prop-types'; import messages from './messages'; const LEGEND_INDEXES = [30, 50, 70, 100]; + const Legend = () => { const legendFontStyle = 'ph2 f7 blue-grey ttc'; @@ -25,27 +27,13 @@ const Legend = () => { ); }; -export const ContributionsGrid = ({ contributionsByDate = [] }) => { +export const ContributionsGrid = ({ contributionsByDate = [], startDate, endDate }) => { const gridData = contributionsByDate.map((contribution) => ({ date: contribution.taskDate, count: contribution.totalcontributions, })); const intl = useIntl(); - const getDate = (isEndDate = false) => { - const today = new Date(); - const currentYear = today.getFullYear(); - - const formatDate = (date) => { - const offset = date.getTimezoneOffset(); - return new Date(date.getTime() - offset * 60 * 1000); - }; - - return !isEndDate - ? formatDate(new Date(currentYear - 1, 11, 31)) - : formatDate(new Date(currentYear, 11, 31)); - }; - const countValues = gridData.map((contribution) => contribution.count); const maxValue = Math.max(...countValues); @@ -69,6 +57,9 @@ export const ContributionsGrid = ({ contributionsByDate = [] }) => { } }; + const endDateYear = endDate.split('-')[0]; + const formattedEndDate = format(new Date(endDateYear, 11, 31), 'yyyy-MM-dd'); + return (

@@ -77,8 +68,8 @@ export const ContributionsGrid = ({ contributionsByDate = [] }) => {
{ if (!value) return 'fill-tan'; @@ -114,4 +105,6 @@ ContributionsGrid.propTypes = { totalcontributions: PropTypes.number, }), ), + startDate: PropTypes.instanceOf(Date), + endDate: PropTypes.instanceOf(Date), }; diff --git a/frontend/src/views/partnersMapswipeStats.js b/frontend/src/views/partnersMapswipeStats.js index ae1fe69b2f..37e7d3a384 100644 --- a/frontend/src/views/partnersMapswipeStats.js +++ b/frontend/src/views/partnersMapswipeStats.js @@ -120,7 +120,11 @@ export const PartnersMapswipeStats = () => { ) : ( <>
- +
From 9107ddced2ec99e3247da45b0c3ee7f7d441309e Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Thu, 2 Jan 2025 15:07:04 +0545 Subject: [PATCH 8/8] Fix crash issue when date filter start & end date mismatch - Adjust dates when start date greater than end date or vice versa --- .../partnerMapswipeStats/dateFilter.js | 25 ++++++++++++++++--- frontend/src/views/partnersMapswipeStats.js | 2 -- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/frontend/src/components/partnerMapswipeStats/dateFilter.js b/frontend/src/components/partnerMapswipeStats/dateFilter.js index 8ca92fe706..0eda552f81 100644 --- a/frontend/src/components/partnerMapswipeStats/dateFilter.js +++ b/frontend/src/components/partnerMapswipeStats/dateFilter.js @@ -1,7 +1,8 @@ import { useEffect } from 'react'; import { FormattedMessage } from 'react-intl'; -import DatePicker from 'react-datepicker'; import { format, parse } from 'date-fns'; +import DatePicker from 'react-datepicker'; +import 'react-datepicker/dist/react-datepicker.css'; import { CalendarIcon } from '../svgIcons'; import messages from './messages'; @@ -24,10 +25,28 @@ export const DateFilter = ({ isLoading, filters, setFilters }) => { })); }, [setFilters]); - const handleDateSelect = (key, date) => { + const handleDateSelect = (key, selectedDate) => { + let { fromDate, toDate } = filters; + const selectedDateValue = new Date(selectedDate).valueOf(); + const toDateValue = new Date(toDate).valueOf(); + const fromDateValue = new Date(fromDate).valueOf(); + // adjust from and to date based on greater/lesser value + if (key === 'fromDate' && selectedDateValue > toDateValue) { + fromDate = toDate; + toDate = selectedDate; + } else if (key === 'toDate' && selectedDateValue < fromDateValue) { + toDate = fromDate; + fromDate = selectedDate; + } else if (key === 'toDate') { + toDate = selectedDate; + } else { + fromDate = selectedDate; + } + // set filters state setFilters((prev) => ({ ...prev, - [key]: date, + fromDate, + toDate, })); }; diff --git a/frontend/src/views/partnersMapswipeStats.js b/frontend/src/views/partnersMapswipeStats.js index 37e7d3a384..948d166764 100644 --- a/frontend/src/views/partnersMapswipeStats.js +++ b/frontend/src/views/partnersMapswipeStats.js @@ -23,8 +23,6 @@ import messages from './messages'; import { fetchLocalJSONAPI } from '../network/genericJSONRequest'; import './partnersMapswipeStats.scss'; -import 'react-placeholder/lib/reactPlaceholder.css'; -import 'react-datepicker/dist/react-datepicker.css'; const PagePlaceholder = () => (