Skip to content

Commit

Permalink
Merge pull request #2159 from ujh/more-generic-code
Browse files Browse the repository at this point in the history
Start making the code generic by passing in functions
  • Loading branch information
ujh authored Apr 24, 2024
2 parents 3650dad + b73bba3 commit 080ae94
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 129 deletions.
38 changes: 38 additions & 0 deletions app/javascript/src/admin/components/clustering/BrandSelector.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React, { useContext } from "react";
import Select from "react-select";
import _ from "lodash";

import { DispatchContext, StateContext } from "../../micro-clusters/GenericApp";
import { UPDATE_SELECTED_BRANDS } from "./actions";
import { setInBrandSelector } from "./keyDownListener";

export const BrandSelector = ({ field }) => {
const dispatch = useContext(DispatchContext);
const { microClusters, selectedBrands } = useContext(StateContext);
const values = _.countBy(microClusters.map((c) => c[field]));
const options = _.sortBy(
_.map(values, (value, key) => ({
value: key,
label: `${key} (${value})`
})),
"label"
);
return (
<div className="mb-3">
<Select
options={options}
onChange={(selected) => {
dispatch({ type: UPDATE_SELECTED_BRANDS, payload: selected });
}}
isMulti
value={selectedBrands}
onFocus={() => {
setInBrandSelector(true);
}}
onBlur={() => {
setInBrandSelector(false);
}}
/>
</div>
);
};
18 changes: 18 additions & 0 deletions app/javascript/src/admin/components/clustering/LoadingOverlay.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import React, { useContext } from "react";

import { StateContext } from "../../micro-clusters/GenericApp";

export const LoadingOverlay = () => {
const { updating } = useContext(StateContext);
if (!updating) return null;
const style = {
position: "fixed",
top: 0,
left: 0,
height: "100%",
width: "100%",
zIndex: 10,
backgroundColor: "rgba(0,0,0,0.5)"
};
return <div style={style}></div>;
};
13 changes: 13 additions & 0 deletions app/javascript/src/admin/components/clustering/Summary.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import React, { useContext } from "react";

import { StateContext } from "../../micro-clusters/GenericApp";

export const Summary = () => {
const { microClusters, selectedMicroClusters } = useContext(StateContext);
return (
<div className="summary">
<b>Total:</b> {microClusters.length} <b>In Selection:</b>{" "}
{selectedMicroClusters.length}
</div>
);
};
121 changes: 13 additions & 108 deletions app/javascript/src/admin/micro-clusters/App.jsx
Original file line number Diff line number Diff line change
@@ -1,111 +1,16 @@
import React, { useEffect, useReducer, useContext } from "react";
import Select from "react-select";
import _ from "lodash";

import { Spinner } from "../components/Spinner";
import { DisplayMicroClusters } from "./DisplayMicroClusters";
import { reducer, initalState } from "../components/clustering/reducer";
import { UPDATE_SELECTED_BRANDS } from "../components/clustering/actions";
import { setInBrandSelector } from "../components/clustering/keyDownListener";
import { getMacroClusters } from "./macroClusters";
import React from "react";
import { getMacroClusters, updateMacroCluster } from "./macroClusters";
import { getMicroClusters } from "./microClusters";
import { assignCluster } from "./assignCluster";

export const StateContext = React.createContext();
export const DispatchContext = React.createContext();

export const App = () => {
const [state, dispatch] = useReducer(reducer, initalState);
const { loadingMacroClusters, loadingMicroClusters } = state;
useEffect(() => {
getMicroClusters(dispatch);
}, []);
useEffect(() => {
getMacroClusters(dispatch);
}, []);
useEffect(() => {
if (
loadingMicroClusters ||
loadingMacroClusters ||
state.microClusters.length > 0
)
return;
const intervalId = setInterval(() => {
getMicroClusters(dispatch);
}, 30 * 1000);
return () => {
clearInterval(intervalId);
};
}, [loadingMicroClusters, loadingMacroClusters, state.microClusters.length]);
if (!loadingMicroClusters && !loadingMacroClusters) {
return (
<DispatchContext.Provider value={dispatch}>
<StateContext.Provider value={state}>
<div>
<LoadingOverlay />
<Summary />
<BrandSelector />
<DisplayMicroClusters />
</div>
</StateContext.Provider>
</DispatchContext.Provider>
);
} else {
return <Spinner text={`${state.loadingPercentage.toFixed(2)}%`} />;
}
};

