diff --git a/frontend/src/main-page/dashboard/Charts/BarYearGrantStatus.tsx b/frontend/src/main-page/dashboard/Charts/BarYearGrantStatus.tsx index e25267c..821a6ec 100644 --- a/frontend/src/main-page/dashboard/Charts/BarYearGrantStatus.tsx +++ b/frontend/src/main-page/dashboard/Charts/BarYearGrantStatus.tsx @@ -47,12 +47,12 @@ const BarYearGrantStatus = observer( .sort((a, b) => b.value - a.value); return ( -
+
{/* Title */} -
- Year Grant Status +
+ Grant Status
{/* Year */}
{recentYear}
@@ -77,20 +77,20 @@ const BarYearGrantStatus = observer(
- + - - typeof label === "number" ? checked diff --git a/frontend/src/main-page/dashboard/Charts/DonutMoneyApplied.tsx b/frontend/src/main-page/dashboard/Charts/DonutMoneyApplied.tsx index 595164b..75b9ac5 100644 --- a/frontend/src/main-page/dashboard/Charts/DonutMoneyApplied.tsx +++ b/frontend/src/main-page/dashboard/Charts/DonutMoneyApplied.tsx @@ -4,8 +4,12 @@ import { aggregateMoneyGrantsByYear, YearAmount } from "../grantCalculations"; import "../styles/Dashboard.css"; import { Grant } from "../../../../../middle-layer/types/Grant"; import { getListApplied } from "../../../../../middle-layer/types/Status"; +import { FaCircle } from "react-icons/fa"; +import { useState } from "react"; const DonutMoneyApplied = observer(({ grants }: { grants: Grant[] }) => { + const [width, setWidth] = useState(0); + // Helper to sum values for given statuses const sumByStatus = (data: Record, statuses: string[]) => Object.entries(data) @@ -18,7 +22,7 @@ const DonutMoneyApplied = observer(({ grants }: { grants: Grant[] }) => { year: grant.year.toString(), received: sumByStatus(grant.data, getListApplied(true)), unreceived: sumByStatus(grant.data, getListApplied(false)), - }) + }), ); // Summing values across years @@ -27,86 +31,76 @@ const DonutMoneyApplied = observer(({ grants }: { grants: Grant[] }) => { sumR + received, sumU + unreceived, ], - [0, 0] + [0, 0], ); const total = sumReceived + sumUnreceived; const data = [ - { name: "Received", value: sumReceived, fill: "var(--color-yellow)"}, - { name: "Unreceived", value: sumUnreceived, fill: "var(--color-primary-800)" }, + { name: "Received", value: sumReceived, fill: "var(--color-primary-900)" }, + { + name: "Unreceived", + value: sumUnreceived, + fill: "var(--color-primary-700)", + }, ]; // Creating the label for the slices const LabelItem = ({ name, - value, percent, color, }: { name: string; - value: number; percent: number; color: string; }) => { return ( -
-
{name}
-
-
- {`${(percent * 100).toFixed(0)}% ($${(value / 1_000_000).toFixed( - 2 - )}M)`} +
+ +
+ {`${(percent * 100).toFixed(0)}%`} {name}
); }; return ( -
-
+
+
250 ? "mb-0" : "mb-14"}`}> {/* Title */} -
- Money Applied For {/* Total Amount */} -
+
+ Money Applied All Time {/* Total Amount */} +
{`$${((sumReceived + sumUnreceived) / 1000000).toLocaleString( "en-us", { maximumFractionDigits: 2, - } + }, )}M`}
- {/* Floating Right Label */} - {sumUnreceived > 0 && ( -
+
250 ? "mt-12" : "mt-2"}`}> + +
- )} - {/* Floating Left Label */} - {sumReceived > 0 && ( -
- -
- )} +
- + setWidth(w)} + > 250 ? 150 : 0, bottom: 0 }} > { endAngle={450} dataKey="value" nameKey="name" - innerRadius="60%" + innerRadius="55%" outerRadius="80%" cornerRadius={50} stroke="white" diff --git a/frontend/src/main-page/dashboard/Charts/GanttYearGrantTimeline.tsx b/frontend/src/main-page/dashboard/Charts/GanttYearGrantTimeline.tsx index 847169a..a7af8e0 100644 --- a/frontend/src/main-page/dashboard/Charts/GanttYearGrantTimeline.tsx +++ b/frontend/src/main-page/dashboard/Charts/GanttYearGrantTimeline.tsx @@ -116,7 +116,7 @@ export const GanttYearGrantTimeline = observer( // Filtering events that are included in current date range // Example can be also found on video https://youtu.be/9oy4rTVEfBQ?t=118&si=52BGKSIYz6bTZ7fx // and in the react-scheduler repo App.tsx file https://github.com/Bitnoise/react-scheduler/blob/master/src/App.tsx - const filteredMockedSchedulerData = data.map((grant) => ({ + const filteredSchedulerData = data.map((grant) => ({ ...grant, data: grant.data.filter((project) => { const startInRange = @@ -140,10 +140,10 @@ export const GanttYearGrantTimeline = observer( })); return ( -
+
{/* Title */} -
- Year Grant Timeline +
+ Grant Timeline
{/* Year */}
@@ -152,9 +152,9 @@ export const GanttYearGrantTimeline = observer( : ""} {recentYear}
-
+
{ return ( -
+
{/* Title */} -
{title}
- +
{title}
+
{formattedValue}
{/* Value and Percent Change */} -
-
- {formattedValue} -
- +
{priorYear && ( -
- {percentChange >= 0 - ? `+${percentChange.toFixed(0)}%` - : `-${Math.abs(percentChange).toFixed(0)}%`} - {percentChange >= 0 ? ( - - ) : ( - +
+ {percentChange === 0 && ( + + - + {` 0%`} + + )} + {percentChange > 0 && ( + + + {`${percentChange.toFixed(0)}%`} + + )} -
+ {percentChange < 0 && ( + + + {`${Math.abs(percentChange).toFixed(0)}%`} + + )} +
)} -
- - {/* Year comparison at bottom */} -
- {recentYear} - {priorYear ? ` vs. ${priorYear}` : ""} + {/* Year comparison at bottom */} +
+ {recentYear} + {priorYear ? ` vs. ${priorYear}` : ""} +
); - } + }, ); export default KPICard; diff --git a/frontend/src/main-page/dashboard/Charts/LineChartSuccessRate.tsx b/frontend/src/main-page/dashboard/Charts/LineChartSuccessRate.tsx index e99f451..774e29a 100644 --- a/frontend/src/main-page/dashboard/Charts/LineChartSuccessRate.tsx +++ b/frontend/src/main-page/dashboard/Charts/LineChartSuccessRate.tsx @@ -1,4 +1,4 @@ -import React from "react"; +import React, { useState } from "react"; import { LineChart, Line, @@ -27,6 +27,8 @@ const LineChartSuccessRate = observer(({ grants }: { grants: Grant[] }) => { const moneyReceived = getListApplied(true); const moneyUnreceived = getListApplied(false); + const [width, setWidth] = useState(0); + // Formatting money data const data_money = aggregateMoneyGrantsByYear(grants, "status").map( (grant: YearAmount) => { @@ -46,7 +48,7 @@ const LineChartSuccessRate = observer(({ grants }: { grants: Grant[] }) => { date: new Date(`${grant.year}-01-03`), money_captured: Number(captured.toFixed(2)), }; - } + }, ); // Formatting count data @@ -68,13 +70,13 @@ const LineChartSuccessRate = observer(({ grants }: { grants: Grant[] }) => { date: new Date(`${grant.year}-01-04`), grants_captured: Number(captured.toFixed(2)), }; - } + }, ); // Merging the data into format for chart const data = data_money.map((moneyItem) => { const countItem = data_count.find( - (c) => c.date.getFullYear() === moneyItem.date.getFullYear() + (c) => c.date.getFullYear() === moneyItem.date.getFullYear(), ); return { date: moneyItem.date, @@ -87,57 +89,64 @@ const LineChartSuccessRate = observer(({ grants }: { grants: Grant[] }) => { data.sort((a, b) => a.date.getTime() - b.date.getTime()); return ( -
+
{/* Title */} -
+
Success Rate by Year
setWidth(w)} > - - > - | Iterable - | React.ReactPortal - | null - | undefined - ) => ( - - {value} - - )} + {width > 400 && ( + 500 ? "right" :"center"} + layout={width > 500 ? "horizontal" :"vertical"} + wrapperStyle={{ top: 0, right: "5%" }} + formatter={( + value: + | string + | number + | boolean + | React.ReactElement< + any, + string | React.JSXElementConstructor + > + | Iterable + | React.ReactPortal + | null + | undefined, + ) => ( + + {value} + + )} + /> + )} + - { { domain={["auto", "auto"]} scale="time" dy={10} + style={{ fontSize: "var(--font-size-sm)" }} tickFormatter={(date: Date) => date.getFullYear().toString()} axisLine={false} tickLine={false} diff --git a/frontend/src/main-page/dashboard/Charts/StackedBarMoneyReceived.tsx b/frontend/src/main-page/dashboard/Charts/StackedBarMoneyReceived.tsx index 4d858fe..4161ffe 100644 --- a/frontend/src/main-page/dashboard/Charts/StackedBarMoneyReceived.tsx +++ b/frontend/src/main-page/dashboard/Charts/StackedBarMoneyReceived.tsx @@ -1,10 +1,9 @@ -import React from "react"; +import React, { useState } from "react"; import { BarChart, Bar, CartesianGrid, XAxis, - YAxis, Tooltip, Legend, ResponsiveContainer, @@ -20,6 +19,8 @@ const StackedBarMoneyReceived = observer(({ grants }: { grants: Grant[] }) => { // Wrap Legend with a React component type to satisfy JSX typing const LegendComp = Legend as unknown as React.ComponentType; + const [width, setWidth] = useState(0); + // Formatting data for chart const data = aggregateMoneyGrantsByYear(grants, "status").map( (grant: YearAmount) => { @@ -36,96 +37,104 @@ const StackedBarMoneyReceived = observer(({ grants }: { grants: Grant[] }) => { received, unreceived, }; - } + }, ); return ( -
+
{/* Title */} -
+
Money Received by Year
- + setWidth(w)} + > - - > - | Iterable - | React.ReactPortal - | null - | undefined - ) => ( - - {value} - - )} + {width > 210 && ( + + > + | Iterable + | React.ReactPortal + | null + | undefined, + ) => ( + {value} + )} + /> + )} + - + {width > 210 && ( typeof label === "number" && label > 0 - ? `$${label / 1000}k` + ? `${(label / 1000000).toFixed(1)}M` : "" } - /> + />)} + {width > 210 && ( typeof label === "number" && label > 0 - ? `$${label / 1000}k` + ? `${(label / 1000000).toFixed(1)}M` : "" } - /> + />)} - - `$${value / 1000}k`} + style={{ fontSize: "var(--font-size-xs)" }} /> + { return ( ); }); diff --git a/frontend/src/main-page/dashboard/Dashboard.tsx b/frontend/src/main-page/dashboard/Dashboard.tsx index 172b7e3..293cb38 100644 --- a/frontend/src/main-page/dashboard/Dashboard.tsx +++ b/frontend/src/main-page/dashboard/Dashboard.tsx @@ -36,8 +36,8 @@ const Dashboard = observer(() => { new Set( yearFilter && yearFilter?.length > 0 ? yearFilter - : allGrants.map((g) => new Date(g.application_deadline).getFullYear()) - ) + : allGrants.map((g) => new Date(g.application_deadline).getFullYear()), + ), ).sort((a, b) => b - a); const recentYear = uniqueYears[0]; @@ -45,41 +45,52 @@ const Dashboard = observer(() => { const { grants } = ProcessGrantData(); - return(
-
- - + return ( +
+
+
Dashboard
+ + +
+ +
+ {/* ROW 1 */} +
+ +
+ +
+ +
+ +
+ +
+ + {/* ROW 2 */} +
+ +
+ +
+
-
-
- -
-
- -
-
- -
-
- -
-
- -
-
- -
+ {/* ROW 3 (Scrollable) */} +
+
-
) +
+
+ ); }); export default Dashboard; diff --git a/frontend/src/main-page/dashboard/DateFilter.tsx b/frontend/src/main-page/dashboard/DateFilter.tsx index bf8d6a1..7fcb8b9 100644 --- a/frontend/src/main-page/dashboard/DateFilter.tsx +++ b/frontend/src/main-page/dashboard/DateFilter.tsx @@ -3,6 +3,8 @@ import { updateYearFilter } from "../../external/bcanSatchel/actions"; import { getAppStore } from "../../external/bcanSatchel/store"; import { observer } from "mobx-react-lite"; import { FaChevronDown } from "react-icons/fa"; +import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import { faXmark } from "@fortawesome/free-solid-svg-icons"; const DateFilter: React.FC = observer(() => { const { allGrants, yearFilter } = getAppStore(); @@ -11,8 +13,8 @@ const DateFilter: React.FC = observer(() => { // Generate unique years dynamically from grants const uniqueYears = Array.from( new Set( - allGrants.map((g) => new Date(g.application_deadline).getFullYear()) - ) + allGrants.map((g) => new Date(g.application_deadline).getFullYear()), + ), ).sort((a, b) => a - b); // Initialize selection from store or fallback to all years @@ -49,32 +51,42 @@ const DateFilter: React.FC = observer(() => { }; return ( -
+
+
    {uniqueYears.map((year) => (
  • -
    +
    { @@ -92,7 +104,9 @@ const DateFilter: React.FC = observer(() => { ))}

- +
); diff --git a/frontend/src/main-page/dashboard/styles/Dashboard.css b/frontend/src/main-page/dashboard/styles/Dashboard.css index 3d51d03..f22c0ac 100644 --- a/frontend/src/main-page/dashboard/styles/Dashboard.css +++ b/frontend/src/main-page/dashboard/styles/Dashboard.css @@ -47,7 +47,7 @@ input[type="checkbox"]:checked::before { display: flex; flex-direction: column; justify-content: flex-start; - background-color: var(--color-tan); + background-color: var(--color-grey-200); width: 100%; height: 100%; overflow-y: auto; @@ -59,11 +59,9 @@ input[type="checkbox"]:checked::before { display: flex; flex-direction: column; justify-content: flex-start; - align-items: center; - padding: 24px; + padding: 1.2rem; background-color: white; - border-radius: 1.2rem; - border: 0.1rem solid black; + border-radius: 0.8rem; } .tooltip { @@ -83,6 +81,22 @@ input[type="checkbox"]:checked::before { border: 1px solid lightgray; } +.dashboard-button { + color: black; + /* Shape and layout */ + border-radius: 0.6rem; + padding: 0.5rem 0.8rem; + align-items: center; + cursor: pointer; + height: 1.75rem; + font-size: var(--font-size-base); + transition: opacity 0.2s ease-in-out; +} + +.dashboard-button:hover { + opacity: 0.8; +} + #reactSchedulerOutsideWrapper { overflow: hidden; } @@ -101,3 +115,7 @@ input[type="checkbox"]:checked::before { #reactSchedulerOutsideWrapper svg { fill: darkslategray; } + +#reactSchedulerOutsideWrapper input:focus { + outline: 0px none; +} diff --git a/frontend/src/main-page/grants/grant-details/CostBenefitAnalysis.tsx b/frontend/src/main-page/grants/grant-details/CostBenefitAnalysis.tsx index f860209..1e416f7 100644 --- a/frontend/src/main-page/grants/grant-details/CostBenefitAnalysis.tsx +++ b/frontend/src/main-page/grants/grant-details/CostBenefitAnalysis.tsx @@ -68,7 +68,7 @@ export const CostBenefitAnalysis: React.FC = ({ grant placeholder="Enter rate" value={hourlyRate} onChange={(e) => setHourlyRate(e.target.value)} - className="w-full h-[42px] px-3 py-4 border border-gray-400 rounded-md bg-tan" + className="w-full h-[42px] px-3 py-4 border border-gray-400 rounded-md bg-grey-200" />
@@ -85,7 +85,7 @@ export const CostBenefitAnalysis: React.FC = ({ grant console.log('Time per report changed to:', e.target.value); setTimePerReport(e.target.value); }} - className="w-full h-[42px] px-3 py-4 border border-gray-400 rounded-md bg-tan" + className="w-full h-[42px] px-3 py-4 border border-gray-400 rounded-md bg-grey-200" />
@@ -102,7 +102,7 @@ export const CostBenefitAnalysis: React.FC = ({ grant Net Benefit:
diff --git a/frontend/src/main-page/grants/grant-list/GrantItem.tsx b/frontend/src/main-page/grants/grant-list/GrantItem.tsx index 1116bdf..0012535 100644 --- a/frontend/src/main-page/grants/grant-list/GrantItem.tsx +++ b/frontend/src/main-page/grants/grant-list/GrantItem.tsx @@ -367,7 +367,7 @@ const GrantItem: React.FC = observer( >

= observer( >

= observer( {attachment.url && (
= observer( Description
{curGrant.description}
diff --git a/frontend/src/main-page/grants/new-grant/NewGrantModal.tsx b/frontend/src/main-page/grants/new-grant/NewGrantModal.tsx index 3a1f995..0152f15 100644 --- a/frontend/src/main-page/grants/new-grant/NewGrantModal.tsx +++ b/frontend/src/main-page/grants/new-grant/NewGrantModal.tsx @@ -470,7 +470,7 @@ const NewGrantModal: React.FC<{ Organization Name * @@ -573,7 +573,7 @@ const NewGrantModal: React.FC<{
-
setGrantProviderPocName(e.target.value)} /> setCurrentAttachment({ @@ -829,7 +829,7 @@ const NewGrantModal: React.FC<{ } />