Skip to content

Commit

Permalink
Merge branch 'master' into dependabot/npm_and_yarn/react-i18next-14.1.3
Browse files Browse the repository at this point in the history
  • Loading branch information
goplayoutside3 authored Nov 18, 2024
2 parents 677353b + 4d0cde2 commit a49df5f
Show file tree
Hide file tree
Showing 5 changed files with 102 additions and 22 deletions.
1 change: 1 addition & 0 deletions docs/arch/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,4 @@
- [ADR 58: Internationalisation with the Panoptes translations API](adr-58.md)
- [ADR 59: Incremental Static Regeneration of project pages](adr-59.md)
- [ADR 60: Enabling Aggregations (Caesar Reducers) on Workflows](adr-60.md)
- [ADR 61: Displaying Stats in UTC Date Ranges](adr-61.md)
47 changes: 47 additions & 0 deletions docs/arch/adr-61.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Displaying Stats in UTC Date Ranges

## Status
Accepted


## Context

Launch of the new homepages, user stats pages, and group stats pages have put a spotlight on our stats service. The new features allow users to see their classification counts and time spent increase after every contribution to a project.

Classification metadata is stored in the database with UTC timestamps, and the stats service, ERAS, aggregates classification counts into buckets by UTC date ranges. However, not all UI components have clear labels indicating a UTC data range, and volunteers could encounter three unintuitive (but expected) scenarios:

### When a volunteer's local timezone is behind UTC

Example: A volunteer submits classifications at 9pm Chicago, but it's 3am UTC.

Classification metadata is stored in our database with UTC timestamps. If a volunteer's local timezone is Oct 31, but the UTC date is Nov 1 then their classifications are put into the time bucket for Nov 1. In a bar chart UI component that displays "Last 7 Days", the volunteer sees Oct 26 - Nov 1. As this volunteer submits classifications, their classification count will increase in the bar for Nov 1 (not their local time of 9pm Oct 31).

### When a volunteer's local timezone is ahead of UTC

Example: A volunteer submits classifications at 8am Korea, but it's 11pm UTC.

If a volunteer's local timezone is Nov 2, but the UTC date is Nov 1, then their classifications are still put into the time bucket for Nov 1. In a bar chart UI component that displays "Last 7 Days", the volunteer sees Oct 26 - Nov 1. As this volunteer submits classifications, their classification count will increase in the bar for Nov 1 (not their local time of 8am Nov 2). This volunteer won't see a bar for Nov 2 on the chart.

### UI Labels that are too relative

The YourStats component in app-project is displayed on each project's Classify page. It has a label for a user's classification count "today". Classification counts "today" are fetched as a time bucket for the current date UTC. However, a volunteer could easily assume "today" means the date of their local timezone, and fall into the two scenarios above.

The YourStats component also has a week-long bar chart with "daily" classification counts that also falls into the two scenarios above.


## Consequences

Whenever classification stats are displayed on the Zooniverse website, we should be clear that the date range is UTC, not a user's local timezone. The YourStats component in app-project has the most potential for volunteers to report discrepancies as described above because of its focus on "today".

Following this ADR, the decisions below will be implemented. When a user navigates the Zooniverse website, their classification counts will be fetched and displayed consistently in UTC date ranges.


## Decision

1. An x-axis label "Date Range (UTC)" will be added to bar charts displaying user stats, group stats, and project stats.

2. A question + answer will be added to the About Zooniverse > FAQ page explaining why stats data are displayed in a UTC date range.

3. The YourStats component in app-project will be redesigned and refactored to match the "Last 7 Days" and "All Time" stats components on a user's personal stats page. The label "Last 7 Days" is more adaptable to volunteers located across the globe, yet granular enough to display incrementing classification counts "live".