const LoadingOverlay = () => {
const { updating } = useContext(StateContext);
if (!updating) return null;
const style = {
position: "fixed",
top: 0,
left: 0,
height: "100%",
width: "100%",
zIndex: 10,
backgroundColor: "rgba(0,0,0,0.5)"
};
return <div style={style}></div>;
};

const Summary = () => {
const { microClusters, selectedMicroClusters } = useContext(StateContext);
return (
<div className="summary">
<b>Total:</b> {microClusters.length} <b>In Selection:</b>{" "}
{selectedMicroClusters.length}
</div>
);
};
import { GenericApp } from "./GenericApp";

const BrandSelector = () => {
const dispatch = useContext(DispatchContext);
const { microClusters, selectedBrands } = useContext(StateContext);
const values = _.countBy(microClusters.map((c) => c.simplified_brand_name));
const options = _.sortBy(
_.map(values, (value, key) => ({
value: key,
label: `${key} (${value})`
})),
"label"
);
return (
<div className="mb-3">
<Select
options={options}
onChange={(selected) => {
dispatch({ type: UPDATE_SELECTED_BRANDS, payload: selected });
}}
isMulti
value={selectedBrands}
onFocus={() => {
setInBrandSelector(true);
}}
onBlur={() => {
setInBrandSelector(false);
}}
/>
</div>
);
};
export const App = () => (
<GenericApp
brandSelectorField="simplified_brand_name"
microClusterLoader={getMicroClusters}
macroClusterLoader={getMacroClusters}
macroClusterUpdater={updateMacroCluster}
assignCluster={assignCluster}
/>
);
13 changes: 7 additions & 6 deletions app/javascript/src/admin/micro-clusters/CreateRow.jsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import React, { useCallback, useContext, useEffect } from "react";
import _ from "lodash";
import { postRequest, putRequest } from "../../fetch";
import { StateContext, DispatchContext } from "./App";
import { StateContext, DispatchContext } from "./GenericApp";
import { groupedInks } from "./groupedInks";
import {
UPDATING,
ADD_MACRO_CLUSTER,
REMOVE_MICRO_CLUSTER
} from "../components/clustering/actions";
import { assignCluster } from "./assignCluster";
import { keyDownListener } from "../components/clustering/keyDownListener";

