Skip to content

Commit

Permalink
Merge pull request #1162 from NSUWAL123/fix-project-details-ui-additions
Browse files Browse the repository at this point in the history
Fix project details UI additions
  • Loading branch information
varun2948 authored Feb 5, 2024
2 parents 03d2c7b + 54a1bad commit 61de9dc
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 100 deletions.
211 changes: 123 additions & 88 deletions src/frontend/src/components/ProjectDetailsV2/ProjectOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ import AssetModules from '@/shared/AssetModules';
import environment from '@/environment';
import { DownloadDataExtract, DownloadProjectForm } from '@/api/Project';
import { ProjectActions } from '@/store/slices/ProjectSlice';
import Button from '@/components/common/Button';

const ProjectOptions = ({ setToggleGenerateModal }) => {
const dispatch = CoreModules.useAppDispatch();
const params = CoreModules.useParams();

const [toggleAction, setToggleAction] = useState(false);
const downloadProjectFormLoading = CoreModules.useAppSelector((state) => state.project.downloadProjectFormLoading);
const downloadDataExtractLoading = CoreModules.useAppSelector((state) => state.project.downloadDataExtractLoading);

Expand Down Expand Up @@ -41,97 +41,132 @@ const ProjectOptions = ({ setToggleGenerateModal }) => {
);
};
return (
<div className="sm:fmtm-mt-4">
<div className="fmtm-flex fmtm-gap-3 fmtm-border-b-[1px] fmtm-pb-2 fmtm-mb-4 sm:fmtm-hidden">
<AssetModules.ListViewIcon className=" fmtm-text-primaryRed" sx={{ fontSize: '35px' }} />
<p className="fmtm-text-2xl">Project Options</p>
</div>
<div
className={`fmtm-flex fmtm-flex-col lg:fmtm-flex-row fmtm-gap-6 lg:fmtm-gap-0 fmtm-px-3 sm:fmtm-px-0 sm:fmtm-flex`}
>
<div className="fmtm-w-full fmtm-flex fmtm-flex-col fmtm-items-start sm:fmtm-flex-row sm:fmtm-justify-center lg:fmtm-justify-start sm:fmtm-items-center fmtm-gap-6 sm:fmtm-ml-4">
<CoreModules.LoadingButton
onClick={() => handleDownload('form')}
sx={{ width: 'unset' }}
loading={downloadProjectFormLoading.type === 'form' && downloadProjectFormLoading.loading}
loadingPosition="end"
endIcon={<AssetModules.FileDownloadIcon />}
variant="contained"
color="error"
>
Form
</CoreModules.LoadingButton>
<CoreModules.LoadingButton
onClick={() => handleDownload('geojson')}
sx={{ width: 'unset' }}
loading={downloadProjectFormLoading.type === 'geojson' && downloadProjectFormLoading.loading}
loadingPosition="end"
endIcon={<AssetModules.FileDownloadIcon />}
variant="contained"
color="error"
>
Tasks
</CoreModules.LoadingButton>
<CoreModules.LoadingButton
onClick={() => onDataExtractDownload()}
sx={{ width: 'unset' }}
loading={downloadDataExtractLoading}
loadingPosition="end"
endIcon={<AssetModules.FileDownloadIcon />}
variant="contained"
color="error"
className="fmtm-truncate"
>
Data Extract
</CoreModules.LoadingButton>
<>
<div className="sm:fmtm-hidden">
<div className="fmtm-flex fmtm-gap-3 fmtm-border-b-[1px] fmtm-pb-2 fmtm-mb-4 sm:fmtm-hidden">
<AssetModules.ListViewIcon className=" fmtm-text-primaryRed" sx={{ fontSize: '35px' }} />
<p className="fmtm-text-2xl">Project Options</p>
</div>
<div className="fmtm-flex fmtm-flex-col sm:fmtm-flex-row sm:fmtm-justify-center lg:fmtm-justify-end fmtm-w-full sm:fmtm-ml-4 fmtm-gap-6">
<CoreModules.Link
to={`/projectInfo/${encodedId}`}
style={{
display: 'flex',
justifyContent: 'flex-end',
alignItems: 'flex-end',
textDecoration: 'none',
marginRight: '15px',
}}
className="fmtm-w-fit"
>
<CoreModules.Button variant="contained" color="error">
ProjectInfo
</CoreModules.Button>
</CoreModules.Link>
<CoreModules.Button
onClick={() => {
setToggleGenerateModal(true);
dispatch(ProjectActions.SetMobileFooterSelection('explore'));
}}
variant="contained"
color="error"
sx={{ width: '200px', mr: '15px' }}
endIcon={<AssetModules.BoltIcon />}
className="fmtm-truncate"
>
Generate MbTiles
</CoreModules.Button>
<CoreModules.Link
to={`/edit-project/project-details/${encodedId}`}
style={{
display: 'flex',
justifyContent: 'flex-end',
alignItems: 'flex-end',
textDecoration: 'none',
marginRight: '15px',
}}
className="fmtm-w-fit"
>
<CoreModules.Button variant="outlined" color="error" className="fmtm-truncate">
Edit Project
<div
className={`fmtm-flex fmtm-flex-col lg:fmtm-flex-row fmtm-gap-6 lg:fmtm-gap-0 fmtm-px-3 sm:fmtm-px-0 sm:fmtm-flex`}
>
<div className="fmtm-w-full fmtm-flex fmtm-flex-col fmtm-items-start sm:fmtm-flex-row sm:fmtm-justify-center lg:fmtm-justify-start sm:fmtm-items-center fmtm-gap-6 sm:fmtm-ml-4">
<CoreModules.LoadingButton
onClick={() => handleDownload('form')}
sx={{ width: 'unset' }}
loading={downloadProjectFormLoading.type === 'form' && downloadProjectFormLoading.loading}
loadingPosition="end"
endIcon={<AssetModules.FileDownloadIcon />}
variant="contained"
color="error"
>
Form
</CoreModules.LoadingButton>
<CoreModules.LoadingButton
onClick={() => handleDownload('geojson')}
sx={{ width: 'unset' }}
loading={downloadProjectFormLoading.type === 'geojson' && downloadProjectFormLoading.loading}
loadingPosition="end"
endIcon={<AssetModules.FileDownloadIcon />}
variant="contained"
color="error"
>
Tasks
</CoreModules.LoadingButton>
<CoreModules.LoadingButton
onClick={() => onDataExtractDownload()}
sx={{ width: 'unset' }}
loading={downloadDataExtractLoading}
loadingPosition="end"
endIcon={<AssetModules.FileDownloadIcon />}
variant="contained"
color="error"
className="fmtm-truncate"
>
Data Extract
</CoreModules.LoadingButton>
</div>
<div className="fmtm-flex fmtm-flex-col sm:fmtm-flex-row sm:fmtm-justify-center lg:fmtm-justify-end fmtm-w-full sm:fmtm-ml-4 fmtm-gap-6">
<CoreModules.Link
to={`/projectInfo/${encodedId}`}
style={{
display: 'flex',
justifyContent: 'flex-end',
alignItems: 'flex-end',
textDecoration: 'none',
marginRight: '15px',
}}
className="fmtm-w-fit"
>
<CoreModules.Button variant="contained" color="error">
ProjectInfo
</CoreModules.Button>
</CoreModules.Link>
<CoreModules.Button
onClick={() => {
setToggleGenerateModal(true);
dispatch(ProjectActions.SetMobileFooterSelection('explore'));
}}
variant="contained"
color="error"
sx={{ width: '200px', mr: '15px' }}
endIcon={<AssetModules.BoltIcon />}
className="fmtm-truncate"
>
Generate MbTiles
</CoreModules.Button>
</CoreModules.Link>
</div>
</div>
</div>
</div>
<div className="fmtm-hidden sm:fmtm-flex fmtm-gap-4 fmtm-flex-col md:fmtm-flex-row">
<Button
isLoading={downloadProjectFormLoading.type === 'form' && downloadProjectFormLoading.loading}
loadingText="FORM"
btnText="FORM"
btnType="other"
className={`${
downloadProjectFormLoading.type === 'form' && downloadProjectFormLoading.loading
? ''
: 'hover:fmtm-text-red-700'
} fmtm-border-red-700 !fmtm-rounded-md`}
icon={<AssetModules.FileDownloadIcon style={{ fontSize: '22px' }} />}
onClick={(e) => {
e.stopPropagation();
handleDownload('form');
}}
/>
<Button
isLoading={downloadProjectFormLoading.type === 'geojson' && downloadProjectFormLoading.loading}
loadingText="TASKS"
btnText="TASKS"
btnType="other"
className={`${
downloadProjectFormLoading.type === 'geojson' && downloadProjectFormLoading.loading
? ''
: 'hover:fmtm-text-red-700'
} fmtm-border-red-700 !fmtm-rounded-md`}
icon={<AssetModules.FileDownloadIcon style={{ fontSize: '22px' }} />}
onClick={(e) => {
e.stopPropagation();
handleDownload('geojson');
}}
/>
<Button
isLoading={downloadDataExtractLoading}
loadingText="DATA EXTRACT"
btnText="DATA EXTRACT"
btnType="other"
className={`${
downloadDataExtractLoading ? '' : 'hover:fmtm-text-red-700'
} fmtm-border-red-700 !fmtm-rounded-md fmtm-truncate`}
icon={<AssetModules.FileDownloadIcon style={{ fontSize: '22px' }} />}
onClick={(e) => {
e.stopPropagation();
onDataExtractDownload();
}}
/>
</div>
</>
);
};

