From 7cc33010b844586e8bce2b6fb71cd8a3e5f42362 Mon Sep 17 00:00:00 2001 From: Nishit Suwal <81785002+NSUWAL123@users.noreply.github.com> Date: Sat, 29 Jun 2024 00:17:23 +0545 Subject: [PATCH] refactor(frontend): update remaining JavaScript files to TypeScript (#1602) * remove(projectTaskStatus): remove unused map, view arguments * fix(themeSlice): add type & remove unused updateBrightness reducer * fix(projectTaskStatus): convert js to ts * fix(dialogTaskActions): convert jsx to tsx * fix(projectDetailsV2): remove map, view props from TaskSelectionPopup * fix(projectDetailsV2): rename prop name * fix(files): convert js to ts * fix(qrcodeComponent): convert jsx to tsx * fix(file): getProjectQrCode parameters type add * fix(taskSelectionPopup): add ts types * fix(modulesDecleration): delare pako/lib/deflate module * fix(mapLegends): convert jsx to tsx * fix(projectDetials): update ts types * fix(projectModel): custom_tms_url type add to projectINfo * fix(generateBaseMap): convert jsx to tsx * fix(notFound404): convert jsx to tsx * fix(activities): remove unused activities & activitiesPanel component * fix(activitiesPanel): remove unused props from activities panel * fix(IProject): remove project_id type from projectTaskactivity * fix(activitiesPanel): update ts type * fix(mapDescriptionComponents): remove unused component * fix(openLayersMap): remove unused component * fix(submissionDetails): add ts types * fix(submissionInstanceMap): update jsx to tsx * fix(exploreProjectCard): file cleanup * fix(mainView): add ts types * fix(utilities): remove unused utility components * fix(primaryAppBar): remove unused props * fix(customDrawer): convert jsx to tsx * fix(customizedImage): convert jsx to tsx * fix(customizedSnackbar): convert jsx to tsx --- src/frontend/src/api/{Files.js => Files.ts} | 22 +- ...jectTaskStatus.js => ProjectTaskStatus.ts} | 17 +- src/frontend/src/components/Activities.jsx | 38 --- .../src/components/ActivitiesPanel.jsx | 181 ---------- ...gTaskActions.jsx => DialogTaskActions.tsx} | 38 ++- ...enerateBasemap.jsx => GenerateBasemap.tsx} | 25 +- .../components/MapDescriptionComponents.jsx | 74 ---- .../{MapLegends.jsx => MapLegends.tsx} | 14 +- src/frontend/src/components/OpenLayersMap.jsx | 309 ----------------- .../ProjectDetailsV2/ActivitiesPanel.tsx | 29 +- .../FeatureSelectionPopup.tsx | 12 +- .../ProjectDetailsV2/Instructions.tsx | 2 +- .../MobileActivitiesContents.tsx | 18 +- .../MobileProjectInfoContent.tsx | 2 +- .../ProjectDetailsV2/ProjectOptions.tsx | 2 +- .../ProjectDetailsV2/TaskSelectionPopup.tsx | 16 +- ...rcodeComponent.jsx => QrcodeComponent.tsx} | 8 +- ...tanceMap.jsx => SubmissionInstanceMap.tsx} | 10 +- .../components/home/ExploreProjectCard.tsx | 38 +-- .../src/models/project/projectModel.ts | 2 + src/frontend/src/store/slices/ThemeSlice.ts | 316 ++++++++---------- src/frontend/src/store/types/IProject.ts | 3 +- .../src/types/modulesDecleration.d.ts | 1 + src/frontend/src/utilities/BasicDialog.jsx | 31 -- src/frontend/src/utilities/BasicDialog.tsx | 42 --- .../{CustomDrawer.jsx => CustomDrawer.tsx} | 31 +- ...ustomizedImage.jsx => CustomizedImage.tsx} | 16 +- .../src/utilities/CustomizedMenus.tsx | 73 ---- ...zedSnackbar.jsx => CustomizedSnackbar.tsx} | 20 +- src/frontend/src/utilities/IconButtonCard.jsx | 16 - src/frontend/src/utilities/PrimaryAppBar.tsx | 10 +- .../src/views/{MainView.jsx => MainView.tsx} | 8 +- .../{NotFound404.jsx => NotFound404.tsx} | 3 +- src/frontend/src/views/ProjectDetailsV2.tsx | 24 +- src/frontend/src/views/SubmissionDetails.tsx | 17 +- 35 files changed, 363 insertions(+), 1105 deletions(-) rename src/frontend/src/api/{Files.js => Files.ts} (85%) rename src/frontend/src/api/{ProjectTaskStatus.js => ProjectTaskStatus.ts} (79%) delete mode 100755 src/frontend/src/components/Activities.jsx delete mode 100755 src/frontend/src/components/ActivitiesPanel.jsx rename src/frontend/src/components/{DialogTaskActions.jsx => DialogTaskActions.tsx} (89%) rename src/frontend/src/components/{GenerateBasemap.jsx => GenerateBasemap.tsx} (93%) delete mode 100755 src/frontend/src/components/MapDescriptionComponents.jsx rename src/frontend/src/components/{MapLegends.jsx => MapLegends.tsx} (88%) delete mode 100755 src/frontend/src/components/OpenLayersMap.jsx rename src/frontend/src/components/{QrcodeComponent.jsx => QrcodeComponent.tsx} (91%) rename src/frontend/src/components/SubmissionMap/{SubmissionInstanceMap.jsx => SubmissionInstanceMap.tsx} (83%) delete mode 100755 src/frontend/src/utilities/BasicDialog.jsx delete mode 100755 src/frontend/src/utilities/BasicDialog.tsx rename src/frontend/src/utilities/{CustomDrawer.jsx => CustomDrawer.tsx} (91%) rename src/frontend/src/utilities/{CustomizedImage.jsx => CustomizedImage.tsx} (64%) delete mode 100755 src/frontend/src/utilities/CustomizedMenus.tsx rename src/frontend/src/utilities/{CustomizedSnackbar.jsx => CustomizedSnackbar.tsx} (64%) delete mode 100755 src/frontend/src/utilities/IconButtonCard.jsx rename src/frontend/src/views/{MainView.jsx => MainView.tsx} (91%) rename src/frontend/src/views/{NotFound404.jsx => NotFound404.tsx} (91%) diff --git a/src/frontend/src/api/Files.js b/src/frontend/src/api/Files.ts similarity index 85% rename from src/frontend/src/api/Files.js rename to src/frontend/src/api/Files.ts index 5f369609b7..6c5d80044f 100755 --- a/src/frontend/src/api/Files.js +++ b/src/frontend/src/api/Files.ts @@ -6,14 +6,22 @@ import { deflate } from 'pako/lib/deflate'; // return new TextDecoder().decode(inflate(Uint8Array.from(window.atob(string), (c) => c.codePointAt(0)))) // } -function base64zlibencode(string) { +function base64zlibencode(string: string) { return window.btoa(String.fromCodePoint(...deflate(new TextEncoder().encode(string)))); } -export const GetProjectQrCode = (odkToken, projectName, osmUser) => { +export const GetProjectQrCode = ( + odkToken: string | undefined, + projectName: string | undefined, + osmUser: string, +): { qrcode: string } => { const [qrcode, setQrcode] = useState(''); useEffect(() => { - const fetchProjectFileById = async (odkToken, projectName, osmUser) => { + const fetchProjectFileById = async ( + odkToken: string | undefined, + projectName: string | undefined, + osmUser: string, + ) => { if (odkToken === '') { setQrcode(''); return; @@ -54,7 +62,7 @@ export const GetProjectQrCode = (odkToken, projectName, osmUser) => { return { qrcode }; }; -export async function readFileFromOPFS(filePath) { +export async function readFileFromOPFS(filePath: string) { const opfsRoot = await navigator.storage.getDirectory(); const directories = filePath.split('/'); @@ -72,7 +80,7 @@ export async function readFileFromOPFS(filePath) { // Get file within final directory handle try { - const filename = directories.pop(); + const filename: any = directories.pop(); console.log(`Getting OPFS file: ${filename}`); const fileHandle = await currentDirectoryHandle.getFileHandle(filename); const fileData = await fileHandle.getFile(); // Read the file @@ -82,14 +90,14 @@ export async function readFileFromOPFS(filePath) { } } -export async function writeBinaryToOPFS(filePath, data) { +export async function writeBinaryToOPFS(filePath: string, data: any) { console.log(`Starting write to OPFS file: ${filePath}`); const opfsRoot = await navigator.storage.getDirectory(); // Split the filePath into directories and filename const directories = filePath.split('/'); - const filename = directories.pop(); + const filename: any = directories.pop(); // Start with the root directory handle let currentDirectoryHandle = opfsRoot; diff --git a/src/frontend/src/api/ProjectTaskStatus.js b/src/frontend/src/api/ProjectTaskStatus.ts similarity index 79% rename from src/frontend/src/api/ProjectTaskStatus.js rename to src/frontend/src/api/ProjectTaskStatus.ts index 918aec0c4e..a1a5072fcb 100755 --- a/src/frontend/src/api/ProjectTaskStatus.js +++ b/src/frontend/src/api/ProjectTaskStatus.ts @@ -2,11 +2,20 @@ import { ProjectActions } from '@/store/slices/ProjectSlice'; import { HomeActions } from '@/store/slices/HomeSlice'; import CoreModules from '@/shared/CoreModules'; import { CommonActions } from '@/store/slices/CommonSlice'; -import { task_status } from '@/types/enums'; +import { projectTaskBoundriesType } from '@/models/project/projectModel'; -const UpdateTaskStatus = (url, style, existingData, currentProjectId, feature, map, view, taskId, body, params) => { +const UpdateTaskStatus = ( + url: string, + style: any, + existingData: projectTaskBoundriesType[], + currentProjectId: string, + feature: Record, + taskId: number, + body: any, + params: { project_id: string }, +) => { return async (dispatch) => { - const updateTask = async (url, existingData, body, feature, params) => { + const updateTask = async (url: string, body: any, feature: Record, params: string) => { try { dispatch(CommonActions.SetLoading(true)); @@ -50,7 +59,7 @@ const UpdateTaskStatus = (url, style, existingData, currentProjectId, feature, m ); } }; - await updateTask(url, existingData, body, feature, params); + await updateTask(url, body, feature, params); }; }; diff --git a/src/frontend/src/components/Activities.jsx b/src/frontend/src/components/Activities.jsx deleted file mode 100755 index 926de1178e..0000000000 --- a/src/frontend/src/components/Activities.jsx +++ /dev/null @@ -1,38 +0,0 @@ -import React from 'react'; -import IconButtonCard from '@/utilities/IconButtonCard'; -import { easeIn, easeOut } from 'ol/easing'; -import CoreModules from '@/shared/CoreModules'; -import AssetModules from '@/shared/AssetModules'; -//Activity Model to be display in Activities panel -const Activities = ({ history, defaultTheme, mapDivPostion, map, view, state, params }) => { - const index = state.projectTaskBoundries.findIndex((project) => project.id == params.id); - - return ( - - - {`Task #${history.taskId}`} - - - - - - - - {history.action_text} - - - - - - - - {history.action_date} - - - ); -}; -export default Activities; diff --git a/src/frontend/src/components/ActivitiesPanel.jsx b/src/frontend/src/components/ActivitiesPanel.jsx deleted file mode 100755 index 55cd6aac7b..0000000000 --- a/src/frontend/src/components/ActivitiesPanel.jsx +++ /dev/null @@ -1,181 +0,0 @@ -import React, { useEffect, useState } from 'react'; -import BasicCard from '@/utilities/BasicCard'; -import Activities from '@/components/Activities'; -import CoreModules from '@/shared/CoreModules'; -import AssetModules from '@/shared/AssetModules'; - -const Search = AssetModules.styled('div')(({ theme }) => ({ - position: 'relative', - borderRadius: theme.shape.borderRadius, - backgroundColor: AssetModules.alpha(theme.palette.common.white, 0.15), - '&:hover': { - backgroundColor: AssetModules.alpha(theme.palette.common.white, 0.25), - }, - marginRight: theme.spacing(2), - marginLeft: 0, - opacity: 0.8, - border: `1px solid ${theme.palette.warning['main']}`, - width: '100%', - [theme.breakpoints.up('sm')]: { - marginLeft: theme.spacing(3), - width: 'auto', - }, -})); - -const SearchIconWrapper = AssetModules.styled('div')(({ theme }) => ({ - padding: theme.spacing(0, 2), - height: '100%', - position: 'absolute', - pointerEvents: 'none', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', -})); - -const StyledInputBase = AssetModules.styled(CoreModules.InputBase)(({ theme }) => ({ - color: 'primary', - '& .MuiInputBase-input': { - padding: theme.spacing(1, 1, 1, 0), - fontFamily: theme.typography.h3.fontFamily, - // vertical padding + font size from searchIcon - paddingLeft: `calc(1em + ${theme.spacing(4)})`, - transition: theme.transitions.create('width'), - width: '100%', - // [theme.breakpoints.up('md')]: { - // width: '20ch', - // }, - }, -})); - -const ActivitiesPanel = ({ defaultTheme, state, params, map, view, mapDivPostion, states }) => { - const displayLimit = 10; - const [searchText, setSearchText] = useState(''); - const [taskHistories, setTaskHistories] = useState([]); - const [paginationSize, setPaginationSize] = useState(0); - const [taskDisplay, setTaskDisplay] = React.useState(displayLimit); - const [allActivities, setAllActivities] = useState(0); - const [prev, setPrv] = React.useState(0); - - const handleChange = (event, value) => { - setPrv(value * displayLimit - displayLimit); - setTaskDisplay(value * displayLimit); - }; - - const handleOnchange = (event) => { - setSearchText(event.target.value); - }; - - useEffect(() => { - const index = state.findIndex((project) => project.id == params.id); - let taskHistories = []; - - if (index != -1) { - state[index].taskBoundries.forEach((task) => { - taskHistories = taskHistories.concat( - task.task_history.map((history) => { - return { ...history, taskId: task.id, status: task.task_status }; - }), - ); - }); - } - - let finalTaskHistory = taskHistories.filter((task) => { - return ( - task.taskId.toString().includes(searchText) || - task.action_text.split(':')[1].replace(/\s+/g, '').toString().includes(searchText.toString()) - ); - }); - - if (searchText != '') { - setAllActivities(finalTaskHistory.length); - const tasksToDisplay = finalTaskHistory.filter((task, index) => { - return index <= taskDisplay - 1 && index >= prev; - }); - setTaskHistories(tasksToDisplay); - const paginationSize = - finalTaskHistory.length % displayLimit == 0 - ? Math.floor(finalTaskHistory.length / displayLimit) - : Math.floor(finalTaskHistory.length / displayLimit) + 1; - setPaginationSize(paginationSize); - } else { - setAllActivities(taskHistories.length); - const tasksToDisplay = taskHistories.filter((task, index) => { - return index <= taskDisplay - 1 && index >= prev; - }); - - setTaskHistories(tasksToDisplay); - const paginationSize = - taskHistories.length % displayLimit == 0 - ? Math.floor(taskHistories.length / displayLimit) - : Math.floor(taskHistories.length / displayLimit) + 1; - setPaginationSize(paginationSize); - } - }, [taskDisplay, state, searchText]); - - return ( - - - {`Total Activities ${allActivities}`} - - - - - - - - - - - {allActivities === 0 && ( - - No Results found. - - )} - - {taskHistories.map((history, index) => ( - - - } - /> - - ))} - - - - - - - - ); -}; - -export default ActivitiesPanel; diff --git a/src/frontend/src/components/DialogTaskActions.jsx b/src/frontend/src/components/DialogTaskActions.tsx similarity index 89% rename from src/frontend/src/components/DialogTaskActions.jsx rename to src/frontend/src/components/DialogTaskActions.tsx index 4b9a0f4579..8d44c6f016 100755 --- a/src/frontend/src/components/DialogTaskActions.jsx +++ b/src/frontend/src/components/DialogTaskActions.tsx @@ -9,25 +9,38 @@ import Button from '@/components/common/Button'; import { useNavigate } from 'react-router-dom'; import { GetProjectTaskActivity } from '@/api/Project'; import { Modal } from '@/components/common/Modal'; +import { useAppSelector } from '@/types/reduxTypes'; +import { taskSubmissionInfoType } from '@/models/task/taskModel'; -export default function Dialog({ taskId, feature, map, view }) { +type dialogPropType = { + taskId: number; + feature: Record; +}; + +type taskListstatusType = { + value: string; + key: string; + btnBG: string; +}; + +export default function Dialog({ taskId, feature }: dialogPropType) { const navigate = useNavigate(); - const projectInfo = CoreModules.useAppSelector((state) => state.project.projectInfo); - const taskBoundaryData = CoreModules.useAppSelector((state) => state.project.projectTaskBoundries); + const projectInfo = useAppSelector((state) => state.project.projectInfo); + const taskBoundaryData = useAppSelector((state) => state.project.projectTaskBoundries); const authDetails = CoreModules.useAppSelector((state) => state.login.authDetails); - const loading = CoreModules.useAppSelector((state) => state.common.loading); - const taskInfo = CoreModules.useAppSelector((state) => state.task.taskInfo); - const [list_of_task_status, set_list_of_task_status] = useState([]); + const loading = useAppSelector((state) => state.common.loading); + const taskInfo = useAppSelector((state) => state.task.taskInfo); + const [list_of_task_status, set_list_of_task_status] = useState([]); const [task_status, set_task_status] = useState('READY'); - const [currentTaskInfo, setCurrentTaskInfo] = useState(); + const [currentTaskInfo, setCurrentTaskInfo] = useState(); const [toggleMappedConfirmationModal, setToggleMappedConfirmationModal] = useState(false); const geojsonStyles = MapStyles(); const dispatch = CoreModules.useAppDispatch(); const params = CoreModules.useParams(); - const currentProjectId = params.id; - const projectData = CoreModules.useAppSelector((state) => state.project.projectTaskBoundries); - const projectIndex = projectData.findIndex((project) => project.id == currentProjectId); + const currentProjectId: string = params.id; + const projectData = useAppSelector((state) => state.project.projectTaskBoundries); + const projectIndex = projectData.findIndex((project) => project.id == parseInt(currentProjectId)); const currentStatus = { ...taskBoundaryData?.[projectIndex]?.taskBoundries?.filter((task) => { return task?.index == taskId; @@ -45,7 +58,7 @@ export default function Dialog({ taskId, feature, map, view }) { useEffect(() => { if (taskInfo?.length === 0) return; - const currentTaskInfo = taskInfo?.filter((task) => taskId == task?.index); + const currentTaskInfo = taskInfo?.filter((task) => taskId.toString() === task?.index); if (currentTaskInfo?.[0]) { setCurrentTaskInfo(currentTaskInfo?.[0]); } @@ -77,8 +90,6 @@ export default function Dialog({ taskId, feature, map, view }) { taskBoundaryData, currentProjectId, feature, - map, - view, taskId, authDetailsCopy, { project_id: currentProjectId }, @@ -165,6 +176,7 @@ export default function Dialog({ taskId, feature, map, view }) { onClick={(e) => { if ( data.key === 'Mark as fully mapped' && + currentTaskInfo && currentTaskInfo?.submission_count < currentTaskInfo?.feature_count ) { setToggleMappedConfirmationModal(true); diff --git a/src/frontend/src/components/GenerateBasemap.jsx b/src/frontend/src/components/GenerateBasemap.tsx similarity index 93% rename from src/frontend/src/components/GenerateBasemap.jsx rename to src/frontend/src/components/GenerateBasemap.tsx index 3d5918243e..f72c7c0e35 100644 --- a/src/frontend/src/components/GenerateBasemap.jsx +++ b/src/frontend/src/components/GenerateBasemap.tsx @@ -5,23 +5,25 @@ import { CommonActions } from '@/store/slices/CommonSlice'; import environment from '@/environment'; import { DownloadTile, GenerateProjectTiles, GetTilesList } from '@/api/Project'; import { ProjectActions } from '@/store/slices/ProjectSlice'; +import { projectInfoType } from '@/models/project/projectModel'; +import { useAppSelector } from '@/types/reduxTypes'; -const GenerateBasemap = ({ projectInfo }) => { +const GenerateBasemap = ({ projectInfo }: { projectInfo: Partial }) => { const dispatch = CoreModules.useAppDispatch(); const params = CoreModules.useParams(); - const id = params.id; + const id: string = params.id; const [selectedTileSource, setSelectedTileSource] = useState(''); const [selectedOutputFormat, setSelectedOutputFormat] = useState(''); const [tmsUrl, setTmsUrl] = useState(''); - const [error, setError] = useState([]); + const [error, setError] = useState([]); - const toggleGenerateMbTilesModal = CoreModules.useAppSelector((state) => state.project.toggleGenerateMbTilesModal); - const defaultTheme = CoreModules.useAppSelector((state) => state.theme.hotTheme); - const generateProjectTilesLoading = CoreModules.useAppSelector((state) => state.project.generateProjectTilesLoading); - const tilesList = CoreModules.useAppSelector((state) => state.project.tilesList); + const toggleGenerateMbTilesModal = useAppSelector((state) => state.project.toggleGenerateMbTilesModal); + const defaultTheme = useAppSelector((state) => state.theme.hotTheme); + const generateProjectTilesLoading = useAppSelector((state) => state.project.generateProjectTilesLoading); + const tilesList = useAppSelector((state) => state.project.tilesList); - const modalStyle = (theme) => ({ + const modalStyle = (theme: Record) => ({ width: '90vw', // Responsive modal width using vw // height: '90vh', bgcolor: theme.palette.mode === 'dark' ? '#0A1929' : 'white', @@ -57,7 +59,7 @@ const GenerateBasemap = ({ projectInfo }) => { } }, [projectInfo]); - const handleTileSourceChange = (e) => { + const handleTileSourceChange = (e: React.ChangeEvent) => { setSelectedTileSource(e.target.value); // If 'tms' is selected, clear the TMS URL if (e.target.value !== 'tms') { @@ -65,12 +67,12 @@ const GenerateBasemap = ({ projectInfo }) => { } }; - const handleTmsUrlChange = (e) => { + const handleTmsUrlChange = (e: React.ChangeEvent) => { setTmsUrl(e.target.value); }; const generateProjectTilesValidation = () => { - const currentError = []; + const currentError: string[] = []; if (!selectedTileSource) { currentError.push('selectedTileSource'); } @@ -343,7 +345,6 @@ const GenerateBasemap = ({ projectInfo }) => { ))} - diff --git a/src/frontend/src/components/MapDescriptionComponents.jsx b/src/frontend/src/components/MapDescriptionComponents.jsx deleted file mode 100755 index 83b3501a38..0000000000 --- a/src/frontend/src/components/MapDescriptionComponents.jsx +++ /dev/null @@ -1,74 +0,0 @@ -import React from 'react'; -import CustomizedMenus from '@/utilities/CustomizedMenus'; -import CoreModules from '@/shared/CoreModules'; - -const MapDescriptionComponents = ({ type, state, defaultTheme }) => { - const descriptionData = [ - { - value: 'Description', - element: {state.projectInfo.description}, - }, - // { - // value: "Instructions", - // element: ( - // - // {state.projectInfo.location_str} - // - // ), - // }, - // { - // value: "Legends", - // element: ( - // - // ), - // }, - ]; - return ( - - - {descriptionData.map((data, index) => { - return ( - - ); - })} - - - ); -}; - -export default MapDescriptionComponents; diff --git a/src/frontend/src/components/MapLegends.jsx b/src/frontend/src/components/MapLegends.tsx similarity index 88% rename from src/frontend/src/components/MapLegends.jsx rename to src/frontend/src/components/MapLegends.tsx index c8a3286ac0..3fde7ad969 100755 --- a/src/frontend/src/components/MapLegends.jsx +++ b/src/frontend/src/components/MapLegends.tsx @@ -2,8 +2,15 @@ import React from 'react'; import CoreModules from '@/shared/CoreModules'; import AssetModules from '@/shared/AssetModules'; -const MapLegends = ({ iconBtnProps, defaultTheme }) => { - const MapDetails = [ +type mapDetialsType = { + value: string; + color: string; + status: string; + type?: string; +}; + +const MapLegends = ({ defaultTheme }: { defaultTheme: any }) => { + const MapDetails: mapDetialsType[] = [ { value: 'Ready', color: defaultTheme.palette.mapFeatureColors.ready, @@ -42,14 +49,13 @@ const MapLegends = ({ iconBtnProps, defaultTheme }) => { }, ]; - const LegendListItem = ({ data }) => { + const LegendListItem = ({ data }: { data: mapDetialsType }) => { return (
{data.type !== 'locked' ? ( { - const [toggleCurrentLoc, setToggleCurrentLoc] = useState(false); - const [currentLocLayer, setCurrentLocLayer] = useState(null); - const dispatch = CoreModules.useAppDispatch(); - const taskModalStatus = CoreModules.useAppSelector((state) => state.project.taskModalStatus); - const { windowSize } = WindowDimension(); - - function elastic(t) { - return Math.pow(2, -10 * t) * Math.sin(((t - 0.075) * (2 * Math.PI)) / 0.3) + 1; - } - - useEffect(() => { - let btnsPosition = 0; - var btnList = ['add', 'minus', 'defaultPosition', 'taskBoundries']; - - if (map != undefined) { - var handleOnClick = function (e) { - if (e.target.id == 'add') { - let actualZoom = map.getView().getZoom(); - map.getView().setZoom(actualZoom + 1); - } else if (e.target.id == 'minus') { - let actualZoom = map.getView().getZoom(); - map.getView().setZoom(actualZoom - 1); - } else if (e.target.id == 'defaultPosition') { - setToggleCurrentLoc(!toggleCurrentLoc); - const sourceProjection = 'EPSG:4326'; // The current projection of the coordinates - const targetProjection = 'EPSG:3857'; // The desired projection - // Create a style for the marker - var markerStyle = new Style({ - image: new Icon({ - src: LocationImage, // Path to your marker icon image - anchor: [0.5, 1], // Anchor point of the marker icon (center bottom) - scale: 2, // Scale factor for the marker icon - }), - }); - if ('geolocation' in navigator) { - if (!toggleCurrentLoc) { - navigator.geolocation.getCurrentPosition((position) => { - const lat = position.coords.latitude; - const lng = position.coords.longitude; - const convertedCoordinates = transform([lng, lat], sourceProjection, targetProjection); - const positionFeature = new ol.Feature(new Point(convertedCoordinates)); - const positionLayer = new Vector({ - source: new VectorSource({ - features: [positionFeature], - }), - }); - positionFeature.setStyle(markerStyle); - setCurrentLocLayer(positionLayer); - }); - } else { - setCurrentLocLayer(null); - } - } - } else if (e.target.id == 'taskBoundries') { - const layers = map.getAllLayers(); - let extent; - layers.map((layer) => { - if (layer instanceof VectorLayer) { - const layerName = layer.getProperties().name; - if (layerName === 'project-area') { - extent = layer.getSource().getExtent(); - } - } - }); - map.getView().fit(extent, { - padding: [10, 10, 10, 10], - }); - - map.getTargetElement().classList.remove('spinner'); - } - }; - - //List buttons avoiding code duplication - btnList.map((elmnt, index) => { - //Add Button - let btn = document.createElement('button'); - if (elmnt == 'add') { - btn.innerHTML = '+'; - btn.style.fontSize = defaultTheme.typography.fontSize; - } else if (elmnt == 'minus') { - btn.innerHTML = '-'; - btn.style.fontSize = defaultTheme.typography.fontSize; - } else if (elmnt == 'defaultPosition') { - let img = document.createElement('img'); - img.src = locationImg; - img.id = `${elmnt}`; - img.addEventListener('click', handleOnClick, false); - btn.appendChild(img); - btn.style.display = 'flex'; - btn.style.alignItems = 'center'; - btn.style.justifyContent = 'center'; - - if (!toggleCurrentLoc) { - btn.style.backgroundColor = 'white'; - } else { - btn.style.backgroundColor = '#E6E6E6'; - } - } else if (elmnt == 'taskBoundries') { - let img = document.createElement('img'); - img.src = gridIcon; - img.id = `${elmnt}`; - img.addEventListener('click', handleOnClick, false); - btn.appendChild(img); - btn.style.display = 'flex'; - btn.style.alignItems = 'center'; - btn.style.justifyContent = 'center'; - } - btn.id = `${elmnt}`; - // btn.style.backgroundColor = 'white'; - btn.style.boxShadow = `0 2px 2px 0 ${defaultTheme.palette.info['main']}`; - btn.style.width = '40px'; - btn.style.height = '40px'; - btn.style.borderRadius = '50%'; - btn.addEventListener('click', handleOnClick, false); - - //Add Button Div - let btnDiv = document.createElement('div'); - btnDiv.id = 'btnsContainer'; - btnDiv.style.borderRadius = '50%'; - btnDiv.className = 'ol-unselectable ol-control'; - index == 0 - ? (btnDiv.style.top = `${(btnsPosition = btnsPosition + 2)}%`) - : windowSize.width >= 640 - ? (btnDiv.style.top = `${(btnsPosition = btnsPosition + 9)}%`) - : (btnDiv.style.top = `${(btnsPosition = btnsPosition + 6)}%`); - btnDiv.appendChild(btn); - var control = new Control({ - element: btnDiv, - }); - - map.addControl(control); - }); - - const MapDetails = [ - { - value: 'Ready', - color: defaultTheme.palette.mapFeatureColors.ready, - status: 'none', - }, - { - value: 'Locked For Mapping', - color: defaultTheme.palette.mapFeatureColors.locked_for_mapping, - status: 'lock', - }, - { - value: 'Ready For Validation', - color: defaultTheme.palette.mapFeatureColors.mapped, - status: 'none', - }, - { - value: 'Locked For Validation', - color: defaultTheme.palette.mapFeatureColors.locked_for_validation, - status: 'lock', - }, - { - value: 'Validated', - color: defaultTheme.palette.mapFeatureColors.validated, - status: 'none', - }, - { - value: 'More mapping needed', - color: defaultTheme.palette.mapFeatureColors.invalidated, - status: 'none', - }, - { - value: 'Locked', - color: defaultTheme.palette.mapFeatureColors.invalidated, - status: 'none', - type: 'locked', - }, - ]; - let legendContainer = document.createElement('div'); - legendContainer.className = 'legend-container'; - const legendLabel = document.createElement('span'); - legendLabel.innerHTML = 'Legend'; - const legendAccIcon = document.createElement('span'); - legendAccIcon.className = 'legend-acc-icon'; - let img = document.createElement('img'); - img.src = accDownImg; - img.style.width = '24px'; - img.style.height = '24px'; - img.style.display = 'none'; - let accUp = document.createElement('img'); - accUp.src = accUpImg; - accUp.style.width = '18px'; - accUp.style.height = '18px'; - - legendAccIcon.appendChild(img); - legendAccIcon.appendChild(accUp); - legendContainer.appendChild(legendLabel); - legendContainer.appendChild(legendAccIcon); - - let legendContent = document.createElement('div'); - legendContent.className = 'legend-content'; - legendContent.style.display = 'none'; - legendContainer.style.margin = '552px 6px'; - MapDetails.forEach((detail) => { - const legend = document.createElement('div'); - legend.className = 'legend'; - - const legendText = document.createElement('span'); - legendText.className = 'legend-text'; - legendText.textContent = detail.value; - - if (detail.type === 'locked') { - const legendSquare = document.createElement('img'); - legendSquare.className = 'legend-lock-img'; - legendSquare.style.height = '20px'; - legendSquare.src = AssetModules.LockPng; - legend.appendChild(legendText); - legend.appendChild(legendSquare); - } else { - const legendSquare = document.createElement('div'); - legendSquare.className = 'legend-square'; - legendSquare.style.backgroundColor = detail.color; - legend.appendChild(legendText); - legend.appendChild(legendSquare); - } - - legendContent.appendChild(legend); - }); - legendContainer.appendChild(legendContent); - // Add event listener to toggle the accordion content - legendAccIcon.addEventListener('click', function () { - if (legendContent.style.display === 'none') { - accUp.style.display = 'none'; - img.style.display = 'inline'; - legendContent.style.display = 'block'; - legendContainer.style.margin = '200px 10px'; - } else { - img.style.display = 'none'; - accUp.style.display = 'inline'; - legendContent.style.display = 'none'; - legendContainer.style.margin = '552px 6px'; - } - }); - var controlx = new Control({ - element: legendContainer, - }); - - map.addControl(controlx); - } - }, [map, toggleCurrentLoc]); - - useEffect(() => { - if (!map) return; - if (!currentLocLayer) return; - map.addLayer(currentLocLayer); - map.getView().fit(currentLocLayer.getSource().getExtent(), { - maxZoom: 18, - duration: 500, - }); - return () => { - map.removeLayer(currentLocLayer); - }; - }, [map, currentLocLayer]); - - return ( - - -
-
-
- ); -}; - -export default OpenLayersMap; diff --git a/src/frontend/src/components/ProjectDetailsV2/ActivitiesPanel.tsx b/src/frontend/src/components/ProjectDetailsV2/ActivitiesPanel.tsx index d759004a0e..ca3ac6a6ca 100644 --- a/src/frontend/src/components/ProjectDetailsV2/ActivitiesPanel.tsx +++ b/src/frontend/src/components/ProjectDetailsV2/ActivitiesPanel.tsx @@ -4,29 +4,34 @@ import AssetModules from '@/shared/AssetModules'; import { Feature } from 'ol'; import { Polygon } from 'ol/geom'; import { ActivitiesCardSkeletonLoader, ShowingCountSkeletonLoader } from '@/components/ProjectDetailsV2/SkeletonLoader'; -import { taskHistoryListType } from '@/models/project/projectModel'; import { useAppSelector } from '@/types/reduxTypes'; -import { useDispatch } from 'react-redux'; +import { projectTaskActivity } from '@/store/types/IProject'; +import { projectTaskBoundriesType } from '@/models/project/projectModel'; -const ActivitiesPanel = ({ defaultTheme, state, params, map, view, mapDivPostion, states }) => { - const dispatch = useDispatch(); - const id = params.id; +type activitiesPanelType = { + defaultTheme: any; + state: projectTaskBoundriesType[]; + params: Record; + map: any; +}; + +const ActivitiesPanel = ({ defaultTheme, state, params, map }: activitiesPanelType) => { const [searchText, setSearchText] = useState(''); - const [taskHistories, setTaskHistories] = useState([]); + const [taskHistories, setTaskHistories] = useState([]); const [allActivities, setAllActivities] = useState(0); const projectActivityLoading = useAppSelector((state) => state?.project?.projectActivityLoading); const projectTaskActivityList = useAppSelector((state) => state?.project?.projectTaskActivity); const selectedTask = useAppSelector((state) => state.task.selectedTask); - const handleOnchange = (event) => { + const handleOnchange = (event: React.ChangeEvent) => { setSearchText(event.target.value); }; useEffect(() => { - let taskHistories: taskHistoryListType[] = projectTaskActivityList; + let taskHistories: projectTaskActivity[] = projectTaskActivityList; setAllActivities(projectTaskActivityList.length); - let finalTaskHistory: taskHistoryListType[] = taskHistories.filter((task) => { + let finalTaskHistory: projectTaskActivity[] = taskHistories.filter((task) => { return task.action_text.split(':')[1].replace(/\s+/g, '').toString().includes(searchText.toString()); }); if (searchText != '') { @@ -36,8 +41,8 @@ const ActivitiesPanel = ({ defaultTheme, state, params, map, view, mapDivPostion } }, [state, searchText, projectTaskActivityList, selectedTask]); - const zoomToTask = (taskId) => { - let geojson = {}; + const zoomToTask = (taskId: number | null) => { + let geojson: Record = {}; const index = state.findIndex((project) => project.id == params.id); if (index != -1) { const taskIndex = state[index]?.taskBoundries.findIndex((task) => task?.index == taskId); @@ -56,7 +61,7 @@ const ActivitiesPanel = ({ defaultTheme, state, params, map, view, mapDivPostion }); }; - const ActivitiesCard = ({ taskHistory }: { taskHistory: taskHistoryListType }) => { + const ActivitiesCard = ({ taskHistory }: { taskHistory: projectTaskActivity }) => { const actionDate = taskHistory?.action_date?.split('T')[0]; const actionTime = `${taskHistory?.action_date?.split('T')[1].split(':')[0]}:${taskHistory?.action_date ?.split('T')[1] diff --git a/src/frontend/src/components/ProjectDetailsV2/FeatureSelectionPopup.tsx b/src/frontend/src/components/ProjectDetailsV2/FeatureSelectionPopup.tsx index a0b5b64ecc..8352ce64f2 100644 --- a/src/frontend/src/components/ProjectDetailsV2/FeatureSelectionPopup.tsx +++ b/src/frontend/src/components/ProjectDetailsV2/FeatureSelectionPopup.tsx @@ -17,17 +17,9 @@ type TaskFeatureSelectionPopupPropType = { taskId: number; featureProperties: TaskFeatureSelectionProperties | null; taskFeature: Record; - map: any; - view: any; }; -const TaskFeatureSelectionPopup = ({ - featureProperties, - taskId, - taskFeature, - map, - view, -}: TaskFeatureSelectionPopupPropType) => { +const TaskFeatureSelectionPopup = ({ featureProperties, taskId, taskFeature }: TaskFeatureSelectionPopupPropType) => { const dispatch = CoreModules.useAppDispatch(); const params = useParams(); const geojsonStyles = MapStyles(); @@ -153,8 +145,6 @@ const TaskFeatureSelectionPopup = ({ taskBoundaryData, currentProjectId, taskFeature, - map, - view, taskId, authDetails, { project_id: currentProjectId }, diff --git a/src/frontend/src/components/ProjectDetailsV2/Instructions.tsx b/src/frontend/src/components/ProjectDetailsV2/Instructions.tsx index dbba6d21f5..20abd5f2ca 100644 --- a/src/frontend/src/components/ProjectDetailsV2/Instructions.tsx +++ b/src/frontend/src/components/ProjectDetailsV2/Instructions.tsx @@ -1,7 +1,7 @@ import React from 'react'; import RichTextEditor from '@/components/common/Editor/Editor'; -const Instructions = ({ instructions }: { instructions: string }) => { +const Instructions = ({ instructions }: { instructions: string | undefined }) => { return (
{instructions ? ( diff --git a/src/frontend/src/components/ProjectDetailsV2/MobileActivitiesContents.tsx b/src/frontend/src/components/ProjectDetailsV2/MobileActivitiesContents.tsx index 3bb9306a7d..7cf700aefe 100644 --- a/src/frontend/src/components/ProjectDetailsV2/MobileActivitiesContents.tsx +++ b/src/frontend/src/components/ProjectDetailsV2/MobileActivitiesContents.tsx @@ -3,22 +3,18 @@ import ActivitiesPanel from '@/components/ProjectDetailsV2/ActivitiesPanel'; import CoreModules from '@/shared/CoreModules'; import { useAppSelector } from '@/types/reduxTypes'; -const MobileActivitiesContents = ({ map, mainView, mapDivPostion }) => { - const params = CoreModules.useParams(); +type mobileActivitiesContentsType = { + map: any; +}; + +const MobileActivitiesContents = ({ map }: mobileActivitiesContentsType) => { + const params: Record = CoreModules.useParams(); const state = useAppSelector((state) => state.project); const defaultTheme = useAppSelector((state) => state.theme.hotTheme); return (
- +
); }; diff --git a/src/frontend/src/components/ProjectDetailsV2/MobileProjectInfoContent.tsx b/src/frontend/src/components/ProjectDetailsV2/MobileProjectInfoContent.tsx index 686c87ceab..8715e8eb63 100644 --- a/src/frontend/src/components/ProjectDetailsV2/MobileProjectInfoContent.tsx +++ b/src/frontend/src/components/ProjectDetailsV2/MobileProjectInfoContent.tsx @@ -4,7 +4,7 @@ import { projectInfoType } from '@/models/project/projectModel'; import Button from '@/components/common/Button'; import { useNavigate } from 'react-router-dom'; -const MobileProjectInfoContent = ({ projectInfo }: { projectInfo: projectInfoType }) => { +const MobileProjectInfoContent = ({ projectInfo }: { projectInfo: Partial }) => { const navigate = useNavigate(); return ( diff --git a/src/frontend/src/components/ProjectDetailsV2/ProjectOptions.tsx b/src/frontend/src/components/ProjectDetailsV2/ProjectOptions.tsx index 6b91d2cb21..5aaec38323 100644 --- a/src/frontend/src/components/ProjectDetailsV2/ProjectOptions.tsx +++ b/src/frontend/src/components/ProjectDetailsV2/ProjectOptions.tsx @@ -6,7 +6,7 @@ import Button from '@/components/common/Button'; import { useAppSelector } from '@/types/reduxTypes'; type projectOptionPropTypes = { - projectName: string; + projectName: string | undefined; }; const ProjectOptions = ({ projectName }: projectOptionPropTypes) => { diff --git a/src/frontend/src/components/ProjectDetailsV2/TaskSelectionPopup.tsx b/src/frontend/src/components/ProjectDetailsV2/TaskSelectionPopup.tsx index 93f316bf57..0cd127de9b 100644 --- a/src/frontend/src/components/ProjectDetailsV2/TaskSelectionPopup.tsx +++ b/src/frontend/src/components/ProjectDetailsV2/TaskSelectionPopup.tsx @@ -7,6 +7,7 @@ import { ProjectActions } from '@/store/slices/ProjectSlice'; import environment from '@/environment'; import { GetProjectQrCode } from '@/api/Files'; import QrcodeComponent from '@/components/QrcodeComponent'; +import { useAppSelector } from '@/types/reduxTypes'; type TaskSelectionPopupPropType = { taskId: number | null; @@ -17,15 +18,14 @@ type TaskSelectionPopupPropType = { const TaskSelectionPopup = ({ taskId, body, feature }: TaskSelectionPopupPropType) => { const dispatch = CoreModules.useAppDispatch(); const [task_status, set_task_status] = useState('READY'); - const taskModalStatus = CoreModules.useAppSelector((state) => state.project.taskModalStatus); + const taskModalStatus = useAppSelector((state) => state.project.taskModalStatus); const params = CoreModules.useParams(); - const currentProjectId = params.id; - const projectData = CoreModules.useAppSelector((state) => state.project.projectTaskBoundries); - const projectIndex = projectData.findIndex((project) => project.id == currentProjectId); + const currentProjectId: string = params.id; + const projectData = useAppSelector((state) => state.project.projectTaskBoundries); + const projectIndex = projectData.findIndex((project) => project.id.toString() === currentProjectId); - //qrcodecomponent - const projectName = CoreModules.useAppSelector((state) => state.project.projectInfo.title); - const odkToken = CoreModules.useAppSelector((state) => state.project.projectInfo.odk_token); + const projectName = useAppSelector((state) => state.project.projectInfo.title); + const odkToken = useAppSelector((state) => state.project.projectInfo.odk_token); const authDetails = CoreModules.useAppSelector((state) => state.login.authDetails); const selectedTask = { ...projectData?.[projectIndex]?.taskBoundries?.filter((indTask, i) => { @@ -35,7 +35,7 @@ const TaskSelectionPopup = ({ taskId, body, feature }: TaskSelectionPopupPropTyp const checkIfTaskAssignedOrNot = selectedTask?.locked_by_username === authDetails?.username || selectedTask?.locked_by_username === null; - const { qrcode } = GetProjectQrCode(odkToken, projectName, authDetails?.username); + const { qrcode }: { qrcode: string } = GetProjectQrCode(odkToken, projectName, authDetails?.username); useEffect(() => { if (projectIndex != -1) { const currentStatus = { diff --git a/src/frontend/src/components/QrcodeComponent.jsx b/src/frontend/src/components/QrcodeComponent.tsx similarity index 91% rename from src/frontend/src/components/QrcodeComponent.jsx rename to src/frontend/src/components/QrcodeComponent.tsx index a1362cfa90..53aa08e4ef 100755 --- a/src/frontend/src/components/QrcodeComponent.jsx +++ b/src/frontend/src/components/QrcodeComponent.tsx @@ -2,7 +2,13 @@ import React from 'react'; import CoreModules from '@/shared/CoreModules'; import AssetModules from '@/shared/AssetModules'; -const TasksComponent = ({ qrcode, projectId, taskIndex }) => { +type tasksComponentType = { + qrcode: string; + projectId: string; + taskIndex: number; +}; + +const TasksComponent = ({ qrcode, projectId, taskIndex }: tasksComponentType) => { const downloadQR = () => { const downloadLink = document.createElement('a'); downloadLink.href = qrcode; diff --git a/src/frontend/src/components/SubmissionMap/SubmissionInstanceMap.jsx b/src/frontend/src/components/SubmissionMap/SubmissionInstanceMap.tsx similarity index 83% rename from src/frontend/src/components/SubmissionMap/SubmissionInstanceMap.jsx rename to src/frontend/src/components/SubmissionMap/SubmissionInstanceMap.tsx index a8fb867d6d..88f81c75cb 100644 --- a/src/frontend/src/components/SubmissionMap/SubmissionInstanceMap.jsx +++ b/src/frontend/src/components/SubmissionMap/SubmissionInstanceMap.tsx @@ -1,12 +1,16 @@ -import React, { useState } from 'react'; +import React from 'react'; import useOLMap from '@/hooks/useOlMap'; import { MapContainer as MapComponent } from '@/components/MapComponent/OpenLayersComponent'; import LayerSwitcherControl from '@/components/MapComponent/OpenLayersComponent/LayerSwitcher/index.js'; import { VectorLayer } from '@/components/MapComponent/OpenLayersComponent/Layers'; import { defaultStyles } from '@/components/MapComponent/OpenLayersComponent/helpers/styleUtils'; -const SubmissionInstanceMap = ({ featureGeojson }) => { - const { mapRef, map } = useOLMap({ +type submissionInstanceMapPropType = { + featureGeojson: Record; +}; + +const SubmissionInstanceMap = ({ featureGeojson }: submissionInstanceMapPropType) => { + const { mapRef, map }: { mapRef: any; map: any } = useOLMap({ center: [0, 0], zoom: 4, maxZoom: 25, diff --git a/src/frontend/src/components/home/ExploreProjectCard.tsx b/src/frontend/src/components/home/ExploreProjectCard.tsx index a738a6ae0d..1c07c270d9 100755 --- a/src/frontend/src/components/home/ExploreProjectCard.tsx +++ b/src/frontend/src/components/home/ExploreProjectCard.tsx @@ -2,17 +2,18 @@ import * as React from 'react'; import CustomizedImage from '@/utilities/CustomizedImage'; import CustomizedProgressBar from '@/utilities/CustomizedProgressBar'; import { HomeActions } from '@/store/slices/HomeSlice'; -import { HomeProjectCardModel, projectType } from '@/models/home/homeModel'; +import { projectType } from '@/models/home/homeModel'; import CoreModules from '@/shared/CoreModules'; import AssetModules from '@/shared/AssetModules'; +import { useAppSelector } from '@/types/reduxTypes'; //Explore Project Card Model to be rendered in home view export default function ExploreProjectCard({ data }: { data: projectType }) { - const [shadowBox, setShadowBox] = React.useState(0); - const dispatch = CoreModules.useAppDispatch(); - const defaultTheme: any = CoreModules.useAppSelector((state) => state.theme.hotTheme); - //use navigate hook for from react router dom for rounting purpose const navigate = CoreModules.useNavigate(); + const dispatch = CoreModules.useAppDispatch(); + + const [shadowBox, setShadowBox] = React.useState(0); + const defaultTheme = useAppSelector((state) => state.theme.hotTheme); //on mounse enter an Element set shadow to 3 const onHoverIn = () => { @@ -31,13 +32,10 @@ export default function ExploreProjectCard({ data }: { data: projectType }) { marginTop: '5%', position: 'absolute', fontFamily: defaultTheme.typography.h3.fontFamily, - // backgroundColor: defaultTheme.palette.error['main'], - // color: defaultTheme.palette.primary['main'], right: 6, borderRadius: '0px', }, card: { - // border: `1px solid #e1e0e0`, marginLeft: '0.1%', marginRight: '0.1%', marginTop: '0.7%', @@ -46,18 +44,17 @@ export default function ExploreProjectCard({ data }: { data: projectType }) { opacity: 0.9, position: 'relative', }, - location: { icon: { fontSize: 22, }, }, }; + return ( { const project: projectType = data; - // dispatch(ProjectActions.SetProjectTaskBoundries([])) dispatch(HomeActions.SetSelectedProject(project)); navigate(`/project/${data.id}`); }} @@ -78,27 +75,10 @@ export default function ExploreProjectCard({ data }: { data: projectType }) { ) : ( )} - - {/*Id Number*/} #{data.id} - {/* <======End======> */}
- {/*Priority Button and Image*/} - {/*
- - {data.priority_str} - - -
*/} - {/* <======End======> */} {/*Project Info and description*/} @@ -122,11 +102,9 @@ export default function ExploreProjectCard({ data }: { data: projectType }) {

- {/* <======End======> */}
- {/* Contributors */} - {/* <======End======> */} {/* Contribution Progress Bar */} - {/* <======End======> */}
diff --git a/src/frontend/src/models/project/projectModel.ts b/src/frontend/src/models/project/projectModel.ts index 7108c0a7af..d9a3422ba2 100644 --- a/src/frontend/src/models/project/projectModel.ts +++ b/src/frontend/src/models/project/projectModel.ts @@ -69,6 +69,8 @@ export type projectInfoType = { total_tasks: any; organisation_id: number; organisation_logo: string; + instructions: string; + custom_tms_url: string; }; export type downloadProjectFormLoadingType = { type: 'form' | 'geojson' | 'csv' | 'json'; loading: boolean }; diff --git a/src/frontend/src/store/slices/ThemeSlice.ts b/src/frontend/src/store/slices/ThemeSlice.ts index 0fac18638d..4d309460af 100755 --- a/src/frontend/src/store/slices/ThemeSlice.ts +++ b/src/frontend/src/store/slices/ThemeSlice.ts @@ -1,179 +1,157 @@ import { createSlice } from '@reduxjs/toolkit'; -const ThemeSlice = createSlice({ - name: 'theme', - initialState: { - hotTheme: { - palette: { - black: '#000000', - mode: 'light', - primary: { - main: '#ffffff', - contrastText: '#44546a', - lightblue: '#99e6ff', - primary_rgb: 'rgb(255, 255, 255,0.8)', - }, - error: { - //hot red - main: '#d73f3e', - purple: '#ff3399', - }, - success: { - //hot blue - //green in regular - main: '#459ca0', - contrastText: '#2C3038', - }, - warning: { - //hot yellow - main: '#f9a61e', - contrastText: '#2C3038', - }, - grey: { - //hot grey and light - main: '#a5a5a5', - light: '#f0efee', - contrastText: '#2C3038', - }, - info: { - //hot dark - main: '#44546a', - contrastText: '#2C3038', - info_rgb: 'rgb(44,48,56,0.2)', - }, - text: { - secondary: '#2C3038', - }, - loading: { - skeleton_rgb: 'rgb(112, 67, 67,0.1)', - }, - mapFeatureColors: { - //blue - ready: 'rgba(255,255,255, 0.5)', - ready_rgb: 'rgba(255,255,255, 0.5)', - locked_for_mapping: 'rgba(0, 128, 153, 0.5)', - locked_for_mapping_rgb: 'rgba(0, 128, 153, 0.5)', - mapped: 'rgba(173, 230, 239, 0.8)', - mapped_rgb: 'rgba(173, 230, 239, 0.8)', - locked_for_validation: 'rgb(252,236,164,0.5)', - locked_for_validation_rgb: 'rgb(252,236,164,0.5)', - //green - validated: 'rgba(64, 172, 140, 0.5)', - validated_rgb: 'rgba(64, 172, 140, 0.5)', - //yellow - // invalidated: '#ffff00', - invalidated: 'rgb(215,63,62,0.5)', - invalidated_rgb: 'rgb(215,63,62,0.5)', - //brown - bad: 'rgba(216, 218, 228, 0.5)', - bad_rgb: 'rgba(216, 218, 228, 0.5)', - split: 'rgb(112, 67, 67,0.5)', - split_rgb: 'rgb(112, 67, 67,0.5)', - }, - }, - statusTextTheme: { - READY: '#a3a2a2', - LOCKED_FOR_MAPPING: '#097085', - MAPPED: '#64cfe3', - LOCKED_FOR_VALIDATION: '#C5BD0A', - VALIDATED: '#44c9a2', - INVALIDATED: '#D73F37', - }, - READY: '#fff', - LOCKED_FOR_MAPPING: '#fff', - MAPPED: '#ade6ef', - LOCKED_FOR_VALIDATION: '#ade6ef', - VALIDATED: '#40ac8c', - INVALIDATED: '#fceca4', - BADIMAGERY: '#d8dae4', - PRIORITY_AREAS: '#efd1d1', - // mapFeatureColors: { - // //blue - // ready: '#008099', - // ready_rgb: 'rgb(0, 128, 153,0.4)', - // locked_for_mapping: '#0063cc', - // locked_for_mapping_rgb: 'rgb(0, 99, 204,0.4)', - // mapped: '#161969', - // mapped_rgb: 'rgb(22, 25, 105,0.4)', - // locked_for_validation: '#3d1c97', - // locked_for_validation_rgb: 'rgb(61, 28, 151,0.4)', - // //green - // validated: '#006600', - // validated_rgb: 'rgb(0, 102, 0,0.4)', - // //yellow - // // invalidated: '#ffff00', - // invalidated: '#ffcc00', - // invalidated_rgb: 'rgb(255, 204, 0,0.4)', - // //brown - // bad: '#704343', - // bad_rgb: 'rgb(112, 67, 67,0.4)', - // split: '#704343', - // split_rgb: 'rgb(112, 67, 67,0.4)', - // }, - // }, - typography: { - //default font family changed to BarlowMedium - fontSize: 16, - // fontFamily: 'ArchivoMedium', - fontFamily: 'BarlowMedium', - //custom - htmlFontSize: 18, +type themeStateType = { + hotTheme: any; +}; - barlowCondensed: { - fontFamily: 'Barlow Condensed', - fontSize: '24px', - }, - caption: { - fontFamily: 'BarlowBold', - fontSize: 24, - }, - // new font size added - condensed: { - fontSize: 36, - fontWeight: 'bold', - }, - subtitle1: { - fontFamily: 'BarlowBold', - fontSize: 24, - fontWeight: 'bold', - }, - subtitle2: { - fontFamily: 'BarlowMedium', - fontSize: 20, - fontWeight: 'bold', - }, - subtitle3: { - fontFamily: 'BarlowMedium', - fontSize: 15, - }, - h1: { - fontFamily: 'BarlowMedium', - fontSize: 20, - }, - h2: { - fontFamily: 'BarlowMedium', - fontSize: 16, - }, - h3: { - fontFamily: 'BarlowMedium', - fontSize: 16, - }, - h4: { - fontFamily: 'BarlowLight', - fontSize: 16, - }, - p: { - fontFamily: 'Archivo', - fontSize: 16, - }, +const initialState: themeStateType = { + hotTheme: { + palette: { + black: '#000000', + mode: 'light', + primary: { + main: '#ffffff', + contrastText: '#44546a', + lightblue: '#99e6ff', + primary_rgb: 'rgb(255, 255, 255,0.8)', + }, + error: { + //hot red + main: '#d73f3e', + purple: '#ff3399', + }, + success: { + //hot blue + //green in regular + main: '#459ca0', + contrastText: '#2C3038', + }, + warning: { + //hot yellow + main: '#f9a61e', + contrastText: '#2C3038', + }, + grey: { + //hot grey and light + main: '#a5a5a5', + light: '#f0efee', + contrastText: '#2C3038', + }, + info: { + //hot dark + main: '#44546a', + contrastText: '#2C3038', + info_rgb: 'rgb(44,48,56,0.2)', + }, + text: { + secondary: '#2C3038', + }, + loading: { + skeleton_rgb: 'rgb(112, 67, 67,0.1)', + }, + mapFeatureColors: { + //blue + ready: 'rgba(255,255,255, 0.5)', + ready_rgb: 'rgba(255,255,255, 0.5)', + locked_for_mapping: 'rgba(0, 128, 153, 0.5)', + locked_for_mapping_rgb: 'rgba(0, 128, 153, 0.5)', + mapped: 'rgba(173, 230, 239, 0.8)', + mapped_rgb: 'rgba(173, 230, 239, 0.8)', + locked_for_validation: 'rgb(252,236,164,0.5)', + locked_for_validation_rgb: 'rgb(252,236,164,0.5)', + //green + validated: 'rgba(64, 172, 140, 0.5)', + validated_rgb: 'rgba(64, 172, 140, 0.5)', + //yellow + // invalidated: '#ffff00', + invalidated: 'rgb(215,63,62,0.5)', + invalidated_rgb: 'rgb(215,63,62,0.5)', + //brown + bad: 'rgba(216, 218, 228, 0.5)', + bad_rgb: 'rgba(216, 218, 228, 0.5)', + split: 'rgb(112, 67, 67,0.5)', + split_rgb: 'rgb(112, 67, 67,0.5)', }, }, - }, - reducers: { - UpdateBrightness(state, action) { - state.hotTheme = action.payload; + statusTextTheme: { + READY: '#a3a2a2', + LOCKED_FOR_MAPPING: '#097085', + MAPPED: '#64cfe3', + LOCKED_FOR_VALIDATION: '#C5BD0A', + VALIDATED: '#44c9a2', + INVALIDATED: '#D73F37', + }, + READY: '#fff', + LOCKED_FOR_MAPPING: '#fff', + MAPPED: '#ade6ef', + LOCKED_FOR_VALIDATION: '#ade6ef', + VALIDATED: '#40ac8c', + INVALIDATED: '#fceca4', + BADIMAGERY: '#d8dae4', + PRIORITY_AREAS: '#efd1d1', + typography: { + //default font family changed to BarlowMedium + fontSize: 16, + // fontFamily: 'ArchivoMedium', + fontFamily: 'BarlowMedium', + //custom + htmlFontSize: 18, + + barlowCondensed: { + fontFamily: 'Barlow Condensed', + fontSize: '24px', + }, + caption: { + fontFamily: 'BarlowBold', + fontSize: 24, + }, + // new font size added + condensed: { + fontSize: 36, + fontWeight: 'bold', + }, + subtitle1: { + fontFamily: 'BarlowBold', + fontSize: 24, + fontWeight: 'bold', + }, + subtitle2: { + fontFamily: 'BarlowMedium', + fontSize: 20, + fontWeight: 'bold', + }, + subtitle3: { + fontFamily: 'BarlowMedium', + fontSize: 15, + }, + h1: { + fontFamily: 'BarlowMedium', + fontSize: 20, + }, + h2: { + fontFamily: 'BarlowMedium', + fontSize: 16, + }, + h3: { + fontFamily: 'BarlowMedium', + fontSize: 16, + }, + h4: { + fontFamily: 'BarlowLight', + fontSize: 16, + }, + p: { + fontFamily: 'Archivo', + fontSize: 16, + }, }, }, +}; + +const ThemeSlice = createSlice({ + name: 'theme', + initialState: initialState, + reducers: {}, }); export const ThemeActions = ThemeSlice.actions; diff --git a/src/frontend/src/store/types/IProject.ts b/src/frontend/src/store/types/IProject.ts index 6ad827c5ca..27c6a10b21 100644 --- a/src/frontend/src/store/types/IProject.ts +++ b/src/frontend/src/store/types/IProject.ts @@ -67,9 +67,8 @@ type projectCommentsListTypes = { status: any; }; -type projectTaskActivity = { +export type projectTaskActivity = { id: number; - project_id: number; task_id: number; action: string; action_text: string; diff --git a/src/frontend/src/types/modulesDecleration.d.ts b/src/frontend/src/types/modulesDecleration.d.ts index a920ec5338..7676fea99a 100644 --- a/src/frontend/src/types/modulesDecleration.d.ts +++ b/src/frontend/src/types/modulesDecleration.d.ts @@ -1,2 +1,3 @@ declare module '*.png'; declare module 'ol/style'; +declare module 'pako/lib/deflate'; diff --git a/src/frontend/src/utilities/BasicDialog.jsx b/src/frontend/src/utilities/BasicDialog.jsx deleted file mode 100755 index 789258f90c..0000000000 --- a/src/frontend/src/utilities/BasicDialog.jsx +++ /dev/null @@ -1,31 +0,0 @@ -import * as React from 'react'; -import CoreModules from '@/shared/CoreModules'; -import AssetModules from '@/shared/AssetModules'; -export default function BasicDialog({ open, actions, title, onClose, subtitle }) { - return ( - - - - - - - - {title != undefined ? ( - - - {title} - - - ) : null} - {subtitle != undefined ? ( - - {subtitle} - - ) : null} - - - {actions} - - - ); -} diff --git a/src/frontend/src/utilities/BasicDialog.tsx b/src/frontend/src/utilities/BasicDialog.tsx deleted file mode 100755 index b339bc0268..0000000000 --- a/src/frontend/src/utilities/BasicDialog.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import * as React from 'react'; -import { TransitionProps } from '@mui/material/transitions'; -import CoreModules from '@/shared/CoreModules'; -import AssetModules from '@/shared/AssetModules'; - -const Transition = function Transition( - ref, - props: TransitionProps & { - children: React.ReactElement; - ref?: React.Ref; - }, -) { - return ; -}; - -export default function BasicDialog({ open, onClose, title, iconCloseMode, actionsButton, element }) { - return ( - - - - {iconCloseMode && ( - - - - - - )} - {title} - - {element} - {iconCloseMode != true && actionsButton} - - - ); -} diff --git a/src/frontend/src/utilities/CustomDrawer.jsx b/src/frontend/src/utilities/CustomDrawer.tsx similarity index 91% rename from src/frontend/src/utilities/CustomDrawer.jsx rename to src/frontend/src/utilities/CustomDrawer.tsx index e8d331f33f..69623ee565 100644 --- a/src/frontend/src/utilities/CustomDrawer.jsx +++ b/src/frontend/src/utilities/CustomDrawer.tsx @@ -1,7 +1,6 @@ -import React, { useEffect, useState } from 'react'; +import React, { useState } from 'react'; import SwipeableDrawer from '@mui/material/SwipeableDrawer'; import Button from '@/components/common/Button'; -import { Modal } from '@/components/common/Modal'; import CoreModules from '@/shared/CoreModules'; import AssetModules from '@/shared/AssetModules'; import { NavLink } from 'react-router-dom'; @@ -10,21 +9,35 @@ import { CommonActions } from '@/store/slices/CommonSlice'; import { LoginActions } from '@/store/slices/LoginSlice'; import { ProjectActions } from '@/store/slices/ProjectSlice'; import DebugConsole from '@/utilities/DebugConsole'; +import { useAppSelector } from '@/types/reduxTypes'; -export default function CustomDrawer({ open, placement, size, type, onClose, onSignOut, setOpen }) { - const defaultTheme = CoreModules.useAppSelector((state) => state.theme.hotTheme); +type customDrawerType = { + open: boolean; + size: { width: number; height: number }; + type: string; + onClose: () => void; + setOpen: (open: boolean) => void; +}; + +export default function CustomDrawer({ open, size, type, onClose, setOpen }: customDrawerType) { const dispatch = CoreModules.useAppDispatch(); + + const defaultTheme = useAppSelector((state) => state.theme.hotTheme); const [showDebugConsole, setShowDebugConsole] = useState(false); + const authDetails = CoreModules.useAppSelector((state) => state.login.authDetails); - const onMouseEnter = (event) => { - const element = document.getElementById(`text${event.target.id}`); + const onMouseEnter = (event: React.MouseEvent) => { + const targetElement = event.target as HTMLElement; + const element = document.getElementById(`text${targetElement.id}`); if (element) element.style.color = defaultTheme.palette.error.main; }; - const authDetails = CoreModules.useAppSelector((state) => state.login.authDetails); - const onMouseLeave = (event) => { - const element = document.getElementById(`text${event.target.id}`); + + const onMouseLeave = (event: React.MouseEvent) => { + const targetElement = event.target as HTMLElement; + const element = document.getElementById(`text${targetElement.id}`); if (element) element.style.color = defaultTheme.palette.info.main; }; + const Drawerstyles = { list: { width: type === 'xs' || type === 'sm' ? size.width - 48 : 350, diff --git a/src/frontend/src/utilities/CustomizedImage.jsx b/src/frontend/src/utilities/CustomizedImage.tsx similarity index 64% rename from src/frontend/src/utilities/CustomizedImage.jsx rename to src/frontend/src/utilities/CustomizedImage.tsx index 373e9e8e59..155d52e5cc 100755 --- a/src/frontend/src/utilities/CustomizedImage.jsx +++ b/src/frontend/src/utilities/CustomizedImage.tsx @@ -2,7 +2,19 @@ import React from 'react'; import cardImg from '@/assets/images/project_icon.png'; import logo from '@/assets/images/hotLog.png'; import { LazyLoadImage } from 'react-lazy-load-image-component'; -const Switcher = ({ status, width, height }) => { + +type switcherType = { + status: 'card' | 'logo'; + width: number; + height: number; +}; + +type CustomizedImageType = { + status: 'card' | 'logo'; + style: { width: number; height: number }; +}; + +const Switcher = ({ status, width, height }: switcherType) => { switch (status) { case 'card': return ; @@ -11,7 +23,7 @@ const Switcher = ({ status, width, height }) => { } }; -const CustomizedImage = ({ status, style }) => { +const CustomizedImage = ({ status, style }: CustomizedImageType) => { return ; }; diff --git a/src/frontend/src/utilities/CustomizedMenus.tsx b/src/frontend/src/utilities/CustomizedMenus.tsx deleted file mode 100755 index 5c47628c86..0000000000 --- a/src/frontend/src/utilities/CustomizedMenus.tsx +++ /dev/null @@ -1,73 +0,0 @@ -import * as React from 'react'; -import { MenuProps } from '@mui/material/Menu'; -import CoreModules from '@/shared/CoreModules'; -import AssetModules from '@/shared/AssetModules'; - -const StyledMenu = AssetModules.styled((props: MenuProps) => ( - -))(({ theme }) => ({ - '& .MuiPaper-root': { - borderRadius: 6, - marginTop: theme.spacing(1), - minWidth: 180, - boxShadow: `rgb(255, 255, 255) 0px 0px 0px 0px, - rgba(0, 0, 0, 0.05) 0px 0px 0px 1px, - rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, - rgba(0, 0, 0, 0.05) 0px 4px 6px -2px`, - '& .MuiMenu-list': { - padding: '4px 0', - }, - }, -})); - -export default function CustomizedMenus({ element, btnProps, btnName }) { - const [anchorEl, setAnchorEl] = React.useState(null); - const open = Boolean(anchorEl); - const handleClick = (event: React.MouseEvent) => { - setAnchorEl(event.currentTarget); - }; - const handleClose = () => { - setAnchorEl(null); - }; - - return ( -
- } - > - {btnName} - - - {element} - -
- ); -} diff --git a/src/frontend/src/utilities/CustomizedSnackbar.jsx b/src/frontend/src/utilities/CustomizedSnackbar.tsx similarity index 64% rename from src/frontend/src/utilities/CustomizedSnackbar.jsx rename to src/frontend/src/utilities/CustomizedSnackbar.tsx index 8097d58edc..1e47dd2f3c 100755 --- a/src/frontend/src/utilities/CustomizedSnackbar.jsx +++ b/src/frontend/src/utilities/CustomizedSnackbar.tsx @@ -1,15 +1,29 @@ import * as React from 'react'; import CoreModules from '@/shared/CoreModules'; -function Alert(props, ref) { +type customizedSnackbarPropType = { + duration: number; + open: boolean; + message: string; + variant: string; + handleClose: () => void; +}; + +function Alert(props: Record, ref: any) { return ; } -function SlideTransition(props) { +function SlideTransition(props: Record) { return ; } -export default function CustomizedSnackbars({ open, message, variant, handleClose, duration }) { +export default function CustomizedSnackbars({ + open, + message, + variant, + handleClose, + duration, +}: customizedSnackbarPropType) { return ( - {element} - - ); -} diff --git a/src/frontend/src/utilities/PrimaryAppBar.tsx b/src/frontend/src/utilities/PrimaryAppBar.tsx index b0fbc6cd22..099040255b 100755 --- a/src/frontend/src/utilities/PrimaryAppBar.tsx +++ b/src/frontend/src/utilities/PrimaryAppBar.tsx @@ -70,15 +70,7 @@ export default function PrimaryAppBar() { return ( - + { const dispatch = CoreModules.useAppDispatch(); const location = useLocation(); const [searchParams, setSearchParams] = useSearchParams(); const { windowSize } = windowDimention(); - const checkTheme = CoreModules.useAppSelector((state) => state.theme.hotTheme); + const checkTheme = useAppSelector((state) => state.theme.hotTheme); const theme = CoreModules.createTheme(checkTheme); - const stateSnackBar = CoreModules.useAppSelector((state) => state.common.snackbar); - const handleClose = (event, reason) => { + const stateSnackBar = useAppSelector((state) => state.common.snackbar); + + const handleClose = (event: React.SyntheticEvent, reason: string) => { if (reason === 'clickaway') { return; } diff --git a/src/frontend/src/views/NotFound404.jsx b/src/frontend/src/views/NotFound404.tsx similarity index 91% rename from src/frontend/src/views/NotFound404.jsx rename to src/frontend/src/views/NotFound404.tsx index e1152480a1..6f40134110 100644 --- a/src/frontend/src/views/NotFound404.jsx +++ b/src/frontend/src/views/NotFound404.tsx @@ -1,6 +1,7 @@ import React from 'react'; import pageNoFound from '@/assets/images/notFound.png'; import CoreModules from '@/shared/CoreModules'; + const NotFoundPage = () => { return ( { You may have mistyped the address or the page may have moved. - + ); }; diff --git a/src/frontend/src/views/ProjectDetailsV2.tsx b/src/frontend/src/views/ProjectDetailsV2.tsx index c5af85f8d3..dd35226aee 100644 --- a/src/frontend/src/views/ProjectDetailsV2.tsx +++ b/src/frontend/src/views/ProjectDetailsV2.tsx @@ -52,9 +52,10 @@ const ProjectDetailsV2 = () => { const [legendRef, legendToggle, handleLegendToggle] = useOutsideClick(); const [mainView, setView] = useState(); - const [selectedTaskArea, setSelectedTaskArea] = useState(); + const [selectedTaskArea, setSelectedTaskArea] = useState | null>(null); + console.log(selectedTaskArea, 'selectedTaskArea'); const [selectedTaskFeature, setSelectedTaskFeature] = useState(); - const [dataExtractUrl, setDataExtractUrl] = useState(null); + const [dataExtractUrl, setDataExtractUrl] = useState(); const [dataExtractExtent, setDataExtractExtent] = useState(null); const [taskBoundariesLayer, setTaskBoundariesLayer] = useState>(null); // Can pass a File object, or a string URL to be read by PMTiles @@ -62,7 +63,7 @@ const ProjectDetailsV2 = () => { const [viewState, setViewState] = useState('project_info'); const projectId: string = params.id; const defaultTheme = useAppSelector((state) => state.theme.hotTheme); - const state = CoreModules.useAppSelector((state) => state.project); + const state = useAppSelector((state) => state.project); const projectInfo = useAppSelector((state) => state.home.selectedProject); const selectedTask = useAppSelector((state) => state.task.selectedTask); const selectedFeatureProps = useAppSelector((state) => state.task.selectedFeatureProps); @@ -102,7 +103,7 @@ const ProjectDetailsV2 = () => { //Fetch project for the first time useEffect(() => { dispatch(ProjectActions.SetNewProjectTrigger()); - if (state.projectTaskBoundries.findIndex((project) => project.id == projectId) == -1) { + if (state.projectTaskBoundries.findIndex((project) => project.id.toString() === projectId) == -1) { dispatch(ProjectActions.SetProjectTaskBoundries([])); dispatch(ProjectById(state.projectTaskBoundries, projectId)); } else { @@ -112,7 +113,7 @@ const ProjectDetailsV2 = () => { if (Object.keys(state.projectInfo)?.length == 0) { dispatch(ProjectActions.SetProjectInfo(projectInfo)); } else { - if (state.projectInfo.id != projectId) { + if (state.projectInfo.id?.toString() != projectId) { dispatch(ProjectActions.SetProjectInfo(projectInfo)); } } @@ -398,9 +399,6 @@ const ProjectDetailsV2 = () => { state={state.projectTaskBoundries} defaultTheme={defaultTheme} map={map} - view={mainView} - mapDivPostion={y} - states={state} /> ) : ( @@ -539,7 +537,7 @@ const ProjectDetailsV2 = () => { className="!fmtm-text-base !fmtm-pr-2" /> - +
{ )} {mobileFooterSelection === 'activities' && ( } + body={} onClose={() => dispatch(ProjectActions.SetMobileFooterSelection(''))} /> )} @@ -583,21 +581,19 @@ const ProjectDetailsV2 = () => {
)} - {selectedTaskArea != undefined && selectedTaskFeature === undefined && ( + {selectedTaskArea != undefined && selectedTaskFeature === undefined && selectedTask && ( - + } /> )} {selectedTaskFeature != undefined && selectedTask && selectedTaskArea && ( { const dispatch = CoreModules.useAppDispatch(); const params = CoreModules.useParams(); const navigate = useNavigate(); + const projectId = params.projectId; const paramsInstanceId = params.instanceId; - const projectDashboardDetail = CoreModules.useAppSelector((state) => state.project.projectDashboardDetail); - const projectDashboardLoading = CoreModules.useAppSelector((state) => state.project.projectDashboardLoading); - + const projectDashboardDetail = useAppSelector((state) => state.project.projectDashboardDetail); + const projectDashboardLoading = useAppSelector((state) => state.project.projectDashboardLoading); const submissionDetails = useAppSelector((state) => state.submission.submissionDetails); const submissionDetailsLoading = useAppSelector((state) => state.submission.submissionDetailsLoading); - const taskId = submissionDetails?.task_id; useEffect(() => { @@ -37,7 +36,7 @@ const SubmissionDetails = () => { ); }, [projectId, paramsInstanceId]); - function removeNullValues(obj) { + function removeNullValues(obj: Record) { const newObj = {}; for (const [key, value] of Object.entries(obj)) { if (value !== null) { @@ -55,18 +54,18 @@ const SubmissionDetails = () => { } const filteredData = submissionDetails ? removeNullValues(submissionDetails) : {}; - var coordinatesArray = submissionDetails?.all?.xlocation?.split(';').map(function (coord) { + var coordinatesArray: [number, number][] = submissionDetails?.xlocation?.split(';').map(function (coord: string) { let coordinate = coord .trim() .split(' ') .slice(0, 2) - .map((value) => { + .map((value: string) => { return parseFloat(value); }); return [coordinate[1], coordinate[0]]; }); - const geojsonFeature = { + const geojsonFeature: Record = { type: 'FeatureCollection', features: [ { @@ -80,7 +79,7 @@ const SubmissionDetails = () => { ], }; - const renderValue = (value, key = '') => { + const renderValue = (value: any, key: string = '') => { if (key === 'start' || key === 'end') { return (