Skip to content

Commit

Permalink
full-scope changes. debounce added to layout files and selection syst…
Browse files Browse the repository at this point in the history
…ems. datagridcommons debugged for deep bugs found during add/editing row process. Additional stabilization steps need to be taken, but website is partially functional and testing environment has been prepared
  • Loading branch information
siddheshraze committed Sep 6, 2024
1 parent 4b5cf0a commit 57ec6c2
Show file tree
Hide file tree
Showing 19 changed files with 631 additions and 1,145 deletions.
165 changes: 102 additions & 63 deletions frontend/app/(hub)/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,18 @@ import { title } from '@/config/primitives';
import { useSession } from 'next-auth/react';
import { redirect, usePathname } from 'next/navigation';
import dynamic from 'next/dynamic';
import { Box, IconButton, Stack, Tooltip, Typography } from '@mui/joy';
import { Box, IconButton, Stack, Typography } from '@mui/joy';
import Divider from '@mui/joy/Divider';
import { useLoading } from '@/app/contexts/loadingprovider';
import { getAllSchemas } from '@/components/processors/processorhelperfunctions';
import { useOrgCensusContext, usePlotContext, useSiteContext } from '@/app/contexts/userselectionprovider';
import { useOrgCensusListDispatch, usePlotListDispatch, useQuadratListDispatch, useSiteListDispatch } from '@/app/contexts/listselectionprovider';
import { getEndpointHeaderName, siteConfig } from '@/config/macros/siteconfigs';
import { AcaciaVersionTypography } from '@/styles/versions/acaciaversion';
import GithubFeedbackModal from '@/components/client/githubfeedbackmodal';
import HelpOutlineOutlinedIcon from '@mui/icons-material/HelpOutlineOutlined';
import { useLockAnimation } from '../contexts/lockanimationcontext';
import { createAndUpdateCensusList } from '@/config/sqlrdsdefinitions/timekeeping';
import { AcaciaVersionTypography } from '@/styles/versions/acaciaversion';