Expand Down
4 changes: 2 additions & 2 deletions src/frontend/src/components/common/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ const btnStyle = (btnType, className) => {
return `hover:fmtm-bg-gray-100 fmtm-flex fmtm-bg-white fmtm-px-4 fmtm-py-1 fmtm-border border-[#E0E0E0] fmtm-rounded-[8px] ${className}`;

case 'other':
return `fmtm-py-1 fmtm-px-5 fmtm-bg-red-500 fmtm-text-white fmtm-rounded-lg hover:fmtm-bg-red-600`;
return `fmtm-py-1 fmtm-px-4 fmtm-text-red-600 fmtm-rounded-lg fmtm-border-[1px] fmtm-border-red-600 ${className}`;
case 'disabled':
return `fmtm-py-1 fmtm-px-4 fmtm-text-white fmtm-rounded-lg fmtm-bg-gray-400 fmtm-cursor-not-allowed ${className}`;

Expand Down Expand Up @@ -68,7 +68,7 @@ const Button = ({
{count}
</p>
)}
<div>{icon && icon}</div>
{icon && <div>{icon}</div>}
</>
)}
</button>
Expand Down
46 changes: 46 additions & 0 deletions src/frontend/src/hooks/useOutsideClick.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { useState, useEffect, useCallback, useRef } from 'react';