export const CreateRow = ({ afterCreate }) => {
export const CreateRow = ({ afterCreate, assignCluster }) => {
const { updating, activeCluster } = useContext(StateContext);
const dispatch = useContext(DispatchContext);
const values = computeValues(activeCluster);
Expand All @@ -20,9 +19,10 @@ export const CreateRow = ({ afterCreate }) => {
values,
activeCluster.id,
dispatch,
afterCreate
afterCreate,
assignCluster
);
}, [activeCluster.id, afterCreate, dispatch, values]);
}, [activeCluster.id, afterCreate, dispatch, values, assignCluster]);
const ignore = () => {
ignoreCluster(activeCluster).then(
dispatch({ type: REMOVE_MICRO_CLUSTER, payload: activeCluster })
Expand Down Expand Up @@ -89,7 +89,8 @@ const createMacroClusterAndAssign = (
values,
microClusterId,
dispatch,
afterCreate
afterCreate,
assignCluster
) => {
dispatch({ type: UPDATING });
setTimeout(() => {
Expand Down
21 changes: 14 additions & 7 deletions app/javascript/src/admin/micro-clusters/DisplayMacroClusters.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import levenshtein from "fast-levenshtein";
import ScrollIntoViewIfNeeded from "react-scroll-into-view-if-needed";
import { matchSorter } from "match-sorter";

import { assignCluster } from "./assignCluster";
import { CollectedInksList } from "./CollectedInksList";
import { SearchLink } from "../components/clustering/SearchLink";
import { StateContext, DispatchContext } from "./App";
import { StateContext, DispatchContext } from "./GenericApp";
import {
ASSIGN_TO_MACRO_CLUSTER,
NEXT_MACRO_CLUSTER,
Expand All @@ -20,18 +19,20 @@ import {
} from "../components/clustering/keyDownListener";
import { useCallback } from "react";

export const DisplayMacroClusters = ({ afterAssign }) => {
export const DisplayMacroClusters = ({ afterAssign, assignCluster }) => {
const dispatch = useContext(DispatchContext);
useEffect(() => {
return keyDownListener(({ keyCode }) => {
if (keyCode == 74) dispatch({ type: NEXT_MACRO_CLUSTER });
if (keyCode == 75) dispatch({ type: PREVIOUS_MACRO_CLUSTER });
});
}, [dispatch]);
return <MacroClusterRows afterAssign={afterAssign} />;
return (
<MacroClusterRows afterAssign={afterAssign} assignCluster={assignCluster} />
);
};

const MacroClusterRows = ({ afterAssign }) => {
const MacroClusterRows = ({ afterAssign, assignCluster }) => {
const {
macroClusters,
activeCluster,
Expand Down Expand Up @@ -73,6 +74,7 @@ const MacroClusterRows = ({ afterAssign }) => {
key={macroCluster.id}
macroCluster={macroCluster}
afterAssign={afterAssign}
assignCluster={assignCluster}
selected={index == selectedMacroClusterIndex}
/>
));
Expand Down Expand Up @@ -165,7 +167,12 @@ const stripped = (str) => {
.replace(/\s+/i, "");
};

const MacroClusterRow = ({ macroCluster, afterAssign, selected }) => {
const MacroClusterRow = ({
macroCluster,
afterAssign,
selected,
assignCluster
}) => {
const { activeCluster, updating } = useContext(StateContext);
const dispatch = useContext(DispatchContext);
const [showInks, setShowInks] = useState(false);
Expand All @@ -181,7 +188,7 @@ const MacroClusterRow = ({ macroCluster, afterAssign, selected }) => {
afterAssign(microCluster);
});
}, 10);
}, [activeCluster.id, afterAssign, dispatch, macroCluster.id]);
}, [activeCluster.id, afterAssign, dispatch, macroCluster.id, assignCluster]);
useEffect(() => {
if (!selected) return;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React, { useContext } from "react";

import { StateContext } from "./App";
import { StateContext } from "./GenericApp";
import { DisplayMacroClusters } from "./DisplayMacroClusters";
import { CollectedInksList } from "./CollectedInksList";
import { CreateRow } from "./CreateRow";

export const DisplayMicroCluster = ({ afterCreate }) => {
export const DisplayMicroCluster = ({ afterCreate, assignCluster }) => {
const { activeCluster } = useContext(StateContext);
return (
<div className="fpc-table fpc-table--full-width fpc-scroll-shadow">
Expand All @@ -18,7 +18,10 @@ export const DisplayMicroCluster = ({ afterCreate }) => {
<tr>
<td colSpan="8" style={{ backgroundColor: "black" }}></td>
</tr>
<DisplayMacroClusters afterAssign={afterCreate} />
<DisplayMacroClusters
afterAssign={afterCreate}
assignCluster={assignCluster}
/>
</tbody>
</table>
</div>
Expand Down
15 changes: 10 additions & 5 deletions app/javascript/src/admin/micro-clusters/DisplayMicroClusters.jsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,26 @@
import React, { useEffect, useContext } from "react";

import { DisplayMicroCluster } from "./DisplayMicroCluster";
import { DispatchContext, StateContext } from "./App";
import { DispatchContext, StateContext } from "./GenericApp";
import {
PREVIOUS,
NEXT,
REMOVE_MICRO_CLUSTER
} from "../components/clustering/actions";
import { keyDownListener } from "../components/clustering/keyDownListener";
import { useCallback } from "react";
import { updateMacroCluster } from "./macroClusters";

export const DisplayMicroClusters = () => {
export const DisplayMicroClusters = ({
macroClusterUpdater,
assignCluster
}) => {
const dispatch = useContext(DispatchContext);
const { activeCluster } = useContext(StateContext);
const { prev, next } = useNavigation(dispatch);
const afterAssign = (newClusterData) => {
dispatch({ type: REMOVE_MICRO_CLUSTER, payload: newClusterData });
const id = newClusterData.macro_cluster.id;
updateMacroCluster(id, dispatch);
macroClusterUpdater(id, dispatch);
};
if (activeCluster) {
return (
Expand All @@ -27,7 +29,10 @@ export const DisplayMicroClusters = () => {
<i className="fa fa-angle-left"></i>
</div>
<div className="main">
<DisplayMicroCluster afterCreate={afterAssign}></DisplayMicroCluster>
<DisplayMicroCluster
afterCreate={afterAssign}
assignCluster={assignCluster}
></DisplayMicroCluster>
</div>
<div className="nav" onClick={next}>
<i className="fa fa-angle-right"></i>
Expand Down
Loading

0 comments on commit 080ae94

Please sign in to comment.