Skip to content

Commit

Permalink
[#48 & #30] see message: #48 (comment) [cf]
Browse files Browse the repository at this point in the history
  • Loading branch information
cfech committed Jun 30, 2023
1 parent feeeeb3 commit 82357a5
Show file tree
Hide file tree
Showing 15 changed files with 269 additions and 87 deletions.
9 changes: 5 additions & 4 deletions .firebase/hosting.ZGlzdA.cache
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
index.html,1687738745527,016072d1a763c361890ca06a62a7509cec0382e92d1e8e12b7e0e5a53048f1ac
assets/index-8891e0f8.css,1687738745527,1a075d488a7b08e62a37a19d72261dc174ddbfe1f61c1342a2920099475124e3
vite.svg,1687738745365,d3bbbc44b3ea71906a72bf2ec1a4716903e2e3d9f85a5007205a65d1f12e2923
assets/index-12ee572c.js,1687738745527,d261caadfead5a996917ab86646080185c8b095760e73d8b2aa8c676d5173f50
favicon.png,1688159113783,f3c2237334cbc2f8708df1eceaaeac907fac4a7bf117fa24820c3f6f2f1527a8
vite.svg,1688159113784,d3bbbc44b3ea71906a72bf2ec1a4716903e2e3d9f85a5007205a65d1f12e2923
index.html,1688159113917,68fd7f1cff50fb9eb3929210dd270ec22032c4f98f31a7de32bbf7106a04cb64
assets/index-8891e0f8.css,1688159113917,1a075d488a7b08e62a37a19d72261dc174ddbfe1f61c1342a2920099475124e3
assets/index-b732e178.js,1688159113917,c9aef8279bb3d359aba2448f39f8e124d86d6c64b45095842fabcbb1023085ec
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="UTF-8" />
<link rel="icon" type="image/png" href="/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + TS</title>
<title>Civics Central</title>
</head>
<body>
<div id="root"></div>
Expand Down
9 changes: 6 additions & 3 deletions src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,13 @@ import { WhyVote } from "./Pages/WhyVote/WhyVote.tsx";
import { Example } from "./Pages/Example/Example.tsx";
import { ContactUs } from "./Pages/ContactUs/ContactUs.tsx";
import { Box } from "@mui/material";
import { GlobalContext } from "./context/GlobalContext.tsx";
import { GlobalContextWrapper } from "./context/GlobalContextWrapper.tsx";
import { Footer } from "./components/footer/Footer.tsx";
import { CivicInfo } from "./Pages/CivicInfo/CivicInfo.tsx";

function App() {
return (
<GlobalContext>
<GlobalContextWrapper>
<Box
sx={{
backgroundColor: "background.default",
Expand All @@ -29,11 +30,13 @@ function App() {
<Route path="/whyvote" element={<WhyVote />} />
<Route path="/example" element={<Example />} />
<Route path="/contactus" element={<ContactUs />} />
<Route path="/civicInformation" element={<CivicInfo />} />
<Route path="*" element={<Home />} />
</Routes>
</Box>
<Footer />
</Box>
</GlobalContext>
</GlobalContextWrapper>
);
}

Expand Down
18 changes: 18 additions & 0 deletions src/Interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ export interface UserData {
};
}

// ================== Representatives Data =====================

export interface RepresentativeDataResponse {
normalizedInput: NormalizedAddressInput;
kind: string;
Expand Down Expand Up @@ -55,3 +57,19 @@ export interface Channel {
type: string;
id: string;
}

// ================== Representatives Data =====================

// ================== Available Elections Data =================
export interface AvailableElectionsDataResponse {
kind: string;
elections: Election[];
}

export interface Election {
id: string;
name: string;
electionDay: string;
ocdDivisionId: string;
}
// ================== Available Elections Data =================
40 changes: 40 additions & 0 deletions src/Pages/CivicInfo/CivicInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Box, Grid, Typography } from "@mui/material";
import {
useAvailableElectionsContext,
useRepresentativeDataContext,
} from "../../context/customHooks.ts";
import { useEffect } from "react";
import { AddressSearchBar } from "../../components/addressSearchBar/AddressSearchBar.tsx";

export const CivicInfo = () => {
const representativeData = useRepresentativeDataContext();
const availableElections = useAvailableElectionsContext();
useEffect(() => {
console.log({ representativeData });
console.log({ availableElections });
}, [representativeData, availableElections]);
return (
<Box>
<AddressSearchBar isHomePage={false} />

<Grid container>
<Grid item md={6} sx={{ border: "3px solid red", width: "100%" }}>
<Typography variant={"h3"}>Representative Data</Typography>
</Grid>
<Grid
item
md={3}
sx={{
border: "3px solid yellow",
width: "100%",
}}
>
<Typography variant={"h3"}>Upcoming Elections</Typography>
</Grid>
<Grid item md={3} xs sx={{ border: "3px solid green", width: "100%" }}>
<Typography variant={"h3"}>Election Info</Typography>
</Grid>
</Grid>
</Box>
);
};
4 changes: 2 additions & 2 deletions src/Pages/Example/Example.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { UserData } from "../../Interfaces.ts";
import axios from "axios";
import { ExampleList } from "./exampleList/ExampleList.tsx";
import { ExampleSearchBar } from "./exampleSearchBar/ExampleSearchBar.tsx";
import { useRepresentativeDataResponse } from "../../context/customHooks.ts";
import { useRepresentativeDataContext } from "../../context/customHooks.ts";

export function Example() {
const [randomUsers, setRandomUsers] = useState<UserData[]>([]);
Expand All @@ -24,7 +24,7 @@ export function Example() {
const theme = useTheme();

// Pulling the representative data from react context
const representativeData = useRepresentativeDataResponse();
const representativeData = useRepresentativeDataContext();

// Check the console to view the theme object
useEffect(() => {
Expand Down
3 changes: 2 additions & 1 deletion src/Pages/Home/Home.test.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { render, screen } from "@testing-library/react";
import { Home } from "./Home.tsx";
import { BrowserRouter } from "react-router-dom";

describe("App", () => {
it("renders headline", () => {
render(<Home />);
render(<Home />, { wrapper: BrowserRouter });

screen.debug();

Expand Down
4 changes: 2 additions & 2 deletions src/Pages/Home/Home.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Box, Typography } from "@mui/material";
import { HomePageSearchBar } from "../../components/homepageSearchBar/HomepageSearchBar.tsx";
import { AddressSearchBar } from "../../components/addressSearchBar/AddressSearchBar.tsx";

export function Home() {
return (
Expand All @@ -17,7 +17,7 @@ export function Home() {
Enter your residential address and we'll take it from here!
</Typography>

<HomePageSearchBar />
<AddressSearchBar isHomePage={true} />
<Box
sx={{
display: "flex",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import React, { useState, useEffect } from "react";
import React, { useEffect, useState } from "react";
import {
TextField,
InputAdornment,
Alert,
Box,
Button,
InputAdornment,
Snackbar,
Alert,
TextField,
} from "@mui/material";
import Fade from "@mui/material/Fade";
import HomeIcon from "@mui/icons-material/Home";
import HowToVoteIcon from "@mui/icons-material/HowToVote";
import axios from "axios";
import {
useRepresentativeDataResponse,
useSetRepresentativeDataResponse,
useSetAvailableElectionsContext,
useSetRepresentativeDataContext,
} from "../../context/customHooks.ts";
import { useNavigate } from "react-router-dom";

Expand All @@ -29,7 +29,11 @@ const placeholders = [
"220 S. 33rd St, Philadelphia, PA 19104",
];

export const HomePageSearchBar: React.FC = () => {
interface AddressSearchBarProps {
isHomePage: boolean;
}

export const AddressSearchBar = ({ isHomePage }: AddressSearchBarProps) => {
// =================== React States ===================
const [searchBarValue, setSearchBarValue] = useState<string>("");
const [placeholder, setPlaceholder] = useState<string>(
Expand All @@ -40,20 +44,23 @@ export const HomePageSearchBar: React.FC = () => {
const [googleApiErrorMessage, setGoogleApiErrorMessage] =
useState<string>("");

const [representativeCallSuccessful, setRepresentativeCallSuccessful] =
useState<boolean>(false);
const [electionCallSuccessful, setElectionCallSuccessful] =
useState<boolean>(false);

// =================== React States ===================

// =================== React Hooks ===================

useEffect(() => {
console.log(searchBarValue);
}, [searchBarValue]);

const representativeDataResponse = useRepresentativeDataResponse();
// Allows us to navigate to a new url
const navigate = useNavigate();

// TODO - figure out what type this should be
const setRepresentativeDataResponse: any = useSetRepresentativeDataResponse();
// Getting access to setters from context
const setRepresentativeDataResponse: any = useSetRepresentativeDataContext();
const setAvailableElections: any = useSetAvailableElectionsContext();

// For changing address
useEffect(() => {
let placeholderIndex = 0;
const interval = setInterval(() => {
Expand All @@ -64,29 +71,33 @@ export const HomePageSearchBar: React.FC = () => {
return () => clearInterval(interval);
}, []);

// Only navigate if both our calls were successful and we are still on the home page
useEffect(() => {
console.log(representativeDataResponse);
}, [representativeDataResponse]);
if (representativeCallSuccessful && electionCallSuccessful && isHomePage) {
navigate("/civicInformation");
}
});

// =================== React Hooks ===================

// =================== Helper Functions ==============

// Updates the state of the search bar value when typing
const handleChange = (event: React.ChangeEvent<HTMLInputElement>) => {
setSearchBarValue(event.target.value);
};

const handleClick = () => {
const address = encodeAddress(searchBarValue);
quereyRepresentativeAPI(address);
queryRepresentativeAPI(address);
};

// Have to change spaces in the entered address to %20 to send over and http call
const encodeAddress = (value: string) => {
const encodedAddress = value.trim().replaceAll(" ", "%20");
return encodedAddress;
return value.trim().replaceAll(" ", "%20");
};

const quereyRepresentativeAPI = (address: string) => {
const queryRepresentativeAPI = (address: string) => {
setButtonIsDisabled(true);
axios
.get(
Expand All @@ -97,9 +108,13 @@ export const HomePageSearchBar: React.FC = () => {
.then((res) => {
console.log(res);
setRepresentativeDataResponse(res.data);
navigate("/example");
setRepresentativeCallSuccessful(true);

// Call the query for elections API after the representative call is successful
queryAvailableElectionsAPI();
})
.catch((err) => {
// Catch any errors in the api chain
console.log(err);
setGoogleApiErrorMessage(err.response.data.error.message);
setSnackBarIsOpen(true);
Expand All @@ -109,13 +124,47 @@ export const HomePageSearchBar: React.FC = () => {
});
};

const queryAvailableElectionsAPI = () => {
axios
.get(
`https://www.googleapis.com/civicinfo/v2/elections?key=${
import.meta.env.VITE_CIVICS_API_KEY
}`
)
.then((res) => {
// Setting the state on successful response
setAvailableElections(res.data);
setElectionCallSuccessful(true);
});
};

const closeSnackBar = () => {
setSnackBarIsOpen(false);
};

// =================== Helper Functions ==============

// =================== Custom Styles ==============
const homePageStyling = {
width: "80%",
marginTop: "50px",
display: "block",
flexDirection: "column",
textAlign: "right",
margin: "auto",
};

const informationPageStyling = {
width: "80%",
marginTop: "50px",
display: "flex",
flexDirection: { xs: "column", sm: "row" },
textAlign: "center",
margin: "50px auto",
};

return (
<Box sx={{ width: "80%", marginTop: "50px" }}>
<Box sx={isHomePage ? homePageStyling : informationPageStyling}>
<TextField
label="Enter your residential address"
value={searchBarValue}
Expand All @@ -130,28 +179,22 @@ export const HomePageSearchBar: React.FC = () => {
),
}}
/>
<Box
<Button
variant="contained"
sx={{
marginTop: "20px",
width: { xs: "100%", sm: "inherit" },
textAlign: { xs: "center", sm: "right" },
backgroundColor: "primary.light",
maxWidth: "250px",
marginTop: isHomePage ? "20px" : "0px",
}}
color="primary"
startIcon={<HowToVoteIcon />}
onClick={handleClick}
disabled={buttonIsDisabled || searchBarValue.trim().length === 0}
>
<Button
variant="contained"
sx={{
width: { xs: "100%", sm: "auto" },
textAlign: { xs: "center", sm: "right" },
backgroundColor: "primary.light",
maxWidth: "250px",
}}
color="primary"
startIcon={<HowToVoteIcon />}
onClick={handleClick}
disabled={buttonIsDisabled || searchBarValue.trim().length === 0}
>
Find my elections info!
</Button>
</Box>
Find my elections info!
</Button>

<Snackbar
open={snackBarIsOpen}
Expand Down
Loading

0 comments on commit 82357a5

Please sign in to comment.