/**
* A React custom hook that handles click events outside a specific DOM element.
*
* Returns a ref, toggle state and a function to handle toggle state.
*
* @usage
* Put the ref on the element.
* Toggle state to change the display from none to block or vice-versa.
* Toggle handler on the element to trigger the toggle.
*
*/
const useOutsideClick = (type = 'single') => {
const ref: any = useRef();
const [toggle, setToggle] = useState<boolean>(false);
const onOutsideClick = useCallback((e) => {
if (!ref.current.contains(e.target)) {
setToggle(false);
}
}, []);

useEffect(() => {
if (toggle) {
window.addEventListener('click', onOutsideClick);
} else {
window.removeEventListener('click', onOutsideClick);
}

return () => {
window.removeEventListener('click', onOutsideClick);
};
}, [toggle, onOutsideClick]);

const handleToggle = (): void => {
if (type === 'multiple') {
setToggle(true);
} else {
setToggle((prev) => !prev);
}
};

return [ref, toggle, handleToggle];
};

export default useOutsideClick;
45 changes: 35 additions & 10 deletions src/frontend/src/views/ProjectDetailsV2.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import MobileActivitiesContents from '@/components/ProjectDetailsV2/MobileActivi
import BottomSheet from '@/components/common/BottomSheet';
import MobileProjectInfoContent from '@/components/ProjectDetailsV2/MobileProjectInfoContent';
import { useNavigate } from 'react-router-dom';
import ProjectOptions from '@/components/ProjectDetails/ProjectOptions';
import ProjectOptions from '@/components/ProjectDetailsV2/ProjectOptions';
import { MapContainer as MapComponent, useOLMap } from '@/components/MapComponent/OpenLayersComponent';
import LayerSwitcherControl from '@/components/MapComponent/OpenLayersComponent/LayerSwitcher/index';
import MapControlComponent from '@/components/ProjectDetailsV2/MapControlComponent';
Expand All @@ -41,12 +41,14 @@ import locationArc from '@/assets/images/locationArc.png';
import { CommonActions } from '@/store/slices/CommonSlice';
import Button from '@/components/common/Button';
import ProjectInfo from '@/components/ProjectDetailsV2/ProjectInfo';
import useOutsideClick from '@/hooks/useOutsideClick';

