diff --git a/frontend/src/main-page/grants/GrantPage.tsx b/frontend/src/main-page/grants/GrantPage.tsx index 9033560..e90fd20 100644 --- a/frontend/src/main-page/grants/GrantPage.tsx +++ b/frontend/src/main-page/grants/GrantPage.tsx @@ -4,10 +4,22 @@ import FilterBar from "./filter-bar/FilterBar.tsx"; import GrantItem from "./grant-view/GrantView.tsx"; import { observer } from "mobx-react-lite"; import { ProcessGrantData } from "./filter-bar/processGrantData.ts"; +import { + amountRangeFilter, + dateRangeFilter, + eligibleFilter, + filterGrants, + searchFilter, + statusFilter, + userEmailFilter, + yearFilterer, +} from "./filter-bar/grantFilters.ts"; import GrantCard from "./grant-view/components/GrantCard.tsx"; import Button from "../../components/Button.tsx"; import EditGrant from "./edit-grant/EditGrant.tsx"; import { faPlus } from "@fortawesome/free-solid-svg-icons"; +import { clearAllFilters } from "../../external/bcanSatchel/actions.ts"; +import { getAppStore } from "../../external/bcanSatchel/store.ts"; function GrantPage() { const [showEditGrant, setShowEditGrant] = useState(false); @@ -21,11 +33,55 @@ function GrantPage() { grants[0] ?? null; - // When the first grant in the list changes (sort/filter/initial load), show it - const firstGrantId = grants[0]?.grantId ?? null; + const handleGrantCreated = (grantId: number) => { + setCurId(grantId); + + const { + allGrants, + filterStatus, + startDateFilter, + endDateFilter, + yearFilter, + searchQuery, + emailFilter, + eligibleOnly, + amountMinFilter, + amountMaxFilter, + user, + } = getAppStore(); + + const createdGrant = allGrants.find((grant) => grant.grantId === grantId); + + if (createdGrant) { + const grantIsVisible = + filterGrants([createdGrant], [ + statusFilter(filterStatus), + eligibleFilter(eligibleOnly), + dateRangeFilter(startDateFilter, endDateFilter), + amountRangeFilter(amountMinFilter, amountMaxFilter), + yearFilterer(yearFilter), + searchFilter(searchQuery), + userEmailFilter(emailFilter, user), + ]).length > 0; + + if (!grantIsVisible) { + clearAllFilters(); + } + } + }; + + // Preserve current selection when still visible; otherwise show the first visible grant. useEffect(() => { - setCurId(grants.length > 0 ? grants[0].grantId : null); - }, [firstGrantId]); + if (grants.length === 0) { + setCurId(null); + return; + } + + const currentSelectionStillVisible = grants.some((grant) => grant.grantId === curId); + if (!currentSelectionStillVisible) { + setCurId(grants[0].grantId); + } + }, [curId, grants]); return (
@@ -64,6 +120,7 @@ function GrantPage() { {showEditGrant && ( { setShowEditGrant(false); }} diff --git a/frontend/src/main-page/grants/edit-grant/EditGrant.tsx b/frontend/src/main-page/grants/edit-grant/EditGrant.tsx index 43f7592..8a0dfc0 100644 --- a/frontend/src/main-page/grants/edit-grant/EditGrant.tsx +++ b/frontend/src/main-page/grants/edit-grant/EditGrant.tsx @@ -42,7 +42,8 @@ export interface GrantFormState { const EditGrant: React.FC<{ grantToEdit: Grant | null; onClose: () => void; -}> = observer(({ grantToEdit, onClose }) => { + onGrantCreated?: (grantId: number) => void; +}> = observer(({ grantToEdit, onClose, onGrantCreated }) => { // State to track if form was submitted successfully const [saving, setSaving] = useState(false); const [showDeleteModal, setShowDeleteModal] = useState(false); @@ -144,6 +145,9 @@ const EditGrant: React.FC<{ : await createNewGrant(grantData); if (result.success) { + if (!grantToEdit && result.grantId != null) { + onGrantCreated?.(result.grantId); + } setSaving(false); onClose(); } else { diff --git a/frontend/src/main-page/grants/edit-grant/processGrantDataEditSave.ts b/frontend/src/main-page/grants/edit-grant/processGrantDataEditSave.ts index 81b956b..1a57637 100644 --- a/frontend/src/main-page/grants/edit-grant/processGrantDataEditSave.ts +++ b/frontend/src/main-page/grants/edit-grant/processGrantDataEditSave.ts @@ -4,8 +4,14 @@ import { api } from "../../../api.ts"; import { GrantFormState } from "./EditGrant.tsx"; import { fetchGrants } from "../filter-bar/processGrantData.ts"; +export type GrantMutationResult = + | { success: true; grantId?: number } + | { success: false; error: string }; + // save a new grant -export const createNewGrant = async (newGrant: Grant) => { +export const createNewGrant = async ( + newGrant: Grant +): Promise => { try { const response = await api("/grant/new-grant", { method: "POST", @@ -14,8 +20,9 @@ export const createNewGrant = async (newGrant: Grant) => { }); if (response.ok) { + const createdGrantId = (await response.json()) as number; await fetchGrants(); - return { success: true }; + return { success: true, grantId: createdGrantId }; } else { const errorData = await response.json(); throw new Error(errorData.message || "Failed to create grant"); @@ -34,7 +41,9 @@ export const createNewGrant = async (newGrant: Grant) => { } }; -export const saveGrantEdits = async (updatedGrant: Grant) => { +export const saveGrantEdits = async ( + updatedGrant: Grant +): Promise => { try { const response = await api("/grant/save", { method: "PUT", diff --git a/frontend/src/main-page/grants/filter-bar/FilterBar.tsx b/frontend/src/main-page/grants/filter-bar/FilterBar.tsx index 8a9c6c6..1858c97 100644 --- a/frontend/src/main-page/grants/filter-bar/FilterBar.tsx +++ b/frontend/src/main-page/grants/filter-bar/FilterBar.tsx @@ -25,6 +25,7 @@ const FilterBar: React.FC = observer(() => { emailFilter, eligibleOnly, sort, + filterStatus, startDateFilter, endDateFilter, amountMinFilter, @@ -34,7 +35,6 @@ const FilterBar: React.FC = observer(() => { const [showDueDateCard, setShowDueDateCard] = useState(false); const [showAmountCard, setShowAmountCard] = useState(false); const [showStatusDropdown, setShowStatusDropdown] = useState(false); - const [selectedStatus, setSelectedStatus] = useState(null); const dueDateDropdownRef = useRef(null); const amountDropdownRef = useRef(null); const statusDropdownRef = useRef(null); @@ -82,8 +82,7 @@ const FilterBar: React.FC = observer(() => { }; const handleStatusSelect = (status: Status) => { - const newSelected = selectedStatus === status ? null : status; - setSelectedStatus(newSelected); + const newSelected = filterStatus === status ? null : status; updateFilter(newSelected); }; @@ -279,11 +278,11 @@ const FilterBar: React.FC = observer(() => { logo={showStatusDropdown ? faChevronUp : faChevronDown} logoPosition="right" className={`bg-white text-sm lg:text-base whitespace-nowrap ${ - showStatusDropdown || selectedStatus ? activeButtonClass : inactiveButtonClass + showStatusDropdown || filterStatus ? activeButtonClass : inactiveButtonClass }`} /> {showStatusDropdown && ( - + )}