Skip to content

Commit

Permalink
feature/localize-date-to-instance-time-zone (#214)
Browse files Browse the repository at this point in the history
* Remove moment
Add timezone

* Format

* Add timezone to meeting card
  • Loading branch information
tohuynh committed May 28, 2022
1 parent c983b9d commit 98ed482
Show file tree
Hide file tree
Showing 17 changed files with 27,663 additions and 146 deletions.
27,573 changes: 27,494 additions & 79 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion package.json
Expand Up @@ -105,7 +105,6 @@
"@mozilla-protocol/core": "^13.0.1",
"firebase": "^9.5.0",
"lodash": "^4.17.21",
"moment": "^2.24.0",
"n-gram": "^2.0.1",
"query-string": "^7.0.1",
"react-highlight-words": "^0.17.0",
Expand Down
2 changes: 2 additions & 0 deletions src/app/AppConfigContext.tsx
Expand Up @@ -13,6 +13,7 @@ export interface AppConfig {
firebaseConfig: FirebaseConfig;
municipality: {
name: string;
timeZone: string;
footerLinksSections: {
footerLinksSectionName: string;
links: {
Expand Down Expand Up @@ -40,6 +41,7 @@ const AppConfigContext = createContext<AppConfig>({
},
municipality: {
name: "Seattle Staging",
timeZone: "America/Los_Angeles",
footerLinksSections: [],
},
});
Expand Down
3 changes: 2 additions & 1 deletion src/components/Cards/MeetingCard/MeetingCard.tsx
Expand Up @@ -58,7 +58,7 @@ const Images = styled.div({

const MeetingCard = ({ event, tags, excerpt, gram, query }: MeetingCardProps) => {
const { language } = useLanguageConfigContext();
const { firebaseConfig } = useAppConfigContext();
const { firebaseConfig, municipality } = useAppConfigContext();

const [staticThumbNailIsLoading, setStaticThumbNailIsLoading] = useState(true);

Expand Down Expand Up @@ -98,6 +98,7 @@ const MeetingCard = ({ event, tags, excerpt, gram, query }: MeetingCardProps) =>
);

const meetingDate = event.event_datetime?.toLocaleDateString(language, {
timeZone: municipality.timeZone,
month: "long",
day: "numeric",
year: "numeric",
Expand Down
7 changes: 5 additions & 2 deletions src/components/Details/Legislation/LegislationOverview.tsx
Expand Up @@ -6,7 +6,7 @@ import Event from "../../../models/Event";
import MatterStatus from "../../../models/MatterStatus";
import Person from "../../../models/Person";

import { useLanguageConfigContext } from "../../../app";
import { useAppConfigContext, useLanguageConfigContext } from "../../../app";

import { DecisionResult } from "../../Shared";
import H2 from "../../Shared/H2";
Expand Down Expand Up @@ -76,13 +76,15 @@ const LegislationOverview: FC<LegislationOverviewProps> = ({
sponsors,
document,
}: LegislationOverviewProps) => {
const { municipality } = useAppConfigContext();
const { language } = useLanguageConfigContext();

return (
<div>
<Title hasBorderBottom={true} className="mzp-u-title-xs">
<span>Legislation Overview</span>
<em>{`Last Updated ${matterStatus.update_datetime.toLocaleDateString(language, {
timeZone: municipality.timeZone,
month: "long",
day: "numeric",
year: "numeric",
Expand All @@ -105,7 +107,8 @@ const LegislationOverview: FC<LegislationOverviewProps> = ({
<dt>Latest Meeting:</dt>
<dd>
<Link to={`/events/${event.id}`}>
{event.event_datetime.toLocaleDateString("en-US", {
{event.event_datetime.toLocaleDateString(language, {
timeZone: municipality.timeZone,
month: "short",
day: "numeric",
year: "numeric",
Expand Down
3 changes: 3 additions & 0 deletions src/components/Details/Legislation/LegislativeHistoryNode.tsx
Expand Up @@ -39,6 +39,8 @@ const LegislativeHistoryNode: FC<LegislativeHistoryNodeProps> = ({
eventMinutesItem,
isLastIndex,
}: LegislativeHistoryNodeProps) => {
const { municipality } = useAppConfigContext();

const isMobile = useMediaQuery({ query: `(max-width: ${screenWidths.tablet})` });
const MARGIN = isMobile ? 4 : 12;

Expand Down Expand Up @@ -70,6 +72,7 @@ const LegislativeHistoryNode: FC<LegislativeHistoryNodeProps> = ({
const { firebaseConfig } = useAppConfigContext();
const { language } = useLanguageConfigContext();
const localizedDateString = eventMinutesItem.event?.event_datetime.toLocaleDateString(language, {
timeZone: municipality.timeZone,
month: "long",
day: "numeric",
year: "numeric",
Expand Down
5 changes: 3 additions & 2 deletions src/components/Filters/SelectDateRange/getDateText.test.ts
@@ -1,7 +1,8 @@
import getDateText from "./getDateText";
import getDateTextFunctionCreator from "./getDateText";

describe("getDateText", () => {
const defaultText = "Date";
const getDateText = getDateTextFunctionCreator("en-US", "America/Los_Angeles");

test("Returns defaultText", () => {
const textRep = getDateText({ start: "", end: "" }, defaultText);
Expand All @@ -20,7 +21,7 @@ describe("getDateText", () => {

test("Returns start and end date with same year and month", () => {
const textRep = getDateText({ start: "2020/01/01", end: "2020/01/02" }, defaultText);
expect(textRep).toEqual("Jan 1 - 2, 2020");
expect(textRep).toEqual("Jan 1 - Jan 2, 2020");
});

test("Returns start and end date with same year only", () => {
Expand Down
63 changes: 32 additions & 31 deletions src/components/Filters/SelectDateRange/getDateText.ts
@@ -1,37 +1,38 @@
import moment from "moment";

import { FilterState } from "../reducer";

/**
* Generate the text representation of a date range.
* @param {Object} dateRange The start and end dates object.
* @param {string} dateRange.start
* @param {string} dateRange.end
* @param {string} defaultText The default text representation, when no dates have been entered.
* @return {string} The text representation.
*/
const getDateText = (dateRange: FilterState<string>, defaultText: string): string => {
const start = moment.utc(dateRange.start, "YYYY-MM-DD");
const end = moment.utc(dateRange.end, "YYYY-MM-DD");
const startString = start.format("MMM D, YYYY");
const endString = end.format("MMM D, YYYY");
let textRep;
if (dateRange.start && dateRange.end) {
if (start.year() === end.year() && start.month() === end.month()) {
textRep = `${startString.split(",")[0]} - ${end.date()}, ${end.year()}`;
} else if (start.year() === end.year()) {
textRep = `${startString.split(",")[0]} - ${endString.split(",")[0]}, ${end.year()}`;
} else {
import getTimeZoneDate from "../../../utils/getTimeZoneName";

const getDateText =
(language: string, timeZone: string) =>
(dateRange: FilterState<string>, defaultText: string): string => {
const timeZoneStartDate = getTimeZoneDate(new Date(dateRange.start), timeZone);
const timeZoneEndDate = getTimeZoneDate(new Date(dateRange.end), timeZone);
const startString = timeZoneStartDate?.toLocaleDateString(language, {
timeZone,
month: "short",
day: "numeric",
year:
timeZoneStartDate.getUTCFullYear() === timeZoneEndDate?.getUTCFullYear()
? undefined
: "numeric",
});
const endString = timeZoneEndDate?.toLocaleDateString(language, {
timeZone,
month: "short",
day: "numeric",
year: "numeric",
});
let textRep;
if (timeZoneStartDate && timeZoneEndDate) {
textRep = `${startString} - ${endString}`;
} else if (timeZoneStartDate) {
textRep = `${startString} -`;
} else if (timeZoneEndDate) {
textRep = `- ${endString}`;
} else {
textRep = defaultText;
}
} else if (dateRange.start) {
textRep = `${startString} -`;
} else if (dateRange.end) {
textRep = `- ${endString}`;
} else {
textRep = defaultText;
}
return textRep;
};
return textRep;
};

export default getDateText;
4 changes: 3 additions & 1 deletion src/components/Tables/VotingTableRow/VotingTableRow.tsx
Expand Up @@ -6,7 +6,7 @@ import { useMediaQuery } from "react-responsive";
import { screenWidths } from "../../../styles/mediaBreakpoints";
import { ReactiveTableRow } from "../ReactiveTableRow";
import { Link } from "react-router-dom";
import { useLanguageConfigContext } from "../../../app";
import { useAppConfigContext, useLanguageConfigContext } from "../../../app";

export type VotingTableRowProps = {
/** the name of the matter that was voted on */
Expand Down Expand Up @@ -46,11 +46,13 @@ const VotingTableRow = ({
columnNames,
columnDistribution,
}: VotingTableRowProps) => {
const { municipality } = useAppConfigContext();
const { language } = useLanguageConfigContext();

const legislationTagsString =
legislationTags && legislationTags.length > 0 ? legislationTags.join(TAG_CONNECTOR) : "";
const dateText = meetingDate?.toLocaleDateString(language, {
timeZone: municipality.timeZone,
month: "long",
day: "numeric",
year: "numeric",
Expand Down
18 changes: 11 additions & 7 deletions src/containers/EventContainer/EventContainer.tsx
@@ -1,7 +1,7 @@
import React, { createRef, FC, useState, useRef, useEffect, useMemo, useCallback } from "react";
import styled from "@emotion/styled";

import { useLanguageConfigContext } from "../../app";
import { useAppConfigContext, useLanguageConfigContext } from "../../app";
import useDocumentTitle from "../../hooks/useDocumentTitle";

import { EventVideoRef } from "../../components/Details/EventVideo/EventVideo";
Expand All @@ -26,7 +26,7 @@ const Container = styled.div({
});

const EventName = styled.div({
"& > h2": {
"& > h1": {
// Remove mozilla protocol margin on h2
margin: 0,
},
Expand Down Expand Up @@ -71,15 +71,14 @@ const EventContainer: FC<EventContainerProps> = ({
initialSeconds,
searchQuery,
}: EventContainerProps) => {
const { municipality } = useAppConfigContext();
const { language } = useLanguageConfigContext();

useDocumentTitle(
`${event.body?.name}` +
`${event.body?.name && event.event_datetime && " -- "}` +
`${event.event_datetime?.toLocaleDateString(language, {
month: "numeric",
day: "numeric",
year: "numeric",
timeZone: municipality.timeZone,
})}`
);

Expand Down Expand Up @@ -135,12 +134,17 @@ const EventContainer: FC<EventContainerProps> = ({
return (
<Container>
<EventName>
<h2 className="mzp-u-title-xs">{event.body?.name}</h2>
<h1 className="mzp-u-title-sm">{event.body?.name}</h1>
<p className="mzp-c-card-desc">
{event.event_datetime?.toLocaleDateString(language, {
{event.event_datetime?.toLocaleString(language, {
timeZone: municipality.timeZone,
timeZoneName: "short",
month: "long",
day: "numeric",
year: "numeric",
hour: "numeric",
minute: "numeric",
second: "numeric",
})}
</p>
</EventName>
Expand Down
20 changes: 14 additions & 6 deletions src/containers/EventsContainer/EventsContainer.tsx
Expand Up @@ -3,7 +3,7 @@ import { useMediaQuery } from "react-responsive";
import { useHistory } from "react-router-dom";
import { Loader } from "semantic-ui-react";

import { useAppConfigContext } from "../../app";
import { useAppConfigContext, useLanguageConfigContext } from "../../app";
import useFetchModels, {
FetchModelsActionType,
FetchModelsState,
Expand Down Expand Up @@ -33,6 +33,7 @@ import { SEARCH_TYPE } from "../../pages/SearchPage/types";
import { strings } from "../../assets/LocalizedStrings";
import { FETCH_CARDS_BATCH_SIZE } from "../../constants/ProjectConstants";
import { screenWidths } from "../../styles/mediaBreakpoints";
import getTimeZoneDate from "../../utils/getTimeZoneName";

interface EventsContainerProps extends EventsData {
initialSelectedBodies: Record<string, boolean>;
Expand All @@ -42,13 +43,14 @@ const EventsContainer: FC<EventsContainerProps> = ({
bodies,
initialSelectedBodies,
}: EventsContainerProps) => {
const { firebaseConfig } = useAppConfigContext();
const { firebaseConfig, municipality } = useAppConfigContext();
const { language } = useLanguageConfigContext();

const dateRangeFilter = useFilter<string>({
name: strings.date,
initialState: { start: "", end: "" },
defaultDataValue: "",
textRepFunction: getDateText,
textRepFunction: getDateText(language, municipality.timeZone),
});
const committeeFilter = useFilter<boolean>({
name: strings.committee,
Expand Down Expand Up @@ -82,8 +84,8 @@ const EventsContainer: FC<EventsContainerProps> = ({
state.batchSize,
getSelectedOptions(committeeFilter.state),
{
start: dateRangeFilter.state.start ? new Date(dateRangeFilter.state.start) : undefined,
end: dateRangeFilter.state.end ? new Date(dateRangeFilter.state.end) : undefined,
start: getTimeZoneDate(new Date(dateRangeFilter.state.start), municipality.timeZone),
end: getTimeZoneDate(new Date(dateRangeFilter.state.end), municipality.timeZone),
},
{
by: sortFilter.state.by,
Expand All @@ -98,7 +100,13 @@ const EventsContainer: FC<EventsContainerProps> = ({
);
return Promise.resolve(renderableEvents);
},
[firebaseConfig, committeeFilter.state, dateRangeFilter.state, sortFilter.state]
[
firebaseConfig,
committeeFilter.state,
dateRangeFilter.state,
sortFilter.state,
municipality.timeZone,
]
);

const isDesktop = useMediaQuery({ query: `(min-width: ${screenWidths.desktop})` });
Expand Down
13 changes: 10 additions & 3 deletions src/containers/PersonContainer/PersonRoles.tsx
Expand Up @@ -4,7 +4,7 @@ import { Link } from "react-router-dom";
import Role from "../../models/Role";
import { getUniqueTermRoles, partitionNonTermRoles } from "../../models/util/RoleUtilities";

import { useLanguageConfigContext } from "../../app";
import { useAppConfigContext, useLanguageConfigContext } from "../../app";

import Details from "../../components/Shared/Details";
import H2 from "../../components/Shared/H2";
Expand Down Expand Up @@ -62,6 +62,7 @@ interface PersonRolesProps {
}

const PersonRoles: FC<PersonRolesProps> = ({ councilMemberRoles, allRoles }: PersonRolesProps) => {
const { municipality } = useAppConfigContext();
const { language } = useLanguageConfigContext();

const [termRoles, partitionedNonTermRoles, nonTermRoles] = useMemo(() => {
Expand Down Expand Up @@ -106,8 +107,14 @@ const PersonRoles: FC<PersonRolesProps> = ({ councilMemberRoles, allRoles }: Per
<strong>{`${strings[role.title.toLowerCase().replace(" ", "_")]}: `}</strong>{" "}
{`${role.seat?.name} // ${
role.seat?.electoral_area
} (${role.start_datetime.toLocaleDateString(language)} - ${
role.end_datetime ? role.end_datetime.toLocaleDateString(language) : ""
} (${role.start_datetime.toLocaleDateString(language, {
timeZone: municipality.timeZone,
})} - ${
role.end_datetime
? role.end_datetime.toLocaleDateString(language, {
timeZone: municipality.timeZone,
})
: ""
})`}
</span>
}
Expand Down

0 comments on commit 98ed482

Please sign in to comment.