4. The eventual redesign and development of the Project Stats page will follow the above practice of a clear x-axis label and data fetching in UTC date ranges.
37 changes: 23 additions & 14 deletions packages/lib-content/src/screens/FAQ/FAQ.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,24 @@ function FAQPage() {
<Trans
i18nKey='FAQ.item3.answer'
t={t}
components={[<Anchor key='stats-blog-post' href='https://blog.zooniverse.org/2024/09/17/launch-news-community-building-pages' />]}
components={[
<Anchor
key='stats-blog-post'
href='https://blog.zooniverse.org/2024/09/17/launch-news-community-building-pages'
/>
]}
/>
</Answer>
</Box>
<Box as='li'>
<Question>{t('FAQ.item4.question')}</Question>
<Answer>{t('FAQ.item4.answer')}</Answer>
</Box>
<Box as='li'>
<Question>{t('FAQ.item5.question')}</Question>
<Answer>
<Trans
i18nKey='FAQ.item4.answer'
i18nKey='FAQ.item5.answer'
t={t}
components={[
<Anchor
Expand All @@ -117,10 +126,10 @@ function FAQPage() {
</Answer>
</Box>
<Box as='li'>
<Question>{t('FAQ.item5.question')}</Question>
<Question>{t('FAQ.item6.question')}</Question>
<Answer>
<Trans
i18nKey='FAQ.item5.answer'
i18nKey='FAQ.item6.answer'
t={t}
components={[
<Anchor
Expand All @@ -137,10 +146,10 @@ function FAQPage() {
</Answer>
</Box>
<Box as='li'>
<Question>{t('FAQ.item6.question')}</Question>
<Question>{t('FAQ.item7.question')}</Question>
<Answer>
<Trans
i18nKey='FAQ.item6.answer'
i18nKey='FAQ.item7.answer'
t={t}
components={[
<Anchor
Expand All @@ -152,11 +161,11 @@ function FAQPage() {
</Answer>
</Box>
<Box as='li'>
<Question>{t('FAQ.item7.question')}</Question>
<Answer>{t('FAQ.item7.answer0')}</Answer>
<Question>{t('FAQ.item8.question')}</Question>
<Answer>{t('FAQ.item8.answer0')}</Answer>
<Paragraph margin='0'>
<Trans
i18nKey='FAQ.item7.answer1'
i18nKey='FAQ.item8.answer1'
t={t}
components={[
<Anchor
Expand All @@ -168,7 +177,7 @@ function FAQPage() {
</Paragraph>
<Answer>
<Trans
i18nKey='FAQ.item7.answer2'
i18nKey='FAQ.item8.answer2'
t={t}
components={[
<Anchor key='donate-link' href='/get-involved/donate' />
Expand All @@ -177,10 +186,10 @@ function FAQPage() {
</Answer>
</Box>
<Box as='li'>
<Question>{t('FAQ.item8.question')}</Question>
<Question>{t('FAQ.item9.question')}</Question>
<Answer>
<Trans
i18nKey='FAQ.item8.answer'
i18nKey='FAQ.item9.answer'
t={t}
components={[
<Anchor key='resources-page' href='/about/resources' />
Expand All @@ -189,9 +198,9 @@ function FAQPage() {
</Answer>
</Box>
<Box as='li'>
<Question>{t('FAQ.item9.question')}</Question>
<Question>{t('FAQ.item10.question')}</Question>
<Paragraph margin={{ top: 'small', bottom: 'medium' }}>
{t('FAQ.item9.answer')}
{t('FAQ.item10.answer')}
</Paragraph>
</Box>
</StyledList>
Expand Down
14 changes: 9 additions & 5 deletions packages/lib-content/src/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -227,28 +227,32 @@
"question": "Can I download a volunteer Certificate? Can I use Zooniverse to fulfill Service Learning requirements?"
},
"item4": {
"answer": "Classification metadata is stored in our database with UTC timestamps, and the stats service aggregates classification counts into buckets by UTC date ranges. All stats are displayed consistently in UTC date ranges.",
"question": "Why are stats displayed in the UTC timezone?"
},
"item5": {
"answer": "The Zooniverse takes very seriously the task of protecting our volunteer's personal information and classification data. Details about these efforts can be found on the <0>Zooniverse User Agreement and Privacy Policy page</0> and the <1>Zooniverse Security page.</1>",
"question": "What does the Zooniverse do with my account information?"
},
"item5": {
"item6": {
"answer": "You can post your suggestions for new features and report bugs via <0>Zooniverse Talk</0>, through an Issue on the relevant <1>Github repository</1>, or <2>contact us</2>.",
"question": "I have a feature request or found a bug; who should I talk to/how do I report it?"
},
"item6": {
"item7": {
"answer": "The Zooniverse is a collaboration between institutions from the United Kingdom and the United States; all of our team are employed by one or the other of these partner institutions. Check out the <0>Zooniverse jobs page</0> to find out more about employment opportunities within the Zooniverse.",
"question": "Is the Zooniverse hiring?"
},
"item7": {
"item8": {
"answer0": "The Zooniverse is a platform for people-powered research, not an entity, company, or non-profit. We are a multi-institutional collaboration.",
"answer1": "The Adler Planetarium in Chicago, one of the host institutions for the Zooniverse team, is a 501(c)(3). Individuals or organizations that need to link explicitly to a 501(c)(3) for their volunteering efforts use the Adler Planetarium as the reference. Documentation of the Adler Planetarium's 501(c)(3) status is provided <0>here</0>, and the Adler Planetarium EIN number is 36-6210902. When inputting the organization name, please use “Adler Planetarium - Zooniverse” if possible. If not possible, please use “Adler Planetarium” (which matches the EIN number). In all cases, you'll volunteer through Zooniverse.org.",
"answer2": "For information on how to donate, please visit our <0>donation page.</0>",
"question": "Is the Zooniverse a non-profit organization?"
},
"item8": {
"item9": {
"answer": "You can find more details on how to cite the Zooniverse in research publications using data derived from use of the Zooniverse Project Builder on our <0>Resources page</0>.",
"question": "I'm a project owner/research team member, how do I acknowledge the Zooniverse and the Project Builder Platform in my paper, talk abstract, etc.?"
},
"item9": {
"item10": {
"answer": "We support major browsers up to the second to last version.",
"question": "What browser version does Zooniverse support?"
}
Expand Down
25 changes: 22 additions & 3 deletions packages/lib-user/src/components/shared/BarChart/BarChart.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,24 @@ const StyledDataChart = styled(DataChart)`
.hidden-period-label {
display: none;
}
// The only way to get to the x-axis bounding div
&.styled-grommet-barchart > :first-child {
// Align the x-axis visual label to the first date label
div:first-of-type > span {
position: relative;
&::after {
content: 'Date range (UTC)';
position: absolute;
top: calc(100% + 5px);
left: 0;
font-size: 0.75rem;
width: max-content;
}
}
}
`

function BarChart({
Expand All @@ -34,17 +52,17 @@ function BarChart({
type = 'count'
}) {
const size = useContext(ResponsiveContext)

// getDateInterval returns an object with a period property based on the date range, start_date, and end_date
const dateInterval = getDateInterval(dateRange)

// getCompleteData returns an array of objects with a period, count, and session_time property,
// including any periods without stats with a count and session_time of 0
const completeData = getCompleteData({ data, dateInterval })

const dateRangeLabel = getDateRangeLabel(dateInterval)
const typeLabel = TYPE_LABEL[type]

// with no data set gradient as 'brand'
let gradient = 'brand'
// with data set gradient range based on data type (count or session_time) and max value of data type
Expand Down Expand Up @@ -89,6 +107,7 @@ function BarChart({
return (
<StyledDataChart
a11yTitle={`Bar chart of ${typeLabel} by ${dateRangeLabel.countLabel} from ${dateRange.startDate} to ${dateRange.endDate}`}
className='styled-grommet-barchart'
axis={{
x: { granularity: 'fine', property: 'period' },
y: { granularity: 'fine', property: type },
Expand Down

0 comments on commit a49df5f

Please sign in to comment.