const Home = () => {
const dispatch = CoreModules.useAppDispatch();
const params = CoreModules.useParams();
const navigate = useNavigate();
const { windowSize, type } = WindowDimension();
const [divRef, toggle, handleToggle] = useOutsideClick();

const [taskId, setTaskId] = useState();
const [mainView, setView] = useState();
Expand All @@ -58,7 +60,6 @@ const Home = () => {
const [positionGeojson, setPositionGeojson] = useState(null);
const [deviceRotation, setDeviceRotation] = useState(0);
const [viewState, setViewState] = useState('project_info');

const encodedId = params.id;
const decodedId = environment.decode(encodedId);
const defaultTheme = CoreModules.useAppSelector((state) => state.theme.hotTheme);
Expand Down Expand Up @@ -292,18 +293,18 @@ const Home = () => {
<div className="fmtm-flex fmtm-justify-between fmtm-items-center fmtm-mb-4">
{projectDetailsLoading ? (
<div className="fmtm-flex fmtm-gap-1 fmtm-items-center">
<p>#</p>
<p className="fmtm-text-[#9B9999]">#</p>
<CoreModules.Skeleton className="!fmtm-w-[50px] fmtm-h-[20px]" />
</div>
) : (
<p className="fmtm-text-lg fmtm-font-archivo">{`#${state.projectInfo.id}`}</p>
<p className="fmtm-text-lg fmtm-font-archivo fmtm-text-[#9B9999]">{`#${state.projectInfo.id}`}</p>
)}
<p
className="fmtm-text-sm fmtm-text-primaryRed hover:fmtm-cursor-pointer hover:fmtm-text-red-700"
onClick={() => navigate(`/project-submissions/${encodedId}`)}
>
View Submissions <AssetModules.LaunchIcon style={{ fontSize: '14px' }} />
</p>
<Button
btnText="MANAGE PROJECT"
btnType="other"
className="hover:fmtm-text-red-700 fmtm-border-red-700 !fmtm-rounded-md"
icon={<AssetModules.SettingsIcon />}
/>
</div>
<div className="fmtm-flex fmtm-flex-col fmtm-gap-4">
{projectDetailsLoading ? (
Expand Down Expand Up @@ -363,6 +364,30 @@ const Home = () => {
/>
)}
</div>
<div className="fmtm-flex fmtm-gap-4">
<Button
btnText="VIEW INFOGRAPHICS"
btnType="other"
className="hover:fmtm-text-red-700 fmtm-border-red-700 !fmtm-rounded-md fmtm-my-2"
onClick={() => navigate(`/project-submissions/${encodedId}`)}
/>
<div className="fmtm-relative" ref={divRef}>
<div onClick={() => handleToggle()}>
<Button
btnText="DOWNLOAD"
btnType="other"
className="hover:fmtm-text-red-700 fmtm-border-red-700 !fmtm-rounded-md fmtm-my-2"
/>
</div>
<div
className={`fmtm-flex fmtm-gap-4 fmtm-absolute fmtm-duration-200 fmtm-z-[1000] fmtm-bg-[#F5F5F5] fmtm-p-2 fmtm-rounded-md fmtm-left-0 fmtm-top-0 ${
toggle ? 'fmtm-left-0 fmtm-top-0' : '-fmtm-left-[60rem] fmtm-top-0'
}`}
>
<ProjectOptions setToggleGenerateModal={false} />
</div>
</div>
</div>
</div>
{params?.id && (
<div className="fmtm-relative sm:fmtm-static fmtm-flex-grow fmtm-h-full sm:fmtm-rounded-2xl fmtm-overflow-hidden">
Expand Down

0 comments on commit 61de9dc

Please sign in to comment.