Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2907 range slider component #2938

Draft
wants to merge 36 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
803b21c
Add range slider component using react-slider
maiyerlee Oct 11, 2024
2377b24
Add fieldset tags to slider
maiyerlee Oct 11, 2024
54e82c7
Fix key warnings
maiyerlee Oct 11, 2024
3d7d7c4
Add FY budget combo box component
maiyerlee Oct 11, 2024
590c995
Add FY budget range calculation
maiyerlee Oct 11, 2024
767b608
refactor: adds handleChange logix (#2925)
fpigeonjr Oct 14, 2024
974ce75
Merge branch 'main' into 2907-range-slider-component
fpigeonjr Oct 16, 2024
4f50a34
deps: adds react-slider and styled-components
fpigeonjr Oct 16, 2024
16a8a43
style: adds UX fixes
fpigeonjr Oct 16, 2024
425b34a
refactor: better var names
fpigeonjr Oct 16, 2024
8e54797
filtering is kinda working
fpigeonjr Oct 16, 2024
9e03fd5
Merge branch 'main' into 2907-range-slider-component
fpigeonjr Oct 16, 2024
b0a4c15
chore: updates deps
fpigeonjr Oct 16, 2024
52e27e4
Merge branch 'main' into 2907-range-slider-component
fpigeonjr Oct 16, 2024
162e953
chore: updates deps
fpigeonjr Oct 16, 2024
e1a7a0a
wip (#2944)
fpigeonjr Oct 17, 2024
bbff0d9
wip: fix range text and FY values (#2946)
maiyerlee Oct 17, 2024
e1b856d
refactor: raises and persists budget state
fpigeonjr Oct 17, 2024
7a2a802
refactor: better state
fpigeonjr Oct 17, 2024
69e215d
docs: adds JSDocs
fpigeonjr Oct 17, 2024
01c571e
fix: fixes reset
fpigeonjr Oct 17, 2024
8ae6575
refactor: adds helper fns
fpigeonjr Oct 17, 2024
6d0c622
chore: cleanup
fpigeonjr Oct 17, 2024
08d5fd3
Merge branch 'main' into 2907-range-slider-component
fpigeonjr Oct 17, 2024
e38554a
chore: adds deps
fpigeonjr Oct 17, 2024
10c9221
test: builds
fpigeonjr Oct 18, 2024
301ff78
wip: bring back the linting
fpigeonjr Oct 18, 2024
41a679a
chore: install deps
fpigeonjr Oct 18, 2024
421239a
style: match icon color on disable state
fpigeonjr Oct 18, 2024
7d54126
style: TBD for 0 value FY Budgets
fpigeonjr Oct 18, 2024
9e81076
docs: adds JSDocs annotations
fpigeonjr Oct 18, 2024
760f932
feat: adds pills
fpigeonjr Oct 18, 2024
6696e09
chore: cleanup
fpigeonjr Oct 18, 2024
cc232c2
refactor: remove unneeded state
fpigeonjr Oct 18, 2024
dd60727
refactor: resets budget state
fpigeonjr Oct 18, 2024
ecc556c
chore: cleanup
fpigeonjr Oct 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion frontend/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ WORKDIR /home/app

COPY --chown=app:app ./package.json ./bun.lockb /home/app/

RUN bun install --production --frozen-lockfile
# RUN bun install --production --frozen-lockfile
RUN bun install

COPY --chown=app:app index.html /home/app/
COPY --chown=app:app src /home/app/src
Expand Down
Binary file modified frontend/bun.lockb
Binary file not shown.
218 changes: 110 additions & 108 deletions frontend/package.json
Original file line number Diff line number Diff line change
@@ -1,111 +1,113 @@
{
"name": "opre-ops",
"version": "1.0.1",
"license": "CC0-1.0",
"private": true,
"type": "module",
"dependencies": {
"@azure/storage-blob": "^12.24.0",
"@fortawesome/fontawesome-svg-core": "6.5.2",
"@fortawesome/free-regular-svg-icons": "6.5.2",
"@fortawesome/free-solid-svg-icons": "6.5.2",
"@fortawesome/react-fontawesome": "0.2.2",
"@nivo/bar": "0.87.0",
"@nivo/core": "0.87.0",
"@nivo/pie": "0.87.0",
"@reduxjs/toolkit": "2.2.8",
"@uswds/uswds": "3.9.0",
"axios": "1.7.7",
"clsx": "2.1.1",
"crypto-random-string": "5.0.0",
"js-cookie": "3.0.5",
"jwt-decode": "4.0.0",
"lodash": "4.17.21",
"react": "18.3.1",
"react-currency-format": "1.1.0",
"react-dom": "18.3.1",
"react-markdown": "9.0.1",
"react-modal": "3.16.1",
"react-redux": "9.1.2",
"react-router-dom": "6.27.0",
"react-select": "5.8.1",
"sass": "1.79.6",
"sass-loader": "14.2.1",
"vest": "5.4.3",
"@eslint/compat": "1.2.0",
"@eslint/js": "9.12.0",
"@vitejs/plugin-react": "4.3.2",
"eslint": "9.12.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-cypress": "4.0.0",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-jest": "28.8.3",
"eslint-plugin-jsx-a11y": "6.10.0",
"eslint-plugin-prettier": "5.2.1",
"eslint-plugin-react": "7.37.1",
"eslint-plugin-react-hooks": "5.0.0",
"eslint-plugin-react-refresh": "0.4.12",
"eslint-plugin-testing-library": "6.3.2",
"jose": "5.9.4",
"jsdom": "25.0.1",
"vite": "5.4.9",
"vite-jsconfig-paths": "2.0.1",
"vite-plugin-babel-macros": "1.0.6",
"vite-plugin-eslint": "1.8.1",
"vite-plugin-svgr": "4.2.0"
},
"overrides": {
"rollup": "4.24.0"
},
"devDependencies": {
"@testing-library/jest-dom": "6.5.0",
"@testing-library/react": "16.0.1",
"@testing-library/user-event": "14.5.2",
"@types/testing-library__jest-dom": "6.0.0",
"@types/testing-library__react": "10.2.0",
"@vitest/coverage-istanbul": "2.1.3",
"@vitest/ui": "2.1.3",
"axe-core": "4.10.1",
"cypress": "13.13.3",
"cypress-axe": "1.5.0",
"cypress-localstorage-commands": "2.2.6",
"globals": "15.9.0",
"history": "5.3.0",
"msw": "2.3.5",
"prettier": "3.3.3",
"redux-mock-store": "1.5.4",
"@uswds/compile": "1.2.0",
"vitest": "2.1.3"
},
"scripts": {
"start": "vite",
"start:debug": "vite --inspect=0.0.0.0:9229",
"build": "vite build",
"test": "vitest",
"test:coverage": "vitest --coverage",
"test:ui": "vitest --ui --coverage.enabled=true",
"test:e2e:interactive": "cypress open --config-file ./cypress.config.js",
"test:e2e": "cypress run --config-file ./cypress.config.js --headless",
"test:e2e:debug": "DEBUG=cypress:* cypress run --config-file ./cypress.config.js --headless",
"lint": "eslint './src/**'",
"cypress:open": "cypress open",
"uswds:update": "bunx gulp compile"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"babelMacros": {
"fontawesome-svg-core": {
"license": "free"
"name": "opre-ops",
"version": "1.0.1",
"license": "CC0-1.0",
"private": true,
"type": "module",
"dependencies": {
"@azure/storage-blob": "12.24.0",
"@eslint/compat": "1.2.0",
"@eslint/js": "9.12.0",
"@fortawesome/fontawesome-svg-core": "6.5.2",
"@fortawesome/free-regular-svg-icons": "6.5.2",
"@fortawesome/free-solid-svg-icons": "6.5.2",
"@fortawesome/react-fontawesome": "0.2.2",
"@nivo/bar": "0.87.0",
"@nivo/core": "0.87.0",
"@nivo/pie": "0.87.0",
"@reduxjs/toolkit": "2.2.8",
"@uswds/uswds": "3.9.0",
"@vitejs/plugin-react": "4.3.2",
"axios": "1.7.7",
"clsx": "2.1.1",
"crypto-random-string": "5.0.0",
"eslint": "9.12.0",
"eslint-config-prettier": "9.1.0",
"eslint-plugin-cypress": "4.0.0",
"eslint-plugin-import": "2.29.1",
"eslint-plugin-jest": "28.8.3",
"eslint-plugin-jsx-a11y": "6.10.0",
"eslint-plugin-prettier": "5.2.1",
"eslint-plugin-react": "7.37.1",
"eslint-plugin-react-hooks": "5.0.0",
"eslint-plugin-react-refresh": "0.4.12",
"eslint-plugin-testing-library": "6.3.2",
"jose": "5.9.4",
"js-cookie": "3.0.5",
"jsdom": "25.0.1",
"jwt-decode": "4.0.0",
"lodash": "4.17.21",
"react": "18.3.1",
"react-currency-format": "1.1.0",
"react-dom": "18.3.1",
"react-markdown": "9.0.1",
"react-modal": "3.16.1",
"react-redux": "9.1.2",
"react-router-dom": "6.27.0",
"react-select": "5.8.1",
"react-slider": "2.0.6",
"sass": "1.79.6",
"sass-loader": "14.2.1",
"styled-components": "6.1.13",
Copy link
Contributor Author

Choose a reason for hiding this comment

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

may consider removing this dependency in favor of css modules

"vest": "5.4.3",
"vite": "5.4.9",
"vite-jsconfig-paths": "2.0.1",
"vite-plugin-babel-macros": "1.0.6",
"vite-plugin-eslint": "1.8.1",
"vite-plugin-svgr": "4.2.0"
},
"overrides": {
"rollup": "4.24.0"
},
"devDependencies": {
"@testing-library/jest-dom": "6.5.0",
"@testing-library/react": "16.0.1",
"@testing-library/user-event": "14.5.2",
"@types/testing-library__jest-dom": "6.0.0",
"@types/testing-library__react": "10.2.0",
"@vitest/coverage-istanbul": "2.1.3",
"@vitest/ui": "2.1.3",
"axe-core": "4.10.1",
"cypress": "13.13.3",
"cypress-axe": "1.5.0",
"cypress-localstorage-commands": "2.2.6",
"globals": "15.9.0",
"history": "5.3.0",
"msw": "2.3.5",
"prettier": "3.3.3",
"redux-mock-store": "1.5.4",
"@uswds/compile": "1.2.0",
"vitest": "2.1.3"
},
"scripts": {
"start": "vite",
"start:debug": "vite --inspect=0.0.0.0:9229",
"build": "vite build",
"test": "vitest",
"test:coverage": "vitest --coverage",
"test:ui": "vitest --ui --coverage.enabled=true",
"test:e2e:interactive": "cypress open --config-file ./cypress.config.js",
"test:e2e": "cypress run --config-file ./cypress.config.js --headless",
"test:e2e:debug": "DEBUG=cypress:* cypress run --config-file ./cypress.config.js --headless",
"lint": "eslint './src/**'",
"cypress:open": "cypress open",
"uswds:update": "bunx gulp compile"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"babelMacros": {
"fontawesome-svg-core": {
"license": "free"
}
}
}
}
3 changes: 2 additions & 1 deletion frontend/src/api/opsAPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ export const opsApi = createApi({
"ServicesComponents",
"ChangeRequests",
"Divisions",
"Documents"
"Documents",
"Cans"
],
baseQuery: fetchBaseQuery({
baseUrl: `${BACKEND_DOMAIN}/api/v1/`,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React from "react";
import DoubleRangeSlider from "../../UI/DoubleRangeSlider";
import CurrencyFormat from "react-currency-format";
/**
* @typedef {Object} CANFYBudgetRangeSliderProps
* @property {[number, number]} fyBudgetRange - The min and max of the fiscal year budget range
* @property {string} [legendClassname] - CSS class for the legend
* @property {[number, number]} budget - The current budget range
* @property {function([number, number]): void} setBudget - Function to update the budget
*/

/**
* @description CANFYBudgetRangeSlider component
* @component
* @param {CANFYBudgetRangeSliderProps} props
* @returns {JSX.Element} - The CAN FY Budget Range Slider component
*/
const CANFYBudgetRangeSlider = ({ fyBudgetRange, legendClassname = "usa-label margin-top-0", budget, setBudget }) => {
const [minValue, maxValue] = budget;
const [fyBudgetMin, fyBudgetMax] = fyBudgetRange;
const [sliderValue, setSliderValue] = React.useState([0, 100]);
/**
* Calculate percentage of a value within a range
* @param {number} value - The value to calculate percentage for
* @param {number} min - The minimum value of the range
* @param {number} max - The maximum value of the range
* @returns {number} The calculated percentage
*/
const calculatePercentage = (value, min, max) => {
return ((value - min) / (max - min)) * 100;
};
/**
* Calculate value based on percentage within a range
* @param {number} percentage - The percentage to calculate value for
* @param {number} min - The minimum value of the range
* @param {number} max - The maximum value of the range
* @returns {number} The calculated value
*/
const calculateValue = (percentage, min, max) => {
return Math.round(min + (percentage / 100) * (max - min));
};

/**
* Calculate the new budget range based on slider values
* @param {[number, number]} newRange - The new range from the slider
*/
const calculateBudgetRange = (newRange) => {
const [minPercentage, maxPercentage] = newRange;
const selectedMinFYBudget = calculateValue(minPercentage, fyBudgetMin, fyBudgetMax);
const selectedMaxFYBudget = calculateValue(maxPercentage, fyBudgetMin, fyBudgetMax);

setBudget([selectedMinFYBudget, selectedMaxFYBudget]);
setSliderValue(newRange);
};

React.useEffect(() => {
const minPercentage = calculatePercentage(minValue, fyBudgetMin, fyBudgetMax);
const maxPercentage = calculatePercentage(maxValue, fyBudgetMin, fyBudgetMax);

setSliderValue([minPercentage, maxPercentage]);
}, [budget, fyBudgetRange]);

return (
<>
<div className="display-flex flex-justify">
<label
className={legendClassname}
htmlFor="can-FY-budgey-combobox-input"
>
FY Budget
</label>
</div>
<div className="padding-right-10">
<DoubleRangeSlider
handleChange={calculateBudgetRange}
defaultValue={[0, 100]}
value={sliderValue}
/>
</div>

<div className="margin-top-1 display-flex flex-justify-center font-12px padding-right-10">
<span>
<CurrencyFormat
value={minValue}
decimalScale={2}
thousandSeparator={true}
displayType="text"
prefix={"$ "}
/>
<span> - </span>
<CurrencyFormat
value={maxValue}
decimalScale={2}
thousandSeparator={true}
displayType="text"
prefix={"$ "}
/>
</span>
</div>
</>
);
};

export default CANFYBudgetRangeSlider;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from "./CANFYBudgetRangeSlider.jsx";
9 changes: 2 additions & 7 deletions frontend/src/components/CANs/CANTable/CANTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,10 @@ import styles from "./style.module.css";
* @returns {JSX.Element}
*/
const CANTable = ({ cans, fiscalYear }) => {
// Filter CANs by fiscal year
const filteredCANsByFiscalYear = React.useMemo(() => {
if (!fiscalYear) return cans;
return cans.filter((can) => can.funding_details.fiscal_year === fiscalYear);
}, [cans, fiscalYear]);
// TODO: once in prod, change this to 25
const CANS_PER_PAGE = 10;
const [currentPage, setCurrentPage] = React.useState(1);
let cansPerPage = [...filteredCANsByFiscalYear];
let cansPerPage = [...cans];
cansPerPage = cansPerPage.slice((currentPage - 1) * CANS_PER_PAGE, currentPage * CANS_PER_PAGE);

if (cansPerPage.length === 0) {
Expand Down Expand Up @@ -52,7 +47,7 @@ const CANTable = ({ cans, fiscalYear }) => {
))}
</tbody>
</table>
{filteredCANsByFiscalYear.length > CANS_PER_PAGE && (
{cans.length > CANS_PER_PAGE && (
<PaginationNav
currentPage={currentPage}
setCurrentPage={setCurrentPage}
Expand Down
Loading