const Sidebar = dynamic(() => import('@/components/sidebar'), { ssr: false });
const Header = dynamic(() => import('@/components/header'), { ssr: false });
Expand Down Expand Up @@ -67,7 +67,25 @@ export default function HubLayout({ children }: { children: React.ReactNode }) {
const coreDataLoaded = siteListLoaded && plotListLoaded && censusListLoaded && quadratListLoaded;
const { isPulsing } = useLockAnimation();

const lastExecutedRef = useRef<number | null>(null);
// Refs for debouncing
const plotLastExecutedRef = useRef<number | null>(null);
const censusLastExecutedRef = useRef<number | null>(null);
const quadratLastExecutedRef = useRef<number | null>(null);

// Debounce delay
const debounceDelay = 100;

const fetchSiteList = useCallback(async () => {
const now = Date.now();
if (lastExecutedRef.current && now - lastExecutedRef.current < debounceDelay + 200) {
console.log('Debounced fetchSiteList: Too soon since last call.');
return;
}

// Update last executed timestamp
lastExecutedRef.current = now;

try {
setLoading(true, 'Loading Sites...');
if (session && !siteListLoaded) {
Expand All @@ -86,74 +104,92 @@ export default function HubLayout({ children }: { children: React.ReactNode }) {
}
}, [session, siteListLoaded, siteListDispatch, setLoading]);

const loadData = useCallback(async () => {
try {
setLoading(true, 'Loading data...');

const promises = [];
const loadPlotData = useCallback(async () => {
const now = Date.now();
if (plotLastExecutedRef.current && now - plotLastExecutedRef.current < debounceDelay) {
console.log('Debounced loadPlotData: Too soon since last call.');
return;
}
plotLastExecutedRef.current = now;

// Load plot data
try {
setLoading(true, 'Loading plot data...');
if (currentSite && !plotListLoaded) {
const loadPlots = fetch(`/api/fetchall/plots?schema=${currentSite?.schemaName || ''}`)
.then(response => response.json())
.then(plotsData => {
if (!plotsData) throw new Error('Failed to load plots data');
if (plotListDispatch) return plotListDispatch({ plotList: plotsData });
});
promises.push(loadPlots);
const response = await fetch(`/api/fetchall/plots?schema=${currentSite?.schemaName || ''}`);
const plotsData = await response.json();
if (!plotsData) throw new Error('Failed to load plots data');
if (plotListDispatch) await plotListDispatch({ plotList: plotsData });
setPlotListLoaded(true);
}
} catch (error) {
console.error('Error loading plot data:', error);
} finally {
setLoading(false);
}
}, [currentSite, plotListLoaded, plotListDispatch, setLoading]);

// Function to load census data with debounce
const loadCensusData = useCallback(async () => {
const now = Date.now();
if (censusLastExecutedRef.current && now - censusLastExecutedRef.current < debounceDelay) {
console.log('Debounced loadCensusData: Too soon since last call.');
return;
}
censusLastExecutedRef.current = now;

// Load census data
try {
setLoading(true, 'Loading census data...');
if (currentSite && currentPlot && !censusListLoaded) {
const loadCensus = fetch(`/api/fetchall/census/${currentPlot.plotID}?schema=${currentSite.schemaName}`)
.then(response => response.json())
.then(async censusRDSLoad => {
if (!censusRDSLoad) throw new Error('Failed to load census data');
const censusList = await createAndUpdateCensusList(censusRDSLoad);
if (censusListDispatch) return censusListDispatch({ censusList });
});
promises.push(loadCensus);
const response = await fetch(`/api/fetchall/census/${currentPlot.plotID}?schema=${currentSite.schemaName}`);
const censusRDSLoad = await response.json();
if (!censusRDSLoad) throw new Error('Failed to load census data');
const censusList = await createAndUpdateCensusList(censusRDSLoad);
if (censusListDispatch) await censusListDispatch({ censusList });
setCensusListLoaded(true);
}
} catch (error) {
console.error('Error loading census data:', error);
} finally {
setLoading(false);
}
}, [currentSite, currentPlot, censusListLoaded, censusListDispatch, setLoading]);

// Load quadrat data
// Function to load quadrat data with debounce
const loadQuadratData = useCallback(async () => {
const now = Date.now();
if (quadratLastExecutedRef.current && now - quadratLastExecutedRef.current < debounceDelay) {
console.log('Debounced loadQuadratData: Too soon since last call.');
return;
}
quadratLastExecutedRef.current = now;

try {
setLoading(true, 'Loading quadrat data...');
if (currentSite && currentPlot && currentCensus && !quadratListLoaded) {
const loadQuadrats = fetch(`/api/fetchall/quadrats/${currentPlot.plotID}/${currentCensus.plotCensusNumber}?schema=${currentSite.schemaName}`)
.then(response => response.json())
.then(quadratsData => {
if (!quadratsData) throw new Error('Failed to load quadrats data');
if (quadratListDispatch) return quadratListDispatch({ quadratList: quadratsData });
});
promises.push(loadQuadrats);
const response = await fetch(`/api/fetchall/quadrats/${currentPlot.plotID}/${currentCensus.plotCensusNumber}?schema=${currentSite.schemaName}`);
const quadratsData = await response.json();
if (!quadratsData) throw new Error('Failed to load quadrats data');
if (quadratListDispatch) await quadratListDispatch({ quadratList: quadratsData });
setQuadratListLoaded(true);
}

// Wait for all promises to resolve
await Promise.all(promises);
} catch (error) {
console.error('Error loading data:', error);
console.error('Error loading quadrat data:', error);
} finally {
setLoading(false);
}
}, [
currentSite,
currentPlot,
currentCensus,
plotListLoaded,
censusListLoaded,
quadratListLoaded,
plotListDispatch,
censusListDispatch,
quadratListDispatch,
setLoading
]);
}, [currentSite, currentPlot, currentCensus, quadratListLoaded, quadratListDispatch, setLoading]);

useEffect(() => {
if (currentSite || currentPlot || currentCensus) {
loadData().catch(console.error);
if (currentSite && siteListLoaded) {
loadPlotData().catch(console.error);
}
if (currentSite && siteListLoaded && currentPlot && plotListLoaded) {
loadCensusData().catch(console.error);
}
if (currentSite && siteListLoaded && currentPlot && plotListLoaded && currentCensus && censusListLoaded) {
loadQuadratData().catch(console.error);
}
}, [currentSite, currentPlot, currentCensus, loadData]);
}, [currentSite, currentPlot, currentCensus, loadPlotData, loadCensusData, loadQuadratData]);

useEffect(() => {
if (manualReset) {
Expand All @@ -163,9 +199,8 @@ export default function HubLayout({ children }: { children: React.ReactNode }) {
setCensusListLoaded(false);
setQuadratListLoaded(false);
setManualReset(false);
loadData().catch(console.error);
}
}, [manualReset, loadData]);
}, [manualReset]);

useEffect(() => {
if (session && !siteListLoaded) {
Expand Down Expand Up @@ -211,13 +246,16 @@ export default function HubLayout({ children }: { children: React.ReactNode }) {
await Promise.all(promises);

// After clearing, load the new data
loadData().catch(console.error);
loadPlotData()
.then(() => loadCensusData())
.then(() => loadQuadratData())
.catch(console.error);
};

if (hasSiteChanged || hasPlotChanged || hasCensusChanged) {
clearLists().catch(console.error);
}
}, [currentSite, currentPlot, currentCensus, plotListDispatch, censusListDispatch, quadratListDispatch, loadData]);
}, [currentSite, currentPlot, currentCensus, plotListDispatch, censusListDispatch, quadratListDispatch, loadPlotData, loadCensusData, loadQuadratData]);

useEffect(() => {
// if contexts are reset due to website refresh, system needs to redirect user back to dashboard
Expand Down Expand Up @@ -325,15 +363,16 @@ export default function HubLayout({ children }: { children: React.ReactNode }) {
justifyContent: 'center'
}}
>
{siteConfig.name}
{/*{siteConfig.name}*/}
<AcaciaVersionTypography>{siteConfig.name}</AcaciaVersionTypography>
</Typography>
<Stack direction="row" sx={{ alignItems: 'center', justifyContent: 'center' }}>
<Tooltip title="Version" variant="solid" placement="top" arrow>
<Box sx={{ display: 'inline-block', verticalAlign: 'middle' }}>
<AcaciaVersionTypography>{siteConfig.version}</AcaciaVersionTypography>
</Box>
</Tooltip>
</Stack>
{/*<Stack direction="row" sx={{ alignItems: 'center', justifyContent: 'center' }}>*/}
{/* <Tooltip title="Version" variant="solid" placement="top" arrow sx={{ pointerEvents: 'none' }}>*/}
{/* <Box sx={{ display: 'inline-block', verticalAlign: 'middle' }}>*/}
{/* <AcaciaVersionTypography>{siteConfig.version}</AcaciaVersionTypography>*/}
{/* </Box>*/}
{/* </Tooltip>*/}
{/*</Stack>*/}
</Stack>
<IconButton
onClick={() => setIsFeedbackModalOpen(true)}
Expand Down
4 changes: 2 additions & 2 deletions frontend/app/api/fixeddata/[dataType]/[[...slugs]]/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,15 +349,15 @@ export async function DELETE(request: NextRequest, { params }: { params: { dataT
const { [viewConfig.primaryKey]: primaryKeyValue } = deleteRowData;
if (!primaryKeyValue) throw new Error(`Primary key value missing for ${viewConfig.primaryKey} in view ${params.dataType}`);

const deleteQuery = `DELETE FROM ${schema}.${viewConfig.table} WHERE ${viewConfig.primaryKey} = ${primaryKeyValue}`;
const deleteQuery = format(`DELETE FROM ?? WHERE ?? = ?`, [`${schema}.${params.dataType}`, viewConfig.primaryKey, primaryKeyValue]);
await runQuery(conn, deleteQuery);
await conn.commit();
return NextResponse.json({ message: 'Delete successful' }, { status: HTTPResponses.OK });
}
// Handle deletion for tables
const deleteRowData = MapperFactory.getMapper<any, any>(params.dataType).demapData([newRow])[0];
const { [demappedGridID]: gridIDKey } = deleteRowData;
const deleteQuery = `DELETE FROM ${schema}.${params.dataType} WHERE ${demappedGridID} = ${gridIDKey}`;
const deleteQuery = format(`DELETE FROM ?? WHERE ?? = ?`, [`${schema}.${params.dataType}`, demappedGridID, gridIDKey]);
await runQuery(conn, deleteQuery);
await conn.commit();
return NextResponse.json({ message: 'Delete successful' }, { status: HTTPResponses.OK });
Expand Down
6 changes: 3 additions & 3 deletions frontend/components/client/rollovermodal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ export default function RolloverModal(props: RolloverModalProps) {

useEffect(() => {
if (open) {
validatePreviousCensusData();
validatePreviousCensusData().catch(console.error);
}
}, [open]);

Expand All @@ -139,7 +139,7 @@ export default function RolloverModal(props: RolloverModalProps) {

if (foundCensus) {
const plotCensusNumber = foundCensus.plotCensusNumber;
fetchPreviousQuadratsData(plotCensusNumber);
fetchPreviousQuadratsData(plotCensusNumber).catch(console.error);
}
}
}, [selectedQuadratsCensus, censusListContext]);
Expand All @@ -149,7 +149,7 @@ export default function RolloverModal(props: RolloverModalProps) {
const foundCensus = censusListContext?.find(census => census?.dateRanges.some(dateRange => dateRange.censusID === selectedPersonnelCensus.censusID));
if (foundCensus) {
const plotCensusNumber = foundCensus.plotCensusNumber;
fetchPreviousPersonnelData(plotCensusNumber);
fetchPreviousPersonnelData(plotCensusNumber).catch(console.error);
}
}
}, [selectedPersonnelCensus, censusListContext]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,13 @@ import UploadParentModal from '@/components/uploadsystemhelpers/uploadparentmoda
import { AttributeGridColumns } from '@/components/client/datagridcolumns';
import { FormType } from '@/config/macros/formdetails';

import { initialAttributesRDSRow } from '@/config/sqlrdsdefinitions/core';

export default function AttributesDataGrid() {
const initialAttributesRDSRow = {
id: 0,
code: '',
description: '',
status: ''
};
const [rows, setRows] = useState([initialAttributesRDSRow] as GridRowsProp);
const [rowCount, setRowCount] = useState(0);
const [rowModesModel, setRowModesModel] = useState({});
Expand Down
Loading

0 comments on commit 57ec6c2

Please sign in to comment.