Skip to content

Commit

Permalink
Merge pull request #42 from dapetcu21/fixes-0.1.2
Browse files Browse the repository at this point in the history
fixes-0.1.2
  • Loading branch information
RaduCStefanescu authored Sep 21, 2020
2 parents 7b80db2 + 0fb3c17 commit 7eaed1d
Show file tree
Hide file tree
Showing 31 changed files with 151 additions and 109 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@code4ro/reusable-components",
"version": "0.1.1",
"version": "0.1.2",
"description": "Component library for code4ro",
"keywords": [
"code4ro",
Expand Down
2 changes: 1 addition & 1 deletion src/components/BarChart/BarChart.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { ComponentType, ReactNode } from "react";
import { themable, ThemableComponentProps } from "../../util/theme";
import { themable, ThemableComponentProps } from "../../hooks/theme";

type Props = {
width: number;
Expand Down
2 changes: 1 addition & 1 deletion src/components/Button/Button.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { ComponentProps, forwardRef } from "react";
import { themable, ThemedComponent, ThemedComponentProps } from "../../util/theme";
import { themable, ThemedComponent, ThemedComponentProps } from "../../hooks/theme";
import cssClasses from "./Button.module.scss";

export const Button = themable<ComponentProps<"button">>(
Expand Down
2 changes: 1 addition & 1 deletion src/components/ColoredSquare/ColoredSquare.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from "react";
import { themable } from "../../util/theme";
import { themable } from "../../hooks/theme";
import cssClasses from "./ColoredSquare.module.scss";

type Props = {
Expand Down
2 changes: 1 addition & 1 deletion src/components/ElectionMap/ElectionMap.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { PropsWithChildren, useMemo } from "react";
import { ElectionScopeIncomplete } from "../../types/Election";
import { themable } from "../../util/theme";
import { themable } from "../../hooks/theme";
import cssClasses from "./ElectionMap.module.scss";
import RomaniaMap from "../../assets/romania-map.svg";
import WorldMap from "../../assets/world-map.svg";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { PropsWithChildren, ReactNode } from "react";
import { ElectionObservation } from "../../types/Election";
import { formatGroupedNumber } from "../../util/format";
import { ClassNames, themable, useTheme } from "../../util/theme";
import { ClassNames, themable, useTheme } from "../../hooks/theme";
import { DivBodyLarge, Heading2 } from "../Typography/Typography";
import cssClasses from "./ElectionObservationSection.module.scss";
import BallotDrop from "../../assets/ballot-drop.svg";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { PropsWithChildren, ReactNode } from "react";
import { ElectionResults } from "../../types/Election";
import { formatGroupedNumber } from "../../util/format";
import { ClassNames, themable } from "../../util/theme";
import { ClassNames, themable } from "../../hooks/theme";
import { DivBodyHuge, Heading2 } from "../Typography/Typography";
import cssClasses from "./ElectionResultsProcess.module.scss";
import BallotFillIn from "../../assets/ballot-fill-in.svg";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { memo, useCallback, useMemo, useState } from "react";
import { ElectionResults } from "../../types/Election";
import { electionCandidateColor, formatGroupedNumber } from "../../util/format";
import { ClassNames, mergeClasses, themable } from "../../util/theme";
import { ClassNames, mergeClasses, themable } from "../../hooks/theme";
import { ColoredSquare } from "../ColoredSquare/ColoredSquare";
import { DivBody, DivLabel } from "../Typography/Typography";
import useDimensions from "react-use-dimensions";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { useMemo } from "react";
import { ElectionResults } from "../../types/Election";
import { themable } from "../../util/theme";
import { themable } from "../../hooks/theme";
import { HorizontalStackedBar, HorizontalStackedBarItem } from "../HorizontalStackedBar/HorizontalStackedBar";
import { PartyResultCard } from "../PartyResultCard/PartyResultCard";
import { PartyResultInline } from "../PartyResultInline/PartyResultInline";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import {
electionScopeIsComplete,
electionTypeInvolvesDiaspora,
} from "../../types/Election";
import { themable } from "../../util/theme";
import { themable } from "../../hooks/theme";
import useDimensions from "react-use-dimensions";
import cssClasses from "./ElectionResultsSummarySection.module.scss";
import { ElectionResultsStackedBar } from "../ElectionResultsStackedBar/ElectionResultsStackedBar";
Expand All @@ -17,7 +17,7 @@ import { ElectionScopeIncompleteWarning } from "../Warning/ElectionScopeIncomple
import { ElectionResultsSummaryTable } from "../ElectionResultsSummaryTable/ElectionResultsSummaryTable";

type Props = {
meta: ElectionBallotMeta;
meta?: ElectionBallotMeta;
scope: ElectionScopeIncompleteResolved;
results?: ElectionResults | null;
separator?: ReactNode;
Expand All @@ -33,7 +33,7 @@ export const ElectionResultsSummarySection = themable<Props>(
cssClasses,
defaultConstants,
)(({ classes, results, meta, scope, constants, separator }) => {
const involvesDiaspora = electionTypeInvolvesDiaspora(meta.type);
const involvesDiaspora = !!meta && electionTypeInvolvesDiaspora(meta.type);

const [measureRef, { width }] = useDimensions();

Expand Down Expand Up @@ -74,7 +74,7 @@ export const ElectionResultsSummarySection = themable<Props>(
{results && !mobileMap && separator}
{!mobileMap && (
<div className={classes.mapSummaryContainer}>
{!fullWidthMap && results && (
{!fullWidthMap && meta && results && (
<ElectionResultsSummaryTable className={classes.mapSummaryTable} meta={meta} results={results} />
)}
{map}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import { electionHasSeats, ElectionBallotMeta, ElectionResults } from "../../types/Election";
import { themable } from "../../util/theme";
import { themable } from "../../hooks/theme";
import cssClasses from "./ElectionResultsSummaryTable.module.scss";
import { DivBody, Heading3, makeTypographyComponent } from "../Typography/Typography";
import { lightFormat, parseISO } from "date-fns";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ResultsTable } from "../ResultsTable/ResultsTable";
import { Heading2 } from "../Typography/Typography";
import { electionHasSeats, ElectionBallotMeta, ElectionResults, ElectionResultsCandidate } from "../../types/Election";
import { formatGroupedNumber, formatPercentage, fractionOf } from "../../util/format";
import { ClassNames, themable } from "../../util/theme";
import { ClassNames, themable } from "../../hooks/theme";
import cssClasses from "./ElectionResultsTableSection.module.scss";
import { Button } from "../Button/Button";

Expand Down
5 changes: 3 additions & 2 deletions src/components/ElectionScopePicker/ElectionScopePicker.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import React, { useCallback, useMemo } from "react";
import Select from "react-select";
import { ElectionScope, ElectionScopeIncomplete } from "../../types/Election";
import { APIRequestState, useApiResponse } from "../../util/api";
import { APIRequestState } from "../../util/api";
import { ElectionScopeAPI, OptionWithID } from "../../util/electionApi";
import { themable, useTheme } from "../../util/theme";
import { themable, useTheme } from "../../hooks/theme";
import { Label } from "../Typography/Typography";
import cssClasses from "./ElectionScopePicker.module.scss";
import { useApiResponse } from "../../hooks/useApiResponse";

type Props = {
apiData: ElectionScopePickerAPIData;
Expand Down
2 changes: 1 addition & 1 deletion src/components/ElectionTimeline/ElectionTimeline.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { parseISO } from "date-fns";
import React, { useEffect, useMemo, useState } from "react";
import { ElectionBallotMeta } from "../../types/Election";
import { mergeClasses, themable } from "../../util/theme";
import { mergeClasses, themable } from "../../hooks/theme";
import cssClasses from "./ElectionTimeline.module.scss";

type Props = {
Expand Down
2 changes: 1 addition & 1 deletion src/components/ElectionTurnoutBars/ElectionTurnoutBars.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import { formatGroupedNumber, formatPercentage } from "../../util/format";
import { themable, useTheme } from "../../util/theme";
import { themable, useTheme } from "../../hooks/theme";
import { PercentageBars } from "../PercentageBars/PercentageBars";
import { PercentageBarsLegend } from "../PercentageBarsLegend/PercentageBarsLegend";

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from "react";
import { ElectionScope, ElectionTurnoutBreakdown } from "../../types/Election";
import { formatGroupedNumber, formatPercentage } from "../../util/format";
import { themable } from "../../util/theme";
import { themable } from "../../hooks/theme";
import { BarChart } from "../BarChart/BarChart";
import { PercentageBarsLegend } from "../PercentageBarsLegend/PercentageBarsLegend";
import cssClasses from "./ElectionTurnoutBreakdownChart.module.scss";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
electionTypeInvolvesDiaspora,
} from "../../types/Election";
import { formatGroupedNumber, formatPercentage, getScopeName } from "../../util/format";
import { mergeClasses, themable } from "../../util/theme";
import { mergeClasses, themable } from "../../hooks/theme";
import { ElectionMap } from "../ElectionMap/ElectionMap";
import { ElectionTurnoutBars } from "../ElectionTurnoutBars/ElectionTurnoutBars";
import { ElectionTurnoutBreakdownChart } from "../ElectionTurnoutBreakdownChart/ElectionTurnoutBreakdownChart";
Expand All @@ -18,7 +18,7 @@ import BallotCheckmark from "../../assets/ballot-checkmark.svg";
import { ElectionScopeIncompleteWarning } from "../Warning/ElectionScopeIncompleteWarning";

type Props = {
meta: ElectionBallotMeta;
meta?: ElectionBallotMeta;
scope: ElectionScopeIncompleteResolved;
turnout?: ElectionTurnout | null;
};
Expand All @@ -34,7 +34,7 @@ export const ElectionTurnoutSection = themable<Props>(
cssClasses,
defaultConstants,
)(({ meta, scope, turnout, classes, constants }) => {
const involvesDiaspora = electionTypeInvolvesDiaspora(meta.type);
const involvesDiaspora = !!meta && electionTypeInvolvesDiaspora(meta.type);

const [measureRef, { width }] = useDimensions();

Expand Down
2 changes: 1 addition & 1 deletion src/components/HereMap/HereMap.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { createContext, useContext, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
import { themable } from "../../util/theme";
import { themable } from "../../hooks/theme";
import cssClasses from "./HereMap.module.scss";

type OnFeatureSelect = (featureId: number) => unknown;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { ReactNode } from "react";
import cssClasses from "./HorizontalStackedBar.module.scss";
import { themable } from "../../util/theme";
import { themable } from "../../hooks/theme";
import { DivBody } from "../Typography/Typography";

export type HorizontalStackedBarItem = {
Expand Down
2 changes: 1 addition & 1 deletion src/components/PartyResultCard/PartyResultCard.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import cssClasses from "./PartyResultCard.module.scss";
import { mergeClasses, themable } from "../../util/theme";
import { mergeClasses, themable } from "../../hooks/theme";
import { formatPercentage } from "../../util/format";
import { DivBodyMedium, DivHeading1 } from "../Typography/Typography";
import { ColoredSquare } from "../ColoredSquare/ColoredSquare";
Expand Down
2 changes: 1 addition & 1 deletion src/components/PartyResultInline/PartyResultInline.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import { formatGroupedNumber, formatPercentage } from "../../util/format";
import { themable } from "../../util/theme";
import { themable } from "../../hooks/theme";
import { ColoredSquare } from "../ColoredSquare/ColoredSquare";
import { DivBody, Label } from "../Typography/Typography";
import cssClasses from "./PartyResultInline.module.scss";
Expand Down
2 changes: 1 addition & 1 deletion src/components/PercentageBars/PercentageBars.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { ReactNode } from "react";
import cssClasses from "./PercentageBars.module.scss";
import { mergeClasses, themable } from "../../util/theme";
import { mergeClasses, themable } from "../../hooks/theme";

type Props = {
total?: number; // Defaults to the max value in items
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { ReactNode } from "react";
import cssClasses from "./PercentageBarsLegend.module.scss";
import { mergeClasses, themable } from "../../util/theme";
import { mergeClasses, themable } from "../../hooks/theme";
import { DivBody } from "../Typography/Typography";

type Props = {
Expand Down
2 changes: 1 addition & 1 deletion src/components/ResultsTable/ResultsTable.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { ComponentProps, forwardRef } from "react";
import { themable, ThemedComponent, ThemedComponentProps } from "../../util/theme";
import { themable, ThemedComponent, ThemedComponentProps } from "../../hooks/theme";
import cssClasses from "./ResultsTable.module.scss";

export const ResultsTable = themable<ComponentProps<"table">>(
Expand Down
2 changes: 1 addition & 1 deletion src/components/Typography/Typography.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { ComponentProps, ComponentType, forwardRef } from "react";
import { mergeClasses, PropsObject, themable, ThemableComponent, ThemedComponentProps } from "../../util/theme";
import { mergeClasses, PropsObject, themable, ThemableComponent, ThemedComponentProps } from "../../hooks/theme";
import cssClasses from "./Typography.module.scss";

export function makeTypographyComponent<Props extends PropsObject>(
Expand Down
36 changes: 36 additions & 0 deletions src/hooks/electionApiHooks.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { useEffect, useState } from "react";
import { ElectionBallot, ElectionScope } from "../types/Election";
import { APIRequestState } from "../util/api";
import { ElectionAPI } from "../util/electionApi";
import { useApiResponse } from "./useApiResponse";

export const useBallotData = (
api: ElectionAPI,
ballotId: number | null,
scope: ElectionScope | null,
autoRefreshInterval: number = 60 * 1000,
): APIRequestState<ElectionBallot> => {
const [timerToken, setTimerToken] = useState<boolean>(false);

const state = useApiResponse(() => (ballotId != null && scope ? api.getBallot(ballotId, scope) : null), [
scope,
ballotId,
timerToken,
]);

// Changing the timerToken will re-trigger useApiResponse
useEffect(() => {
if (state.loading || !state.data?.meta.live) {
return undefined;
}

const timerId = setTimeout(() => {
setTimerToken((x) => !x);
}, autoRefreshInterval);

return () => {
clearTimeout(timerId);
};
}, [state.data, state.loading, timerToken, autoRefreshInterval]);
return state;
};
File renamed without changes.
76 changes: 76 additions & 0 deletions src/hooks/useApiResponse.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { useEffect, useState } from "react";
import { APIInvocation, APIRequestState } from "../util/api";

export type UseAPIResponseOptions<ResponseType> = {
invocation?: APIInvocation<ResponseType> | null;
discardPreviousData?: boolean; // Defaults to false
discardDataOnError?: boolean; // Defaults to false
abortPreviousRequest?: boolean; // Defaults to true
};

export function useApiResponse<ResponseType>(
makeInvocation: () => APIInvocation<ResponseType> | UseAPIResponseOptions<ResponseType> | undefined | void | null,
dependencies: unknown[],
): APIRequestState<ResponseType> {
const [state, setState] = useState<APIRequestState<ResponseType>>({
data: null,
hasData: false,
loading: false,
error: null,
});

useEffect(() => {
const inv = makeInvocation();
const options: UseAPIResponseOptions<ResponseType> = (typeof inv === "function" ? { invocation: inv } : inv) || {};
const {
invocation,
discardPreviousData = false,
discardDataOnError = false,
abortPreviousRequest = true,
} = options;

if (!invocation && !discardPreviousData) return;

setState((prevState) => ({
data: discardPreviousData ? null : prevState.data,
hasData: discardPreviousData ? false : prevState.hasData,
loading: invocation != null,
error: invocation != null || discardPreviousData ? null : prevState.error,
}));

if (!invocation) return;

const abortController = new AbortController();

let mounted = true;
invocation(abortController.signal).then(
(data) => {
if (!mounted) return;
setState({
data,
hasData: true,
loading: false,
error: null,
});
},
(error) => {
if (!mounted) return;
setState((prevState) => ({
data: discardDataOnError ? null : prevState.data,
hasData: discardDataOnError ? false : prevState.hasData,
loading: false,
error,
}));
},
);

return () => {
mounted = false;
if (abortPreviousRequest) {
abortController.abort();
}
};
}, dependencies);

return state;
}
7 changes: 6 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
export * from "./util/theme";
export * from "./util/api";
export * from "./util/electionApi";

export * from "./constants/servers";

export * from "./types/Election";

export * from "./hooks/theme";
export * from "./hooks/useApiResponse";
export * from "./hooks/electionApiHooks";

export * from "./components/Typography/Typography";
export * from "./components/Button/Button";
export * from "./components/ColoredSquare/ColoredSquare";
Expand Down
2 changes: 1 addition & 1 deletion src/stories/APIIntegration.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */

import React, { useMemo, useState } from "react";
import { useApiResponse } from "../util/api";
import { useApiResponse } from "../hooks/useApiResponse";
import { ElectionAPI, makeElectionApi } from "../util/electionApi";
import { mockElectionAPI } from "../util/mocks";
import { ElectionObservationSection } from "../components/ElectionObservationSection/ElectionObservationSection";
Expand Down
Loading

1 comment on commit 7eaed1d

@vercel
Copy link

@vercel vercel bot commented on 7eaed1d Sep 21, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.