diff --git a/package-lock.json b/package-lock.json
index d04b7c094..69331046c 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -12,6 +12,7 @@
"@ant-design/icons": "^4.7.0",
"@ant-design/pro-form": "^1.52.13",
"@ant-design/pro-table": "^2.62.7",
+ "@auth0/auth0-react": "^2.2.4",
"@craco/craco": "^6.4.3",
"@material-ui/core": "^4.12.4",
"@reduxjs/toolkit": "^1.8.2",
@@ -245,6 +246,23 @@
"react": ">=16.9.0"
}
},
+ "node_modules/@auth0/auth0-react": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/@auth0/auth0-react/-/auth0-react-2.2.4.tgz",
+ "integrity": "sha512-l29PQC0WdgkCoOc6WeMAY26gsy/yXJICW0jHfj0nz8rZZphYKrLNqTRWFFCMJY+sagza9tSgB1kG/UvQYgGh9A==",
+ "dependencies": {
+ "@auth0/auth0-spa-js": "^2.1.3"
+ },
+ "peerDependencies": {
+ "react": "^16.11.0 || ^17 || ^18",
+ "react-dom": "^16.11.0 || ^17 || ^18"
+ }
+ },
+ "node_modules/@auth0/auth0-spa-js": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@auth0/auth0-spa-js/-/auth0-spa-js-2.1.3.tgz",
+ "integrity": "sha512-NMTBNuuG4g3rame1aCnNS5qFYIzsTUV5qTFPRfTyYFS1feS6jsCBR+eTq9YkxCp1yuoM2UIcjunPaoPl77U9xQ=="
+ },
"node_modules/@babel/code-frame": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
@@ -30233,6 +30251,19 @@
"resize-observer-polyfill": "^1.5.1"
}
},
+ "@auth0/auth0-react": {
+ "version": "2.2.4",
+ "resolved": "https://registry.npmjs.org/@auth0/auth0-react/-/auth0-react-2.2.4.tgz",
+ "integrity": "sha512-l29PQC0WdgkCoOc6WeMAY26gsy/yXJICW0jHfj0nz8rZZphYKrLNqTRWFFCMJY+sagza9tSgB1kG/UvQYgGh9A==",
+ "requires": {
+ "@auth0/auth0-spa-js": "^2.1.3"
+ }
+ },
+ "@auth0/auth0-spa-js": {
+ "version": "2.1.3",
+ "resolved": "https://registry.npmjs.org/@auth0/auth0-spa-js/-/auth0-spa-js-2.1.3.tgz",
+ "integrity": "sha512-NMTBNuuG4g3rame1aCnNS5qFYIzsTUV5qTFPRfTyYFS1feS6jsCBR+eTq9YkxCp1yuoM2UIcjunPaoPl77U9xQ=="
+ },
"@babel/code-frame": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
diff --git a/package.json b/package.json
index 284588c52..325790713 100644
--- a/package.json
+++ b/package.json
@@ -16,6 +16,7 @@
"@ant-design/icons": "^4.7.0",
"@ant-design/pro-form": "^1.52.13",
"@ant-design/pro-table": "^2.62.7",
+ "@auth0/auth0-react": "^2.2.4",
"@craco/craco": "^6.4.3",
"@material-ui/core": "^4.12.4",
"@reduxjs/toolkit": "^1.8.2",
diff --git a/src/auth0-provider-with-history.js b/src/auth0-provider-with-history.js
new file mode 100644
index 000000000..b4575683e
--- /dev/null
+++ b/src/auth0-provider-with-history.js
@@ -0,0 +1,32 @@
+import { Auth0Provider } from '@auth0/auth0-react';
+import React from 'react';
+import { useHistory } from 'react-router-dom';
+
+export const Auth0ProviderWithHistory = ({ children }) => {
+ const history = useHistory();
+
+ const domain = process.env.REACT_APP_AUTH0_DOMAIN;
+ const clientId = process.env.REACT_APP_AUTH0_CLIENT_ID;
+ const redirectUri = process.env.REACT_APP_AUTH0_CALLBACK_URL;
+
+ const onRedirectCallback = appState => {
+ history.push(appState?.returnTo || window.location.pathname);
+ };
+
+ if (!(domain && clientId)) {
+ return null;
+ }
+
+ return (
+
+ {children}
+
+ );
+};
diff --git a/src/callback-page.js b/src/callback-page.js
new file mode 100644
index 000000000..12163da8d
--- /dev/null
+++ b/src/callback-page.js
@@ -0,0 +1,12 @@
+import React from 'react';
+// import { NavBar } from "../components/navigation/desktop/nav-bar";
+// import { MobileNavBar } from "../components/navigation/mobile/mobile-nav-bar";
+
+export const CallbackPage = () => {
+ return (
+
+ );
+};
diff --git a/src/components/Layout/Header.jsx b/src/components/Layout/Header.jsx
index 3346cbfe4..0cee057a5 100644
--- a/src/components/Layout/Header.jsx
+++ b/src/components/Layout/Header.jsx
@@ -1,12 +1,18 @@
+import { useAuth0 } from '@auth0/auth0-react';
import React from 'react';
import { Image } from 'antd';
import { Link } from 'react-router-dom';
import Logo from '../../styles/Images/WhiteLogo.png';
import { colors } from '../../styles/data_vis_colors';
+import { LoginButton } from '../common/login-button';
+import { LogoutButton } from '../common/logout-button';
+import { SignupButton } from '../common/signup-button';
const { primary_accent_color } = colors;
function HeaderContent() {
+ const { isAuthenticated } = useAuth0();
+
return (
Home
-
+
Graphs
+ {!isAuthenticated && (
+ <>
+
+
+ >
+ )}
+ {isAuthenticated && (
+ <>
+
+ Profile
+
+
+ >
+ )}
);
diff --git a/src/components/common/login-button.js b/src/components/common/login-button.js
new file mode 100644
index 000000000..088c6a4fc
--- /dev/null
+++ b/src/components/common/login-button.js
@@ -0,0 +1,32 @@
+import { useAuth0 } from '@auth0/auth0-react';
+import React from 'react';
+
+export const LoginButton = () => {
+ const { loginWithRedirect } = useAuth0();
+
+ const handleLogin = async () => {
+ await loginWithRedirect({
+ appState: {
+ returnTo: '/profile',
+ },
+ authorizationParams: {
+ screen_hint: 'signup',
+ },
+ });
+ };
+
+ return (
+
+ Log In
+
+ );
+};
diff --git a/src/components/common/logout-button.js b/src/components/common/logout-button.js
new file mode 100644
index 000000000..f6520823b
--- /dev/null
+++ b/src/components/common/logout-button.js
@@ -0,0 +1,29 @@
+import { useAuth0 } from '@auth0/auth0-react';
+import React from 'react';
+
+export const LogoutButton = () => {
+ const { logout } = useAuth0();
+
+ const handleLogout = () => {
+ logout({
+ logoutParams: {
+ returnTo: window.location.origin,
+ },
+ });
+ };
+
+ return (
+
+ Log Out
+
+ );
+};
diff --git a/src/components/common/signup-button.js b/src/components/common/signup-button.js
new file mode 100644
index 000000000..66484376c
--- /dev/null
+++ b/src/components/common/signup-button.js
@@ -0,0 +1,33 @@
+import { useAuth0 } from '@auth0/auth0-react';
+import React from 'react';
+
+export const SignupButton = () => {
+ const { loginWithRedirect } = useAuth0();
+
+ const handleSignUp = async () => {
+ await loginWithRedirect({
+ appState: {
+ returnTo: '/profile',
+ },
+ authorizationParams: {
+ screen_hint: 'signup',
+ },
+ });
+ };
+
+ return (
+
+ Sign Up
+
+ );
+};
diff --git a/src/components/pages/DataVisualizations/GraphWrapper.jsx b/src/components/pages/DataVisualizations/GraphWrapper.jsx
index 2d25a26e8..c082f4d92 100644
--- a/src/components/pages/DataVisualizations/GraphWrapper.jsx
+++ b/src/components/pages/DataVisualizations/GraphWrapper.jsx
@@ -10,7 +10,7 @@ import YearLimitsSelect from './YearLimitsSelect';
import ViewSelect from './ViewSelect';
import axios from 'axios';
import { resetVisualizationQuery } from '../../../state/actionCreators';
-import test_data from '../../../data/test_data.json';
+//import test_data from '../../../data/test_data.json';
import { colors } from '../../../styles/data_vis_colors';
import ScrollToTopOnMount from '../../../utils/scrollToTopOnMount';
@@ -19,10 +19,12 @@ const { background_color } = colors;
function GraphWrapper(props) {
const { set_view, dispatch } = props;
let { office, view } = useParams();
+
if (!view) {
set_view('time-series');
view = 'time-series';
}
+
let map_to_render;
if (!office) {
switch (view) {
@@ -50,6 +52,7 @@ function GraphWrapper(props) {
break;
}
}
+
function updateStateWithNewData(years, view, office, stateSettingCallback) {
/*
_ _
@@ -73,9 +76,15 @@ function GraphWrapper(props) {
*/
+ // updated test data to API data (SR 3/16/24)
+ const baseURL = `https://hrf-asylum-be-b.herokuapp.com/cases`;
+ let endpoint =
+ view === 'citizenship' ? '/citizenshipSummary' : '/fiscalSummary';
+
if (office === 'all' || !office) {
axios
- .get(process.env.REACT_APP_API_URI, {
+ //.get(process.env.REACT_APP_API_URI, {
+ .get(`${baseURL}${endpoint}`, {
// mock URL, can be simply replaced by `${Real_Production_URL}/summary` in prod!
params: {
from: years[0],
@@ -83,15 +92,21 @@ function GraphWrapper(props) {
},
})
.then(result => {
- stateSettingCallback(view, office, test_data); // <-- `test_data` here can be simply replaced by `result.data` in prod!
+ //stateSettingCallback(view, office, view === 'citizenship' ? result.data : [result.data]); // <-- `test_data` here can be simply replaced by `result.data` in prod!
+ stateSettingCallback(
+ view,
+ office,
+ view === 'citizenship' ? result.data : [result.data]
+ );
})
.catch(err => {
console.error(err);
});
} else {
axios
- .get(process.env.REACT_APP_API_URI, {
- // mock URL, can be simply replaced by `${Real_Production_URL}/summary` in prod!
+ //.get(process.env.REACT_APP_API_URI, {
+ // mock URL, can be simply replaced by `${Real_Production_URL}/summary` in prod!
+ .get(`${baseURL}${endpoint}`, {
params: {
from: years[0],
to: years[1],
@@ -99,7 +114,11 @@ function GraphWrapper(props) {
},
})
.then(result => {
- stateSettingCallback(view, office, test_data); // <-- `test_data` here can be simply replaced by `result.data` in prod!
+ stateSettingCallback(
+ view,
+ office,
+ view === 'citizenship' ? result.data : [result.data]
+ ); // <-- `test_data` here can be simply replaced by `result.data` in prod!
})
.catch(err => {
console.error(err);
diff --git a/src/components/pages/DataVisualizations/Graphs/CitizenshipMapAll.jsx b/src/components/pages/DataVisualizations/Graphs/CitizenshipMapAll.jsx
index a94c202a9..67483827c 100644
--- a/src/components/pages/DataVisualizations/Graphs/CitizenshipMapAll.jsx
+++ b/src/components/pages/DataVisualizations/Graphs/CitizenshipMapAll.jsx
@@ -58,7 +58,7 @@ function CitizenshipMapAll(props) {
'Citizenship',
'Total Cases',
'% Granted',
- '% Admin Close / Dismissal',
+ '% Admin Closed / Dismissal',
'% Denied',
];
@@ -115,8 +115,12 @@ function CitizenshipMapAll(props) {
/>
Select another region below
- {geoScopeArray.map(a => {
- return {a.toUpperCase()} ;
+ {geoScopeArray.map((a, index) => {
+ return (
+
+ {a.toUpperCase()}
+
+ );
})}
Table view
diff --git a/src/components/pages/DataVisualizations/Graphs/CitizenshipMapSingleOffice.jsx b/src/components/pages/DataVisualizations/Graphs/CitizenshipMapSingleOffice.jsx
index 18305f99e..bed68a48c 100644
--- a/src/components/pages/DataVisualizations/Graphs/CitizenshipMapSingleOffice.jsx
+++ b/src/components/pages/DataVisualizations/Graphs/CitizenshipMapSingleOffice.jsx
@@ -57,7 +57,7 @@ function CitizenshipMapSingleOffice(props) {
'Citizenship',
'Total Cases',
'% Granted',
- '% Admin Close / Dismissal',
+ '% Admin Closed / Dismissal',
'% Denied',
];
return (
@@ -107,10 +107,14 @@ function CitizenshipMapSingleOffice(props) {
}}
style={{ width: '100%', fontWeight: '900' }}
/>
- Select another region below
+ Select another region below
- {geoScopeArray.map(a => {
- return {a.toUpperCase()} ;
+ {geoScopeArray.map((a, index) => {
+ return (
+
+ {a.toUpperCase()}
+
+ );
})}
Table view
diff --git a/src/components/pages/DataVisualizations/Graphs/TableComponents/TableRow.jsx b/src/components/pages/DataVisualizations/Graphs/TableComponents/TableRow.jsx
index 2ede5a306..066d70cc8 100644
--- a/src/components/pages/DataVisualizations/Graphs/TableComponents/TableRow.jsx
+++ b/src/components/pages/DataVisualizations/Graphs/TableComponents/TableRow.jsx
@@ -17,25 +17,26 @@ function TableRow(props) {
}}
>
{columns.map((property, idx) => {
- if (row) {
- if (typeof row[property] === 'object') {
- return (
-
+ );
+ } else {
+ return (
+
+
- );
- } else {
- return (
-
- );
- }
+
+ );
}
})}
diff --git a/src/components/pages/DataVisualizations/GraphsContainer.jsx b/src/components/pages/DataVisualizations/GraphsContainer.jsx
index 9dc39a163..4715a8979 100644
--- a/src/components/pages/DataVisualizations/GraphsContainer.jsx
+++ b/src/components/pages/DataVisualizations/GraphsContainer.jsx
@@ -26,17 +26,17 @@ function GraphsContainer() {
'New Orleans, LA',
];
function handle_office_select(value) {
- // if (view === 'office-heat-map') {
- // set_view('time-series');
- // }
- // if (value === 'All') {
- // history.push(
- // `/graphs/all/${view === 'office-heat-map' ? 'time-series' : view}`
- // );
- // }
- // history.push(
- // `/graphs/${value}/${view === 'office-heat-map' ? 'time-series' : view}`
- // );
+ if (view === 'office-heat-map') {
+ set_view('time-series');
+ }
+ if (value === 'All') {
+ history.push(
+ `/graphs/all/${view === 'office-heat-map' ? 'time-series' : view}`
+ );
+ }
+ history.push(
+ `/graphs/${value}/${view === 'office-heat-map' ? 'time-series' : view}`
+ );
switch (value) {
case 'All Offices':
@@ -152,7 +152,7 @@ function GraphsContainer() {
>
{offices.map((office, idx) =>
office === 'All' ? (
-
+
{office}
) : (
diff --git a/src/components/pages/Landing/RenderLandingPage.jsx b/src/components/pages/Landing/RenderLandingPage.jsx
index 6be6b69a4..11929150c 100644
--- a/src/components/pages/Landing/RenderLandingPage.jsx
+++ b/src/components/pages/Landing/RenderLandingPage.jsx
@@ -1,25 +1,31 @@
import React from 'react';
// ADD IMPORTS BACK FOR GRAPHS SECTION
-// import GrantRatesByOfficeImg from '../../../styles/Images/bar-graph-no-text.png';
-// import GrantRatesByNationalityImg from '../../../styles/Images/pie-chart-no-text.png';
-// import GrantRatesOverTimeImg from '../../../styles/Images/line-graph-no-text.png';
+
+// SR - imported styling images
+import GrantRatesByOfficeImg from '../../../styles/Images/bar-graph-no-text.png';
+import GrantRatesByNationalityImg from '../../../styles/Images/pie-chart-no-text.png';
+import GrantRatesOverTimeImg from '../../../styles/Images/line-graph-no-text.png';
import HrfPhoto from '../../../styles/Images/paper-stack.jpg';
import '../../../styles/RenderLandingPage.less';
import { Button } from 'antd';
import { useHistory } from 'react-router-dom';
+
// for the purposes of testing PageNav
-// import PageNav from '../../common/PageNav';
+//import PageNav from '../../common/PageNav';
function RenderLandingPage(props) {
+ // declare function for scroll back to top
const scrollToTop = () => {
document.body.scrollTop = 0;
document.documentElement.scrollTop = 0;
};
+ // declare history function for navigation
const history = useHistory();
return (
+ {/* Header Section */}
Asylum Office Grant Rate Tracker
@@ -31,18 +37,64 @@ function RenderLandingPage(props) {
- {/* Graphs Section: Add code here for the graphs section for your first ticket */}
- {/*
*/}
+ {/* Graphs Section (SR 3/3)*/}
+
+
+
+
Search Grant Rates By Office
+
+
+
+
Search Grant Rates By Nationality
+
+
+
+
Search Grant Rates Over Time
+
+
+
+ {/* Button container and buttons */}
history.push('/graphs')}
+ onClick={() => {
+ // navigates to "GraphsContainer component"
+ history.push('/graphs');
+ }}
>
View the Data
+
+ {/* Download Data Button (SR 3/3) */}
+
+ (window.location.href =
+ 'https://humanrightsfirst.org/wp-content/uploads/2022/10/COW2021001887-I589Data.csv')
+ }
+ >
+ Download the Data
+
+ {/* Middle Section (SR 3/3)*/}
@@ -55,13 +107,53 @@ function RenderLandingPage(props) {
through a Freedom of Information Act request. You can search for
information on asylum grant rates by year, nationality, and asylum
office, visualize the data with charts and heat maps, and download
- the data set
+ the data set.
- {/* Bottom Section: Add code here for the graphs section for your first ticket */}
- {/*
*/}
+ {/* Bottom Section (SR 3/3) */}
+
+
Systemic Disparity Insights
+
+
+
36%
+
+ By the end of the Trump administration, the average asylum
+ office grant rate had fallen 36 percent from an average of 44
+ percent in fiscal year 2016 to 28 percent in fiscal year 2020.
+
+
+
+
5%
+
+ The New York asylum office grant rate dropped to 5 percent in
+ fiscal year 2020.
+
+
+
+
6x Lower
+
+ Between fiscal year 2017 and 2020, the New York asylum office’s
+ average grant rate was six times lower than the San Francisco
+ asylum office.
+
+
+
+
+ {/* Read More button takes user to article on humanrightsfirst.org (SR 3/3) */}
+
+ (window.location.href =
+ 'https://humanrightsfirst.org/library/uscis-records-reveal-systemic-disparities-in-asylum-decisions/')
+ }
+ >
+ Read More
+
+
scrollToTop()} className="back-to-top">
Back To Top ^
diff --git a/src/components/pages/profile-page.js b/src/components/pages/profile-page.js
new file mode 100644
index 000000000..a6370ed71
--- /dev/null
+++ b/src/components/pages/profile-page.js
@@ -0,0 +1,33 @@
+import { useAuth0 } from '@auth0/auth0-react';
+import React from 'react';
+// import { NavBar } from "../components/navigation/desktop/nav-bar";
+// import { MobileNavBar } from "../components/navigation/mobile/mobile-nav-bar";
+
+export const ProfilePage = () => {
+ const { user } = useAuth0();
+
+ if (!user) {
+ return null;
+ }
+
+ return (
+
+
+ Profile Page
+
+
+
+
+
+
+
+ Username: {user.name}
+
+
+ Email: {user.email}
+
+
+
+
+ );
+};
diff --git a/src/components/protected-route.js b/src/components/protected-route.js
new file mode 100644
index 000000000..4a14de930
--- /dev/null
+++ b/src/components/protected-route.js
@@ -0,0 +1,17 @@
+import { withAuthenticationRequired } from '@auth0/auth0-react';
+import React from 'react';
+import { Route } from 'react-router-dom';
+import LoadingComponent from './common/LoadingComponent';
+
+export const ProtectedRoute = ({ component, ...args }) => (
+
(
+
+
+
+ ),
+ })}
+ {...args}
+ />
+);
diff --git a/src/index.jsx b/src/index.jsx
index 73962baa5..80e594339 100644
--- a/src/index.jsx
+++ b/src/index.jsx
@@ -10,7 +10,7 @@ import {
import 'antd/dist/antd.less';
import { NotFoundPage } from './components/pages/NotFound';
import { LandingPage } from './components/pages/Landing';
-
+import { ProtectedRoute } from './components/protected-route';
import { FooterContent, SubFooter } from './components/Layout/Footer';
import { HeaderContent } from './components/Layout/Header';
@@ -22,6 +22,9 @@ import { Provider } from 'react-redux';
import { configureStore } from '@reduxjs/toolkit';
import reducer from './state/reducers';
import { colors } from './styles/data_vis_colors';
+import { CallbackPage } from './callback-page';
+import { ProfilePage } from './components/pages/profile-page';
+import { Auth0ProviderWithHistory } from './auth0-provider-with-history';
const { primary_accent_color } = colors;
@@ -29,9 +32,11 @@ const store = configureStore({ reducer: reducer });
ReactDOM.render(
-
-
-
+
+
+
+
+
,
document.getElementById('root')
@@ -54,6 +59,8 @@ export function App() {
+
+
{
+ let rowsForTable;
+ let rowItem;
const officeNames = [
'Los Angeles, CA',
'San Francisco, CA',
@@ -11,239 +13,469 @@ const rawApiDataToPlotlyReadyInfo = (view, office, data) => {
'Miami, FL',
'New Orleans, LA',
];
- let rowItem;
- let rowsForTable;
- let yearMinMax = []; //variable to set minYear and MaxYear
- for (let yearResults of data[0]['yearResults']) {
- yearMinMax.push(yearResults['fiscal_year']);
- }
+ // Handling for 'citizenship' view first (SR 3/16/24)
+ if (view === 'citizenship') {
+ const rowsForTable = data.map(item => ({
+ Citizenship: item.citizenship,
+ 'Total Cases': item.totalCases,
+ '% Granted': Number(item.granted).toFixed(2),
+ '% Admin Closed / Dismissal': Number(item.adminClosed).toFixed(2),
+ '% Denied': Number(item.denied).toFixed(2),
+ }));
+
+ const countryGrantRateObj = {
+ countries: data.map(item => item.citizenship),
+ countriesPercentGranteds: data.map(item => item.granted),
+ };
+
+ return { rowsForTable, countryGrantRateObj };
+ } else {
+ const yearMinMax = [];
+ const yearByOfficeByGrant = {};
- const yearByOfficeByGrant = {}; //Object that contacts year by Office by grant rate information
- for (let office of data[0]['yearResults']) {
- if (!yearByOfficeByGrant[office['fiscal_year']])
- yearByOfficeByGrant[office['fiscal_year']] = {}; //if year not existing set to empty object
- for (let yearData of office['yearData']) {
- yearByOfficeByGrant[office['fiscal_year']][yearData['office']] = {
- //assign rates to year:{office:{}}
- granted: yearData['granted'],
- adminClosed: yearData['adminClosed'],
- denied: yearData['denied'],
+ for (let office of data[0]['yearResults']) {
+ if (!yearByOfficeByGrant[office['fiscal_year']]) {
+ yearByOfficeByGrant[office['fiscal_year']] = {};
+ }
+ for (let yearData of office['yearData']) {
+ yearByOfficeByGrant[office['fiscal_year']][yearData['office']] = {
+ granted: yearData['granted'],
+ adminClosed: yearData['adminClosed'],
+ denied: yearData['denied'],
+ };
+ }
+ }
+
+ const officeData = {};
+ for (let officeName of officeNames) {
+ officeData[officeName] = {
+ xYears: [],
+ totals: [],
+ yTotalPercentGranteds: [],
+ totalPercentAdminCloseds: [],
+ totalPercentDenieds: [],
};
}
- }
- const officeData = {}; //object that holds each % as a key of array value
- for (let officeName of officeNames) {
- officeData[officeName] = {
- xYears: [],
- totals: [],
- yTotalPercentGranteds: [],
- totalPercentAdminCloseds: [],
- totalPercentDenieds: [],
- };
- }
- for (let yearResults of data[0]['yearResults']) {
- for (let yearData of yearResults['yearData']) {
- officeData[yearData['office']]['xYears'].push(yearResults['fiscal_year']);
- officeData[yearData['office']]['totals'].push(yearData['totalCases']);
- officeData[yearData['office']]['yTotalPercentGranteds'].push(
- yearData['granted']
- );
- officeData[yearData['office']]['totalPercentAdminCloseds'].push(
- yearData['adminClosed']
- );
- officeData[yearData['office']]['totalPercentDenieds'].push(
- yearData['denied']
- );
+ for (let yearResults of data[0]['yearResults']) {
+ yearMinMax.push(yearResults['fiscal_year']);
+ for (let yearData of yearResults['yearData']) {
+ officeData[yearData['office']]['xYears'].push(
+ yearResults['fiscal_year']
+ );
+ officeData[yearData['office']]['totals'].push(yearData['totalCases']);
+ officeData[yearData['office']]['yTotalPercentGranteds'].push(
+ yearData['granted']
+ );
+ officeData[yearData['office']]['totalPercentAdminCloseds'].push(
+ yearData['adminClosed']
+ );
+ officeData[yearData['office']]['totalPercentDenieds'].push(
+ yearData['denied']
+ );
+ }
}
- }
- if (!office || office === 'all') {
- switch (view) {
- case 'time-series':
- const rowsForAllDisplay = [];
- for (let yearResults of data[0].yearResults) {
- rowItem = {
- 'Fiscal Year': yearResults.fiscal_year,
- 'Total Cases': yearResults.totalCases,
- '% Granted': Number(yearResults.granted).toFixed(2),
- '% Admin Close / Dismissal': Number(
- yearResults.adminClosed
- ).toFixed(2),
- '% Denied': Number(yearResults.denied).toFixed(2),
+ if (!office || office === 'all') {
+ switch (view) {
+ case 'time-series':
+ const rowsForAllDisplay = [];
+ for (let yearResults of data[0].yearResults) {
+ rowItem = {
+ 'Fiscal Year': yearResults.fiscal_year,
+ 'Total Cases': yearResults.totalCases,
+ '% Granted': Number(yearResults.granted).toFixed(2),
+ '% Admin Close / Dismissal': Number(
+ yearResults.adminClosed
+ ).toFixed(2),
+ '% Denied': Number(yearResults.denied).toFixed(2),
+ };
+ rowsForAllDisplay.push(rowItem);
+ }
+
+ const finalData = {
+ xYears: [],
+ totals: [],
+ yTotalPercentGranteds: [],
+ totalPercentAdminCloseds: [],
+ totalPercentDenieds: [],
};
- rowsForAllDisplay.push(rowItem);
- }
-
- const finalData = {
- xYears: [],
- totals: [],
- yTotalPercentGranteds: [],
- totalPercentAdminCloseds: [],
- totalPercentDenieds: [],
- };
- for (let officeName of data[0]['yearResults']) {
- finalData['xYears'].push(officeName['fiscal_year']);
- finalData['totals'].push(officeName['totalCases']);
- finalData['yTotalPercentGranteds'].push(officeName['granted']);
- finalData['totalPercentAdminCloseds'].push(officeName['adminClosed']);
- finalData['totalPercentDenieds'].push(officeName['denied']);
- }
-
- return { ...finalData, rowsForAllDisplay, officeData };
-
- case 'office-heat-map':
- rowsForTable = [];
- for (let yearResults of data[0].yearResults) {
- for (let officeKey of officeNames) {
+ for (let officeName of data[0]['yearResults']) {
+ finalData['xYears'].push(officeName['fiscal_year']);
+ finalData['totals'].push(officeName['totalCases']);
+ finalData['yTotalPercentGranteds'].push(officeName['granted']);
+ finalData['totalPercentAdminCloseds'].push(
+ officeName['adminClosed']
+ );
+ finalData['totalPercentDenieds'].push(officeName['denied']);
+ }
+
+ return { ...finalData, rowsForAllDisplay, officeData };
+
+ case 'office-heat-map':
+ rowsForTable = [];
+ for (let yearResults of data[0].yearResults) {
+ for (let officeKey of officeNames) {
+ if (
+ yearResults.yearData.filter(
+ yearItem => yearItem.office === officeKey
+ ).length > 0
+ ) {
+ rowItem = {
+ 'Year [Office]':
+ String(yearResults.fiscal_year) +
+ ' [' +
+ String(officeKey) +
+ ']',
+ 'Total Cases': yearResults.yearData.filter(
+ yearItem => yearItem.office === officeKey
+ )[0].totalCases,
+ '% Granted': Number(
+ yearResults.yearData.filter(
+ yearItem => yearItem.office === officeKey
+ )[0].granted
+ ).toFixed(2),
+ '% Admin Close / Dismissal': Number(
+ yearResults.yearData.filter(
+ yearItem => yearItem.office === officeKey
+ )[0].adminClosed
+ ).toFixed(2),
+ '% Denied': Number(
+ yearResults.yearData.filter(
+ yearItem => yearItem.office === officeKey
+ )[0].denied
+ ).toFixed(2),
+ };
+ rowsForTable.push(rowItem);
+ }
+ }
+ }
+ const officeHeatMapDataObject = {
+ //declare helper object to construct data for heatmap plotly
+ x: officeNames, //office
+ y: [], //year
+ z: [], //rate
+ };
+ for (let fiscal_year in yearByOfficeByGrant) {
+ //loop through
+ officeHeatMapDataObject['y'].push(fiscal_year); //include year into y axis
+ let zAxisArray = []; //Array to hold each row for z axis
+ for (let officeName of officeNames) {
+ //loop using unique office names
+ zAxisArray.push(
+ yearByOfficeByGrant[fiscal_year][officeName]
+ ? yearByOfficeByGrant[fiscal_year][officeName]['granted']
+ : 0
+ );
+ }
+ officeHeatMapDataObject['z'].push(zAxisArray); //push to zaxis array
+ }
+ return { officeHeatMapDataObject, rowsForTable };
+ // switch(view){
+ // case 'time-series':
+ // case 'office-heat-map':
+ // const rowsForAllDisplay = data[0].yearResults.map(yearResult => ({
+ // 'Fiscal Year': yearResult.fiscal_year,
+ // 'Total Cases': yearResult.totalCases,
+ // '% Granted': Number(yearResult.granted).toFixed(2),
+ // '% Admin Close / Dismissal': Number(yearResult.adminClosed).toFixed(2),
+ // '% Denied': Number(yearResult.denied).toFixed(2),
+ // }));
+ // return {
+ // rowsForTable: rowsForAllDisplay,
+ // officeData
+ // };
+
+ default:
+ return {};
+ }
+ } else {
+ let rowsForTable = [];
+ switch (view) {
+ case 'time-series':
+ data[0].yearResults.sort((a, b) => a.fiscal_year - b.fiscal_year);
+ for (let i = 0; i < data[0].yearResults.length; i++) {
if (
- yearResults.yearData.filter(
- yearItem => yearItem.office === officeKey
- ).length > 0
+ data[0].yearResults[i].yearData.filter(
+ dataItem => dataItem.office === office
+ )[0]
) {
+ const officeObj = data[0].yearResults[i].yearData.filter(
+ dataItem => dataItem.office === office
+ )[0];
rowItem = {
- 'Year [Office]':
- String(yearResults.fiscal_year) +
- ' [' +
- String(officeKey) +
- ']',
- 'Total Cases': yearResults.yearData.filter(
- yearItem => yearItem.office === officeKey
- )[0].totalCases,
- '% Granted': Number(
- yearResults.yearData.filter(
- yearItem => yearItem.office === officeKey
- )[0].granted
- ).toFixed(2),
+ 'Fiscal Year': data[0].yearResults[i].fiscal_year,
+ 'Total Cases': officeObj.totalCases,
+ '% Granted': Number(officeObj.granted).toFixed(2),
'% Admin Close / Dismissal': Number(
- yearResults.yearData.filter(
- yearItem => yearItem.office === officeKey
- )[0].adminClosed
- ).toFixed(2),
- '% Denied': Number(
- yearResults.yearData.filter(
- yearItem => yearItem.office === officeKey
- )[0].denied
+ officeObj.adminClosed
).toFixed(2),
+ '% Denied': Number(officeObj.denied).toFixed(2),
};
rowsForTable.push(rowItem);
}
}
- }
- const officeHeatMapDataObject = {
- //declare helper object to construct data for heatmap plotly
- x: officeNames, //office
- y: [], //year
- z: [], //rate
- };
- for (let fiscal_year in yearByOfficeByGrant) {
- //loop through
- officeHeatMapDataObject['y'].push(fiscal_year); //include year into y axis
- let zAxisArray = []; //Array to hold each row for z axis
- for (let officeName of officeNames) {
- //loop using unique office names
- zAxisArray.push(
- yearByOfficeByGrant[fiscal_year][officeName]
- ? yearByOfficeByGrant[fiscal_year][officeName]['granted']
- : 0
- );
- }
- officeHeatMapDataObject['z'].push(zAxisArray); //push to zaxis array
- }
- return { officeHeatMapDataObject, rowsForTable };
-
- case 'citizenship':
- rowsForTable = [];
- for (let item of data[0].citizenshipResults) {
- rowItem = {
- Citizenship: item.citizenship,
- 'Total Cases': item.totalCases,
- '% Granted': Number(item.granted).toFixed(2),
- '% Admin Close / Dismissal': Number(item.adminClosed).toFixed(2),
- '% Denied': Number(item.denied).toFixed(2),
+ const singleOfficeDataObject = officeData[office];
+ return {
+ rowsForTable,
+ singleOfficeDataObject,
};
- rowsForTable.push(rowItem);
- }
- const countryGrantRateObj = {
- countries: [],
- countriesPercentGranteds: [],
- };
- for (let country of data[0]['citizenshipResults']) {
- countryGrantRateObj['countries'].push(country['citizenship']);
- countryGrantRateObj['countriesPercentGranteds'].push(
- country['granted']
- );
- }
- return {
- rowsForTable,
- countryGrantRateObj,
- };
- default:
- return {};
- }
- } else {
- switch (view) {
- case 'time-series':
- rowsForTable = [];
- data[0].yearResults.sort((a, b) => a.fiscal_year - b.fiscal_year);
- for (let i = 0; i < data[0].yearResults.length; i++) {
- if (
- data[0].yearResults[i].yearData.filter(
- dataItem => dataItem.office === office
- )[0]
- ) {
- const officeObj = data[0].yearResults[i].yearData.filter(
- dataItem => dataItem.office === office
- )[0];
- rowItem = {
- 'Fiscal Year': data[0].yearResults[i].fiscal_year,
- 'Total Cases': officeObj.totalCases,
- '% Granted': Number(officeObj.granted).toFixed(2),
- '% Admin Close / Dismissal': Number(
- officeObj.adminClosed
- ).toFixed(2),
- '% Denied': Number(officeObj.denied).toFixed(2),
- };
- rowsForTable.push(rowItem);
- }
- }
- const singleOfficeDataObject = officeData[office];
- return {
- rowsForTable,
- singleOfficeDataObject,
- };
- case 'citizenship':
- rowsForTable = [];
- for (let item of data[0].citizenshipResults) {
- rowItem = {
- Citizenship: item.citizenship,
- 'Total Cases': item.totalCases,
- '% Granted': Number(item.granted).toFixed(2),
- '% Admin Close / Dismissal': Number(item.adminClosed).toFixed(2),
- '% Denied': Number(item.denied).toFixed(2),
- };
- rowsForTable.push(rowItem);
- }
- const countryGrantRateObj = {
- countries: [],
- countriesPercentGranteds: [],
- };
- for (let country of data[0]['citizenshipResults']) {
- countryGrantRateObj['countries'].push(country['citizenship']);
- countryGrantRateObj['countriesPercentGranteds'].push(
- country['granted']
- );
- }
- return {
- rowsForTable,
- countryGrantRateObj,
- };
- default:
- return {};
+ default:
+ return {};
+ }
}
}
};
-
export { rawApiDataToPlotlyReadyInfo };
+
+// const rawApiDataToPlotlyReadyInfo = (view, office, data) => {
+// const officeNames = [
+// 'Los Angeles, CA',
+// 'San Francisco, CA',
+// 'New York, NY',
+// 'Houston, TX',
+// 'Chicago, IL',
+// 'Newark, NJ',
+// 'Arlington, VA',
+// 'Boston, MA',
+// 'Miami, FL',
+// 'New Orleans, LA',
+// ];
+// let rowItem;
+// let rowsForTable;
+
+// let yearMinMax = []; //variable to set minYear and MaxYear
+// for (let yearResults of data[0]['yearResults']) {
+// yearMinMax.push(yearResults['fiscal_year']);
+// }
+
+// const yearByOfficeByGrant = {}; //Object that contacts year by Office by grant rate information
+// for (let office of data[0]['yearResults']) {
+// if (!yearByOfficeByGrant[office['fiscal_year']])
+// yearByOfficeByGrant[office['fiscal_year']] = {}; //if year not existing set to empty object
+// for (let yearData of office['yearData']) {
+// yearByOfficeByGrant[office['fiscal_year']][yearData['office']] = {
+// //assign rates to year:{office:{}}
+// granted: yearData['granted'],
+// adminClosed: yearData['adminClosed'],
+// denied: yearData['denied'],
+// };
+// }
+// }
+
+// const officeData = {}; //object that holds each % as a key of array value
+// for (let officeName of officeNames) {
+// officeData[officeName] = {
+// xYears: [],
+// totals: [],
+// yTotalPercentGranteds: [],
+// totalPercentAdminCloseds: [],
+// totalPercentDenieds: [],
+// };
+// }
+// for (let yearResults of data[0]['yearResults']) {
+// for (let yearData of yearResults['yearData']) {
+// officeData[yearData['office']]['xYears'].push(yearResults['fiscal_year']);
+// officeData[yearData['office']]['totals'].push(yearData['totalCases']);
+// officeData[yearData['office']]['yTotalPercentGranteds'].push(
+// yearData['granted']
+// );
+// officeData[yearData['office']]['totalPercentAdminCloseds'].push(
+// yearData['adminClosed']
+// );
+// officeData[yearData['office']]['totalPercentDenieds'].push(
+// yearData['denied']
+// );
+// }
+// }
+
+// if (!office || office === 'all') {
+// switch (view) {
+// case 'time-series':
+// const rowsForAllDisplay = [];
+// for (let yearResults of data[0].yearResults) {
+// rowItem = {
+// 'Fiscal Year': yearResults.fiscal_year,
+// 'Total Cases': yearResults.totalCases,
+// '% Granted': Number(yearResults.granted).toFixed(2),
+// '% Admin Close / Dismissal': Number(
+// yearResults.adminClosed
+// ).toFixed(2),
+// '% Denied': Number(yearResults.denied).toFixed(2),
+// };
+// rowsForAllDisplay.push(rowItem);
+// }
+
+// const finalData = {
+// xYears: [],
+// totals: [],
+// yTotalPercentGranteds: [],
+// totalPercentAdminCloseds: [],
+// totalPercentDenieds: [],
+// };
+// for (let officeName of data[0]['yearResults']) {
+// finalData['xYears'].push(officeName['fiscal_year']);
+// finalData['totals'].push(officeName['totalCases']);
+// finalData['yTotalPercentGranteds'].push(officeName['granted']);
+// finalData['totalPercentAdminCloseds'].push(officeName['adminClosed']);
+// finalData['totalPercentDenieds'].push(officeName['denied']);
+// }
+
+// return { ...finalData, rowsForAllDisplay, officeData };
+
+// case 'office-heat-map':
+// rowsForTable = [];
+// for (let yearResults of data[0].yearResults) {
+// for (let officeKey of officeNames) {
+// if (
+// yearResults.yearData.filter(
+// yearItem => yearItem.office === officeKey
+// ).length > 0
+// ) {
+// rowItem = {
+// 'Year [Office]':
+// String(yearResults.fiscal_year) +
+// ' [' +
+// String(officeKey) +
+// ']',
+// 'Total Cases': yearResults.yearData.filter(
+// yearItem => yearItem.office === officeKey
+// )[0].totalCases,
+// '% Granted': Number(
+// yearResults.yearData.filter(
+// yearItem => yearItem.office === officeKey
+// )[0].granted
+// ).toFixed(2),
+// '% Admin Close / Dismissal': Number(
+// yearResults.yearData.filter(
+// yearItem => yearItem.office === officeKey
+// )[0].adminClosed
+// ).toFixed(2),
+// '% Denied': Number(
+// yearResults.yearData.filter(
+// yearItem => yearItem.office === officeKey
+// )[0].denied
+// ).toFixed(2),
+// };
+// rowsForTable.push(rowItem);
+// }
+// }
+// }
+// const officeHeatMapDataObject = {
+// //declare helper object to construct data for heatmap plotly
+// x: officeNames, //office
+// y: [], //year
+// z: [], //rate
+// };
+// for (let fiscal_year in yearByOfficeByGrant) {
+// //loop through
+// officeHeatMapDataObject['y'].push(fiscal_year); //include year into y axis
+// let zAxisArray = []; //Array to hold each row for z axis
+// for (let officeName of officeNames) {
+// //loop using unique office names
+// zAxisArray.push(
+// yearByOfficeByGrant[fiscal_year][officeName]
+// ? yearByOfficeByGrant[fiscal_year][officeName]['granted']
+// : 0
+// );
+// }
+// officeHeatMapDataObject['z'].push(zAxisArray); //push to zaxis array
+// }
+// return { officeHeatMapDataObject, rowsForTable };
+
+// case 'citizenship':
+// rowsForTable = [];
+// for (let item of data[0].citizenshipResults) {
+// rowItem = {
+// Citizenship: item.citizenship,
+// 'Total Cases': item.totalCases,
+// '% Granted': Number(item.granted).toFixed(2),
+// '% Admin Close / Dismissal': Number(item.adminClosed).toFixed(2),
+// '% Denied': Number(item.denied).toFixed(2),
+// };
+// rowsForTable.push(rowItem);
+// }
+// const countryGrantRateObj = {
+// countries: [],
+// countriesPercentGranteds: [],
+// };
+// for (let country of data[0]['citizenshipResults']) {
+// countryGrantRateObj['countries'].push(country['citizenship']);
+// countryGrantRateObj['countriesPercentGranteds'].push(
+// country['granted']
+// );
+// }
+// return {
+// rowsForTable,
+// countryGrantRateObj,
+// };
+// default:
+// return {};
+// }
+// } else {
+// switch (view) {
+// case 'time-series':
+// rowsForTable = [];
+// data[0].yearResults.sort((a, b) => a.fiscal_year - b.fiscal_year);
+// for (let i = 0; i < data[0].yearResults.length; i++) {
+// if (
+// data[0].yearResults[i].yearData.filter(
+// dataItem => dataItem.office === office
+// )[0]
+// ) {
+// const officeObj = data[0].yearResults[i].yearData.filter(
+// dataItem => dataItem.office === office
+// )[0];
+// rowItem = {
+// 'Fiscal Year': data[0].yearResults[i].fiscal_year,
+// 'Total Cases': officeObj.totalCases,
+// '% Granted': Number(officeObj.granted).toFixed(2),
+// '% Admin Close / Dismissal': Number(
+// officeObj.adminClosed
+// ).toFixed(2),
+// '% Denied': Number(officeObj.denied).toFixed(2),
+// };
+// rowsForTable.push(rowItem);
+// }
+// }
+// const singleOfficeDataObject = officeData[office];
+// return {
+// rowsForTable,
+// singleOfficeDataObject,
+// };
+
+// case 'citizenship':
+// rowsForTable = [];
+// for (let item of data[0].citizenshipResults) {
+// rowItem = {
+// Citizenship: item.citizenship,
+// 'Total Cases': item.totalCases,
+// '% Granted': Number(item.granted).toFixed(2),
+// '% Admin Close / Dismissal': Number(item.adminClosed).toFixed(2),
+// '% Denied': Number(item.denied).toFixed(2),
+// };
+// rowsForTable.push(rowItem);
+// }
+// const countryGrantRateObj = {
+// countries: [],
+// countriesPercentGranteds: [],
+// };
+// for (let country of data[0]['citizenshipResults']) {
+// countryGrantRateObj['countries'].push(country['citizenship']);
+// countryGrantRateObj['countriesPercentGranteds'].push(
+// country['granted']
+// );
+// }
+// return {
+// rowsForTable,
+// countryGrantRateObj,
+// };
+// default:
+// return {};
+// }
+// }
+// };
+
+// export { rawApiDataToPlotlyReadyInfo };