Skip to content

Commit

Permalink
Geojson upload feature (#40)
Browse files Browse the repository at this point in the history
* Added an input field to take geojson file as input

* added geojson input field to naksha-gmap-draw

* modified toFullGeoJson function to merge geojsons

* seperated out lat-long  and geojson import options

* added input validation for latlong import

* added geojson validation,file preview

* placed latlong import,geojson import in a pop -up

* updated lib from es2015 to es6

* added few chakra ui packages and its dependencies

* added file and location icon svgs

* put geojson and point import inside a modal box

* modified point import component to enhance ui

* placed geojson inside modal,enhanced the ui

* used useDisclosure for closing/opening the modal

* replaced plain JS with useref for content-height

* fixed a typo syntax error

* used chakra-ui table components

* reverted es6 to es2015 and the configurations

* replaced divs with chakra-ui box components

* Changed configuration to fix some type errors

* Moved the status messages to constants file

* used boolean variable to handle the upload status

* changed gmaps-draw version to 4.5.0

* Updated the naksha-components-react to 4.5.3
  • Loading branch information
abrahul committed Dec 27, 2023
1 parent adb42c7 commit 1885064
Show file tree
Hide file tree
Showing 11 changed files with 4,603 additions and 2,160 deletions.
4 changes: 2 additions & 2 deletions packages/naksha-components-react/package.json
@@ -1,6 +1,6 @@
{
"name": "naksha-components-react",
"version": "4.5.2",
"version": "4.5.3",
"author": "harshzalavadiya",
"main": "./dist/index.js",
"module": "./dist/esm/index.js",
Expand All @@ -21,7 +21,7 @@
},
"dependencies": {
"@biodiv-platform/eslint-preset": "4.4.9",
"@biodiv-platform/naksha-gmaps-draw": "4.4.9",
"@biodiv-platform/naksha-gmaps-draw": "4.5.0",
"@biodiv-platform/naksha-gmaps-view": "4.4.9",
"@biodiv-platform/naksha-mapbox-draw": "4.4.9",
"@biodiv-platform/naksha-mapbox-list": "4.5.0",
Expand Down
10 changes: 8 additions & 2 deletions packages/naksha-gmaps-draw/package.json
@@ -1,6 +1,6 @@
{
"name": "@biodiv-platform/naksha-gmaps-draw",
"version": "4.4.9",
"version": "4.5.0",
"author": "harshzalavadiya",
"main": "./dist/index.js",
"module": "./dist/esm/index.js",
Expand Down Expand Up @@ -34,6 +34,12 @@
},
"dependencies": {
"@biodiv-platform/naksha-commons": "*",
"@turf/bbox": "^6.5.0"
"@chakra-ui/icons": "^2.1.1",
"@chakra-ui/react": "^2.8.2",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@turf/bbox": "^6.5.0",
"framer-motion": "^10.16.16",
"react-dropzone": "^14.2.3"
}
}
220 changes: 220 additions & 0 deletions packages/naksha-gmaps-draw/src/geojson/index.tsx
@@ -0,0 +1,220 @@
import { CheckCircleIcon, CloseIcon, DeleteIcon } from "@chakra-ui/icons";
import { Box, Icon, List, ListItem, Text } from "@chakra-ui/react";
import React, { useState } from "react";
import { useDropzone } from "react-dropzone";
import FileIcon from "../icons/file";

const GeojsonImport = ({ addFeature, ButtonComponent }) => {
const [isGeoJSONValid, setIsGeoJSONValid] = useState(true);
const [uploadStatus, setUploadStatus] = useState("");
const [filesToUpload, setFilesToUpload] = useState<any[]>([]);
const [uploadedFiles, setUploadedFiles] = useState<any[]>([]);

const onDrop = (acceptedFiles: File[]) => {
setFilesToUpload(acceptedFiles);
};

const handleAddFeature = () => {
try {
filesToUpload.forEach((file) => {
const reader = new FileReader();

reader.onabort = () =>
handleError("File reading was aborted. Please try again.");
reader.onerror = () =>
handleError("File reading has failed. Please try again.");

reader.onload = () => {
const result = reader.result;

if (result) {
const jsonString =
typeof result === "string"
? result
: new TextDecoder().decode(result);

try {
const geojsonObject = JSON.parse(jsonString);

const featuresToAdd = Array.isArray(geojsonObject.features)
? geojsonObject.features.map((feature) => ({
...feature,
isGeojson: true,
}))
: [{ ...geojsonObject, isGeojson: true }];

featuresToAdd.forEach((featureToAdd) => {
addFeature([featureToAdd]);
});

setUploadStatus("Geojson added successfully");
setIsGeoJSONValid(true);

// Update the list of successfully uploaded files
setUploadedFiles((prevFiles) => [
...prevFiles,
{ name: file.name },
]);

// Reset the dropzone content
setFilesToUpload([]);
} catch (error) {
console.error(error);
handleError("Upload failed. Invalid GeoJSON format.");
}
} else {
handleError("File reading result is null.");
}
};

reader.readAsText(file);
});
} catch (error) {
console.error(error);
handleError("File upload failed. Please try again.");
} finally {
setTimeout(() => {
setUploadStatus("");
setIsGeoJSONValid(true);
}, 2000);
}
};

const handleError = (message: string) => {
setUploadStatus(message);
setIsGeoJSONValid(false);
};

const removeFile = () => {
setFilesToUpload([]);
};

const { getRootProps, getInputProps, isDragActive } = useDropzone({
onDrop,
accept: {
"application/geo+json": [".geojson"],
},
});

return (
<Box
display="flex"
flexDirection="column"
alignItems="flex-start"
marginTop="10px"
>
<Text marginBottom="10px" fontWeight="bold" fontSize="lg">
GeoJSON
</Text>

<Box display="flex" flexDirection="row" alignItems="center">
<Box
border="2px solid #519895"
borderRadius="4px"
display="flex"
flexDirection="column"
alignItems="center"
padding="10px"
cursor="pointer"
marginLeft="15px"
width="350px"
height="100px"
{...getRootProps()}
>
<input {...getInputProps()} />

{filesToUpload.length > 0 ? (
<Box display="flex" alignItems="center">
<Box ml="10px" display="flex" alignItems="center">
<Icon
as={FileIcon}
boxSize={30}
color="gray.500"
style={{ marginRight: "5px" }}
/>
<Text
marginTop="10px"
overflow="hidden"
whiteSpace="pre-wrap"
textOverflow="ellipsis"
maxWidth="200px"
>
{filesToUpload[0].name}
</Text>
<DeleteIcon
boxSize={20}
color="red"
onClick={removeFile}
ml="10px"
mt="10px"
>
Remove
</DeleteIcon>
</Box>
</Box>
) : (
<>
<Text>
{"Drag 'n' drop GeoJSON file here, or click to select a file"}
</Text>
{isDragActive && <Text>Drop the file here...</Text>}
</>
)}
</Box>

{React.cloneElement(ButtonComponent, {
type: "button",
ml: "30px",
style: { paddingLeft: "15px" },
onClick: handleAddFeature,
})}
</Box>

{uploadStatus && (
<Text
fontWeight="bold"
color={isGeoJSONValid ? "green" : "red"}
height="20px"
>
{isGeoJSONValid ? (
<CheckCircleIcon boxSize={20} mr={2} />
) : (
<CloseIcon boxSize={15} mr={2} />
)}
{uploadStatus}
</Text>
)}

{/* Display the list of successfully uploaded files */}
{uploadedFiles.length > 0 && (
<Box mt="10px" pl="15px">
<Text fontSize="sm">Added GeoJSONs:</Text>
<List styleType="none" padding="0">
{uploadedFiles.map((file, index) => (
<ListItem key={index} display="flex" alignItems="center">
<Icon
as={FileIcon}
boxSize={20}
color="teal"
mr="3px"
style={{ marginTop: "5px" }}
/>
<Text
mt="10px"
overflow="hidden"
whiteSpace="pre-wrap"
textOverflow="ellipsis"
maxWidth="300px"
>
{file.name}
</Text>
</ListItem>
))}
</List>
</Box>
)}
</Box>
);
};

export default GeojsonImport;
47 changes: 47 additions & 0 deletions packages/naksha-gmaps-draw/src/icons/file.tsx
@@ -0,0 +1,47 @@
import { createIcon } from "@chakra-ui/icon";
import React from "react";

const FileIcon = createIcon({
displayName: "Calendar",
path: (
<g>
<path
fill="#231F20"
d="M60,0H14c-2.211,0-4,1.789-4,4v27H4c-2.211,0-4,1.789-4,4v23c0,3.313,2.687,6,6,6h52c3.313,0,6-2.687,6-6V4
C64,1.789,62.211,0,60,0z M2,58V35c0-1.104,0.896-2,2-2h6v25c0,2.209-1.791,4-4,4S2,60.209,2,58z M58,62H10.463
C11.416,60.938,12,59.539,12,58V4c0-1.104,0.896-2,2-2h46c1.104,0,2,0.896,2,2v54C62,60.209,60.209,62,58,62z"
/>
<path
fill="#231F20"
d="M53,25H21c-0.553,0-1,0.447-1,1s0.447,1,1,1h32c0.553,0,1-0.447,1-1S53.553,25,53,25z"
/>
<path
fill="#231F20"
d="M53,19H21c-0.553,0-1,0.447-1,1s0.447,1,1,1h32c0.553,0,1-0.447,1-1S53.553,19,53,19z"
/>
<path
fill="#231F20"
d="M53,37H21c-0.553,0-1,0.447-1,1s0.447,1,1,1h32c0.553,0,1-0.447,1-1S53.553,37,53,37z"
/>
<path
fill="#231F20"
d="M53,43H21c-0.553,0-1,0.447-1,1s0.447,1,1,1h32c0.553,0,1-0.447,1-1S53.553,43,53,43z"
/>
<path
fill="#231F20"
d="M53,49H21c-0.553,0-1,0.447-1,1s0.447,1,1,1h32c0.553,0,1-0.447,1-1S53.553,49,53,49z"
/>
<path
fill="#231F20"
d="M53,31H21c-0.553,0-1,0.447-1,1s0.447,1,1,1h32c0.553,0,1-0.447,1-1S53.553,31,53,31z"
/>
<path
fill="#231F20"
d="M21,15h15c0.553,0,1-0.447,1-1s-0.447-1-1-1H21c-0.553,0-1,0.447-1,1S20.447,15,21,15z"
/>
</g>
),
viewBox: "0 0 64 64"
});

export default FileIcon;
9 changes: 9 additions & 0 deletions packages/naksha-gmaps-draw/src/icons/location.tsx
@@ -0,0 +1,9 @@
import { createIcon } from "@chakra-ui/icon";

const LocationIcon = createIcon({
displayName: "Location",
d: "M11.536 3.464a5 5 0 010 7.072L8 14.07l-3.536-3.535a5 5 0 117.072-7.072v.001zm1.06 8.132a6.5 6.5 0 10-9.192 0l3.535 3.536a1.5 1.5 0 002.122 0l3.535-3.536zM8 9a2 2 0 100-4 2 2 0 000 4z",
viewBox: "0 0 16 16"
});

export default LocationIcon;

0 comments on commit 1885064

Please sign in to comment.