= ({
-
-
Latest Meeting:
-
-
- {event.event_datetime.toLocaleDateString(language, {
- timeZone: municipality.timeZone,
- month: "short",
- day: "numeric",
- year: "numeric",
- })}
-
-
-
-
+ {event && (
+
+
Latest Meeting:
+
+
+ {event.event_datetime.toLocaleDateString(language, {
+ timeZone: municipality.timeZone,
+ month: "short",
+ day: "numeric",
+ year: "numeric",
+ })}
+
+
+
+ )}
+ {document && (
+
+ )}
Sponsored by:
diff --git a/src/components/Details/MinutesItemsList/MinutesItemsList.tsx b/src/components/Details/MinutesItemsList/MinutesItemsList.tsx
index 4656cff8..0b35333c 100644
--- a/src/components/Details/MinutesItemsList/MinutesItemsList.tsx
+++ b/src/components/Details/MinutesItemsList/MinutesItemsList.tsx
@@ -1,11 +1,12 @@
import React, { FC } from "react";
import styled from "@emotion/styled";
-/* import { Link } from "react-router-dom"; */
+import { Link } from "react-router-dom";
import DocumentsList from "./DocumentsList";
-/* import ChevronDownIcon from "../../Shared/ChevronDownIcon"; */
+import ChevronDownIcon from "../../Shared/ChevronDownIcon";
import { Item } from "./types";
+import { strings } from "../../../assets/LocalizedStrings";
const ListItem = styled.li({
"& > div:first-of-type": {
@@ -37,11 +38,11 @@ const MinutesItemsList: FC = ({ minutesItems }: MinutesIt
return (
{elem.name}
- {/* {elem.matter_ref && (
+ {elem.matter_ref && (
- {"Go to Full Legislation Details"}
+ {strings.go_to_matter_details}
- )} */}
+ )}
{elem.description && {elem.description}
}
diff --git a/src/components/Tables/MeetingVotesTableRow/MeetingVotesTableRow.tsx b/src/components/Tables/MeetingVotesTableRow/MeetingVotesTableRow.tsx
index 6d958ed4..df43c0b0 100644
--- a/src/components/Tables/MeetingVotesTableRow/MeetingVotesTableRow.tsx
+++ b/src/components/Tables/MeetingVotesTableRow/MeetingVotesTableRow.tsx
@@ -98,7 +98,7 @@ function VoteCell(isExpanded: boolean, votes: IndividualMeetingVote[], isMobile:
const MeetingVotesTableRow = ({
index,
- /* legislationLink, */
+ legislationLink,
legislationName,
legislationDescription,
councilDecision,
@@ -120,10 +120,11 @@ const MeetingVotesTableRow = ({
}}
>
- {/*
{legislationName} */}
-
- {legislationName}
-
+
+
+ {legislationName}
+
+
{!isMobile &&
{legislationDescription}
}
diff --git a/src/components/Tables/VotingTableRow/VotingTableRow.tsx b/src/components/Tables/VotingTableRow/VotingTableRow.tsx
index 03e65da8..960041de 100644
--- a/src/components/Tables/VotingTableRow/VotingTableRow.tsx
+++ b/src/components/Tables/VotingTableRow/VotingTableRow.tsx
@@ -35,7 +35,7 @@ export type VotingTableRowProps = {
const VotingTableRow = ({
index,
- /* legislationLink, */
+ legislationLink,
legislationName,
legislationTags,
voteDecision,
@@ -67,10 +67,11 @@ const VotingTableRow = ({
columnDistribution={columnDistribution}
>
- {/* {legislationName} */}
-
- {legislationName}
-
+
+
+ {legislationName}
+
+
{!isMobile && {legislationTagsString}
}
diff --git a/src/containers/MatterContainer/MatterContainer.tsx b/src/containers/MatterContainer/MatterContainer.tsx
new file mode 100644
index 00000000..98d2805b
--- /dev/null
+++ b/src/containers/MatterContainer/MatterContainer.tsx
@@ -0,0 +1,51 @@
+import React from "react";
+import styled from "@emotion/styled";
+
+import MatterStatus from "../../models/MatterStatus";
+import Event from "../../models/Event";
+import Person from "../../models/Person";
+import Vote from "../../models/Vote";
+import IndexedMatterGram from "../../models/IndexedMatterGram";
+import EventMinutesItem from "../../models/EventMinutesItem";
+
+import LegislationIntroduction from "../../components/Details/Legislation/LegislationIntroduction";
+import LegislationOverview from "../../components/Details/Legislation/LegislationOverview";
+import { LegislationLatestVote } from "../../components/Details/Legislation/LegislationLatestVote";
+import { LegislationHistory } from "../../components/Details/Legislation/LegislationHistory";
+
+const Matter = styled.div({
+ display: "grid",
+ gridTemplateColumns: "1fr",
+ rowGap: 64,
+});
+interface MatterContainerProps {
+ matterStatus: MatterStatus;
+ indexedMatterGrams: IndexedMatterGram[];
+ event?: Event;
+ sponsors: Person[];
+ votes?: Vote[];
+ legislationHistory?: EventMinutesItem[];
+}
+
+const MatterContainer = ({
+ matterStatus,
+ indexedMatterGrams,
+ event,
+ sponsors,
+ votes,
+ legislationHistory,
+}: MatterContainerProps) => {
+ return (
+
+
+
+ {votes && }
+ {legislationHistory && }
+
+ );
+};
+
+export default MatterContainer;
diff --git a/src/containers/MatterContainer/index.ts b/src/containers/MatterContainer/index.ts
new file mode 100644
index 00000000..caafa980
--- /dev/null
+++ b/src/containers/MatterContainer/index.ts
@@ -0,0 +1 @@
+export { default as MatterContainer } from "./MatterContainer";
diff --git a/src/containers/PersonContainer/MattersSponsored.tsx b/src/containers/PersonContainer/MattersSponsored.tsx
index fed08260..8562598a 100644
--- a/src/containers/PersonContainer/MattersSponsored.tsx
+++ b/src/containers/PersonContainer/MattersSponsored.tsx
@@ -1,5 +1,6 @@
import React, { FC, useMemo, useCallback } from "react";
import { Loader } from "semantic-ui-react";
+import { Link } from "react-router-dom";
import { useAppConfigContext } from "../../app";
import useFetchModels, {
@@ -74,7 +75,12 @@ const MattersSponsored: FC = ({ personId }: MattersSponso
-
- {matterSponsored.matter?.name}
+
+ {matterSponsored.matter?.name}
+
- {matterSponsored.matter?.title}
diff --git a/src/networking/MatterSponsorService.ts b/src/networking/MatterSponsorService.ts
index a9383eca..9803fd03 100644
--- a/src/networking/MatterSponsorService.ts
+++ b/src/networking/MatterSponsorService.ts
@@ -27,6 +27,29 @@ export default class MatterSponsorService extends ModelService {
super(COLLECTION_NAME.MatterSponsor, firebaseConfig);
}
+ async getMatterSponsorByMatterId(matterId: string): Promise {
+ const populatePerson = new Populate(
+ COLLECTION_NAME.MatterSponsor,
+ REF_PROPERTY_NAME.MatterSponsorPersonRef
+ );
+ const networkQueryResponse = this.networkService.getDocuments(
+ COLLECTION_NAME.MatterSponsor,
+ [
+ where(
+ REF_PROPERTY_NAME.MatterSponsorMatterRef,
+ WHERE_OPERATOR.eq,
+ doc(NetworkService.getDb(), COLLECTION_NAME.Matter, matterId)
+ ),
+ ],
+ new PopulationOptions([populatePerson])
+ );
+ return this.createModels(
+ networkQueryResponse,
+ MatterSponsor,
+ `getMatterSponsorByMatterId(${matterId})`
+ ) as Promise;
+ }
+
/**
*
* @param personId The person's id
diff --git a/src/networking/MatterStatusService.ts b/src/networking/MatterStatusService.ts
new file mode 100644
index 00000000..264b8ee7
--- /dev/null
+++ b/src/networking/MatterStatusService.ts
@@ -0,0 +1,44 @@
+import ModelService from "./ModelService";
+import { where, orderBy, doc } from "@firebase/firestore";
+import {
+ COLLECTION_NAME,
+ Populate,
+ PopulationOptions,
+ REF_PROPERTY_NAME,
+} from "./PopulationOptions";
+import { ORDER_DIRECTION, WHERE_OPERATOR } from "./constants";
+import { NetworkService } from "./NetworkService";
+
+import MatterStatus from "../models/MatterStatus";
+import { FirebaseConfig } from "../app/AppConfigContext";
+
+export default class MatterStatusService extends ModelService {
+ constructor(firebaseConfig: FirebaseConfig) {
+ super(COLLECTION_NAME.MatterStatus, firebaseConfig);
+ }
+
+ async getMatterStatusesByMatterId(matterId: string): Promise {
+ const populateEventMinutesItems = new Populate(
+ COLLECTION_NAME.MatterStatus,
+ REF_PROPERTY_NAME.MatterStatusEventMinutesItemRef
+ );
+
+ const networkQueryResponse = this.networkService.getDocuments(
+ COLLECTION_NAME.MatterStatus,
+ [
+ where(
+ REF_PROPERTY_NAME.MatterStatusMatterRef,
+ WHERE_OPERATOR.eq,
+ doc(NetworkService.getDb(), COLLECTION_NAME.Matter, matterId)
+ ),
+ orderBy("update_datetime", ORDER_DIRECTION.desc),
+ ],
+ new PopulationOptions([populateEventMinutesItems])
+ );
+ return this.createModels(
+ networkQueryResponse,
+ MatterStatus,
+ `getMatterStatusByMatterId(${matterId})`
+ ) as Promise;
+ }
+}
diff --git a/src/pages/MatterPage/MatterPage.tsx b/src/pages/MatterPage/MatterPage.tsx
new file mode 100644
index 00000000..eabb669c
--- /dev/null
+++ b/src/pages/MatterPage/MatterPage.tsx
@@ -0,0 +1,111 @@
+import React, { FC, useCallback } from "react";
+import { useParams } from "react-router-dom";
+import { useAppConfigContext } from "../../app";
+import useFetchData from "../../containers/FetchDataContainer/useFetchData";
+import FetchDataContainer from "../../containers/FetchDataContainer/FetchDataContainer";
+import { MatterContainer } from "../../containers/MatterContainer";
+
+import MatterStatus from "../../models/MatterStatus";
+import IndexedMatterGram from "../../models/IndexedMatterGram";
+import EventMinutesItem from "../../models/EventMinutesItem";
+import Event from "../../models/Event";
+import Person from "../../models/Person";
+import Vote from "../../models/Vote";
+
+import MatterStatusService from "../../networking/MatterStatusService";
+import EventService from "../../networking/EventService";
+import MatterSponsorService from "../../networking/MatterSponsorService";
+import VoteService from "../../networking/VoteService";
+
+interface MatterContainerType {
+ matterStatus: MatterStatus;
+ indexedMatterGrams: IndexedMatterGram[];
+ event?: Event;
+ sponsors: Person[];
+ votes?: Vote[];
+ legislationHistory: EventMinutesItem[];
+}
+
+const MatterPage: FC = () => {
+ // Get the app config context
+ const { firebaseConfig } = useAppConfigContext();
+ // Get the id the matter, provided the route is `matter/:id`
+ const { id } = useParams<{ id: string }>();
+
+ const fetchMatterDetails = useCallback(async () => {
+ const matterStatusService = new MatterStatusService(firebaseConfig);
+ const matterSponsorService = new MatterSponsorService(firebaseConfig);
+ const eventService = new EventService(firebaseConfig);
+
+ const matterSponsorPromises = matterSponsorService.getMatterSponsorByMatterId(id);
+ const matterStatusPromises = matterStatusService.getMatterStatusesByMatterId(id);
+ const responses = await Promise.all([matterSponsorPromises, matterStatusPromises]);
+ const [matterSponsors, matterStatuses] = responses; // javascript array destructuring shorthand
+ const sponsors = matterSponsors
+ .filter((matterSponsor) => {
+ return matterSponsor.person;
+ })
+ .map((matterSponsor) => {
+ return matterSponsor.person as Person;
+ });
+ const legislationHistory = matterStatuses.reduce((filtered, optional) => {
+ if (optional.event_minutes_item) {
+ filtered.push(optional.event_minutes_item);
+ }
+ return filtered;
+ }, [] as EventMinutesItem[]);
+
+ const latestStatus = matterStatuses[0];
+ const matterContainerData: MatterContainerType = {
+ matterStatus: latestStatus,
+ indexedMatterGrams: [],
+ sponsors,
+ legislationHistory,
+ };
+
+ // loop through matterStatuses until we find one where the event_minutes_item is not null
+ let latestEventMinutesItem: EventMinutesItem | undefined;
+ for (const matterStatus of matterStatuses) {
+ if (matterStatus.event_minutes_item) {
+ latestEventMinutesItem = matterStatus.event_minutes_item;
+ break;
+ }
+ }
+ if (latestEventMinutesItem) {
+ const votesService = new VoteService(firebaseConfig);
+ const eventResponses = await Promise.all([
+ votesService.getVotesByEventMinutesItemId(latestEventMinutesItem.id),
+ eventService.getEventById(latestEventMinutesItem.event_ref),
+ ]);
+ matterContainerData.votes = eventResponses[0];
+ matterContainerData.event = eventResponses[1];
+ }
+ return matterContainerData;
+ }, [firebaseConfig, id]);
+
+ const { state: matterDetailsState } = useFetchData(
+ {
+ isLoading: false,
+ error: null,
+ hasFetchRequest: true,
+ },
+ fetchMatterDetails
+ );
+
+ return (
+
+ {matterDetailsState.data && (
+
+ )}
+
+ );
+};
+
+export default MatterPage;
diff --git a/src/pages/MatterPage/index.ts b/src/pages/MatterPage/index.ts
new file mode 100644
index 00000000..8467f3f8
--- /dev/null
+++ b/src/pages/MatterPage/index.ts
@@ -0,0 +1 @@
+export { default as MatterPage } from "./MatterPage";