Skip to content
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
40 changes: 29 additions & 11 deletions community-dashboard/app/Base/utils/temporal.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { isDefined } from '@togglecorp/fujs';

export function getDateSafe(value: Date | number | string) {
if (typeof value === 'string') {
return new Date(`${value}T00:00`);
}

return new Date(value);
}

export function resolveTime(date: Date | number | string, resolution: 'day' | 'month' | 'year'): Date {
const newDate = new Date(date);
const newDate = getDateSafe(date);

if (resolution === 'day' || resolution === 'month' || resolution === 'year') {
newDate.setUTCHours(0, 0, 0, 0);
}
Expand All @@ -22,42 +31,51 @@ export function getTimestamps(
const sanitizedStartDate = resolveTime(startDate, resolution);
const sanitizedEndDate = resolveTime(endDate, resolution);

const returns: number[] = [
const timestamps: number[] = [
sanitizedStartDate.getTime(),
];

while (sanitizedStartDate < sanitizedEndDate) {
let increment = 1;
while (true) {
const myDate = new Date(sanitizedStartDate);
if (resolution === 'year') {
sanitizedStartDate.setFullYear(sanitizedStartDate.getFullYear() + 1);
myDate.setFullYear(sanitizedStartDate.getFullYear() + increment);
} else if (resolution === 'month') {
sanitizedStartDate.setMonth(sanitizedStartDate.getMonth() + 1);
myDate.setMonth(sanitizedStartDate.getMonth() + increment);
} else {
sanitizedStartDate.setDate(sanitizedStartDate.getDate() + 1);
myDate.setDate(sanitizedStartDate.getDate() + increment);
}
myDate.setUTCHours(0, 0, 0, 0);

if (myDate > sanitizedEndDate) {
break;
}
returns.push(sanitizedStartDate.getTime());

timestamps.push(myDate.getTime());
increment += 1;
}

return returns;
return timestamps;
}

export function formatDate(value: number | string) {
const date = new Date(value);
const date = getDateSafe(value);
return new Intl.DateTimeFormat(
navigator.language,
{ year: 'numeric', month: 'short', day: 'numeric' },
).format(date);
}

export function formatMonth(value: number | string) {
const date = new Date(value);
const date = getDateSafe(value);
return new Intl.DateTimeFormat(
navigator.language,
{ year: 'numeric', month: 'short' },
).format(date);
}

export function formatYear(value: number | string) {
const date = new Date(value);
const date = getDateSafe(value);
return new Intl.DateTimeFormat(
navigator.language,
{ year: 'numeric' },
Expand Down
8 changes: 5 additions & 3 deletions community-dashboard/app/components/Calendar/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
IoCalendarOutline,
} from 'react-icons/io5';

import { getDateSafe } from '#utils/temporal';

import Button from '../Button';
import NumberInput from '../NumberInput';
import SelectInput from '../SelectInput';
Expand Down Expand Up @@ -124,7 +126,7 @@ function Calendar<P extends CalendarDateProps>(props: Props<P>) {
} = props;

const today = new Date();
const current = initialDate ? new Date(initialDate) : today;
const current = initialDate ? getDateSafe(initialDate) : today;
const currentYear = current.getFullYear();
const currentMonth = current.getMonth();

Expand Down Expand Up @@ -193,8 +195,8 @@ function Calendar<P extends CalendarDateProps>(props: Props<P>) {
styles.monthSelectionPopup,
)}
optionsPopupContentClassName={styles.popupContent}
optionRenderer={undefined}
optionRendererParams={undefined}
// optionRenderer={undefined}
// optionRendererParams={undefined}
/>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import { scaleQuantile } from 'd3-scale';
import ReactTooltip from 'react-tooltip';
import InformationCard from '#components/InformationCard';

import { getDateSafe } from '#utils/temporal';

import styles from './styles.css';

const githubColors = [' #eeeeee', '#d6e685', '#8cc665', '#44a340', '#1e6823'];
Expand All @@ -24,15 +26,16 @@ function getDateRange(data: Data[] | null | undefined) {
const startDate = sortedData[0].date;
const endDate = sortedData[sortedData.length - 1].date;

if (getDifferenceInDays(new Date(endDate).getTime(), new Date(startDate).getTime()) <= 365) {
const currentYear = new Date(startDate).getFullYear();
if (getDifferenceInDays(getDateSafe(endDate).getTime(),
getDateSafe(startDate).getTime()) <= 365) {
const currentYear = getDateSafe(startDate).getFullYear();
return {
startDate: encodeDate(new Date(currentYear, 0, 1)),
endDate: encodeDate(new Date(currentYear, 11, 31)),
};
}
const startDateTime = new Date(startDate);
const endDateTime = new Date(endDate);
const startDateTime = getDateSafe(startDate);
const endDateTime = getDateSafe(endDate);

return {
startDate: encodeDate(new Date(startDateTime.getFullYear(), startDateTime.getMonth(), 1)),
Expand Down
2 changes: 1 addition & 1 deletion community-dashboard/app/components/Page/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ function Page(props: Props) {
value={props.totalUserGroups}
label="Total Groups"
// eslint-disable-next-line react/destructuring-assignment
secondaryValue={props.totalContributorsLastMonth}
secondaryValue={props.totalUserGroupsLastMonth}
secondaryValueDescription="active groups in the last 30 days"
/>
</>
Expand Down
28 changes: 19 additions & 9 deletions community-dashboard/app/views/StatsBoard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import {
formatYear,
resolveTime,
getTimestamps,
getDateSafe,
} from '#utils/temporal';
import styles from './styles.css';

Expand Down Expand Up @@ -120,6 +121,10 @@ const organizationTotalSwipeFormatter = (value: number, name: string) => (
[value.toLocaleString(), organizationNameFormatter(name)]
);

const missionTypeTotalSwipeFormatter = (value: number, name: string) => (
[value.toLocaleString(), name]
);

// Timeseries by week day

interface Day {
Expand Down Expand Up @@ -208,14 +213,15 @@ function StatsBoard(props: Props) {
React.useEffect(
() => {
const timestamps = contributionTimeStats?.map(
(item) => new Date(item.date).getTime(),
(item) => getDateSafe(item.date).getTime(),
) ?? [];

if (timestamps.length <= 0) {
timestamps.push(new Date().getTime());
}

const minDate = new Date(Math.min(...timestamps));
const maxDate = new Date(Math.max(...timestamps));
const minDate = getDateSafe(Math.min(...timestamps));
const maxDate = getDateSafe(Math.max(...timestamps));

const minDateYear = minDate.getFullYear();
const maxDateYear = maxDate.getFullYear();
Expand Down Expand Up @@ -295,11 +301,13 @@ function StatsBoard(props: Props) {
(item) => item.total,
);

return getTimestamps(
const timestamps = getTimestamps(
contributionTimeSeries[0].date,
contributionTimeSeries[contributionTimeSeries.length - 1].date,
resolution,
).map((item) => ({
);

return timestamps.map((item) => ({
total: mapping[item] ?? 0,
date: item,
}));
Expand All @@ -325,7 +333,7 @@ function StatsBoard(props: Props) {
const totalContributionByDay = useMemo(() => {
const dayWiseContribution = listToGroupList(
contributionTimeStats,
(d) => new Date(d.date).getDay(),
(d) => getDateSafe(d.date).getDay(),
(d) => d.totalSwipeTime,
);

Expand Down Expand Up @@ -364,7 +372,7 @@ function StatsBoard(props: Props) {
...item,
projectType: item.projectType ?? '-1',
}))
.sort((a, b) => compareNumber(a.totalSwipes, b.totalSwipes)) ?? []
.sort((a, b) => compareNumber(a.totalSwipes, b.totalSwipes, -1)) ?? []
),
[swipeByProjectType],
);
Expand All @@ -382,7 +390,7 @@ function StatsBoard(props: Props) {
organizationName: item.organizationName ?? 'Unknown',
}))
.filter((project) => isDefined(project.organizationName))
.sort((a, b) => compareNumber(a.totalSwipes, b.totalSwipes)) ?? [];
.sort((a, b) => compareNumber(a.totalSwipes, b.totalSwipes, -1)) ?? [];

if (sortedTotalSwipeByOrganization.length <= 5) {
return sortedTotalSwipeByOrganization;
Expand Down Expand Up @@ -706,7 +714,9 @@ function StatsBoard(props: Props) {
{sortedProjectSwipeType.length > 0 ? (
<ResponsiveContainer>
<PieChart>
<Tooltip />
<Tooltip
formatter={missionTypeTotalSwipeFormatter}
/>
<Legend
align={documentWidth <= CHART_BREAKPOINT ? 'center' : 'right'}
layout={documentWidth <= CHART_BREAKPOINT ? 'horizontal' : 'vertical'}
Expand Down