Skip to content

Commit

Permalink
refactor(web): datasource layer creation (#1050)
Browse files Browse the repository at this point in the history
Co-authored-by: airslice <[email protected]>
  • Loading branch information
mkumbobeaty and airslice authored Jul 12, 2024
1 parent 8b8a8f9 commit 8e3d8bc
Show file tree
Hide file tree
Showing 29 changed files with 980 additions and 639 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ const CommonHeader: FC<HeaderProps> = ({
iconColor={viewState === "grid" ? theme.content.main : theme.content.weak}
appearance="simple"
onClick={() => onChangeView?.("grid")}
shadow={false}
size="small"
/>
<Button
Expand All @@ -61,7 +60,6 @@ const CommonHeader: FC<HeaderProps> = ({
appearance="simple"
disabled={icon === "uploadSimple" ? true : false}
onClick={() => onChangeView?.("list")}
shadow={false}
size="small"
/>
</Actions>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,6 @@ const ProjectGridViewItem: FC<ProjectProps> = ({
onClick={e => onProjectStarClick?.(e, project.id)}
iconColor={isStarred ? theme.warning.main : theme.content.main}
appearance="simple"
shadow={false}
/>
</StarButtonWrapper>
</CardImage>
Expand All @@ -73,7 +72,7 @@ const ProjectGridViewItem: FC<ProjectProps> = ({
</CardTitleWrapper>
<PopupMenu
menu={popupMenu}
label={<Button icon="dotsThreeVertical" iconButton appearance="simple" shadow={false} />}
label={<Button icon="dotsThreeVertical" iconButton appearance="simple" />}
/>
</CardFooter>
</Card>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,6 @@ const ProjectListViewItem: FC<ProjectProps> = ({
onClick={e => onProjectStarClick?.(e, project.id)}
iconColor={isStarred ? theme.warning.main : theme.content.main}
appearance="simple"
shadow={false}
/>
</StarButtonWrapper>
<ProjectImage backgroundImage={project.imageUrl} />
Expand Down Expand Up @@ -94,7 +93,7 @@ const ProjectListViewItem: FC<ProjectProps> = ({
}}>
<PopupMenu
menu={popupMenu}
label={<Button icon="dotsThreeVertical" iconButton appearance="simple" shadow={false} />}
label={<Button icon="dotsThreeVertical" iconButton appearance="simple" />}
/>
</ActionCell>
</StyledRow>
Expand Down
152 changes: 152 additions & 0 deletions web/src/beta/features/Editor/Map/DataSourceLayerCreator/CSV/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import { FC, useCallback, useMemo, useState } from "react";

import URLField from "@reearth/beta/components/fields/URLField";
import {
InputGroup,
SubmitWrapper,
Wrapper,
InputsWrapper,
ContentWrapper,
} from "@reearth/beta/features/Editor/Map/SharedComponent";
import { Button, Icon, RadioGroup, TextInput } from "@reearth/beta/lib/reearth-ui";
import { useT } from "@reearth/services/i18n";
import { styled, useTheme } from "@reearth/services/theme";

import { DataProps, SourceType, DataSourceOptType } from "..";
import { generateTitle } from "../util";

const CSV: FC<DataProps> = ({ sceneId, onSubmit, onClose }) => {
const t = useT();
const theme = useTheme();
const [sourceType, setSourceType] = useState<SourceType>("local");
const [value, setValue] = useState("");
const [layerName, setLayerName] = useState("");
const [lat, setLat] = useState("");
const [lng, setLng] = useState("");

const dataSourceOptions: DataSourceOptType = useMemo(
() => [
{ label: t("From Assets"), value: "local" },
{ label: t("From Web"), value: "url" },
],
[t],
);

const handleSubmit = () => {
onSubmit({
layerType: "simple",
sceneId,
title: generateTitle(value, layerName),
visible: true,
config: {
data: {
url: (sourceType === "url" || sourceType === "local") && value !== "" ? value : undefined,
type: "csv",
csv: {
latColumn: lat,
lngColumn: lng,
},
},
},
});
onClose();
};

const handleValueChange = useCallback((value?: string, name?: string) => {
setValue(value || "");
setLayerName(name || "");
}, []);

const handleDataSourceTypeChange = useCallback((newValue: string) => {
setSourceType(newValue as SourceType);
setValue("");
}, []);

return (
<Wrapper>
<ContentWrapper>
<InputGroup label={t("Source Type")}>
<RadioGroup options={dataSourceOptions} onChange={handleDataSourceTypeChange} />
</InputGroup>

{sourceType == "local" && (
//this Url field component will be replaced with new ui/fields
<InputsWrapper>
<URLField
fileType="asset"
entityType="file"
name={t("Asset")}
value={value}
fileFormat="CSV"
onChange={handleValueChange}
/>
</InputsWrapper>
)}
{sourceType == "url" && (
<InputGroup label={t("Resource URL")}>
<InputsWrapper>
<TextInput placeholder="https://" value={value} onChange={handleValueChange} />
</InputsWrapper>
</InputGroup>
)}
<Warning>
<Icon icon="lightBulb" color={theme.warning.main} size="large" />
<TextWrapper>
{t(
"Visualizer currently only supports CSV point data. Please specify the column names for latitude and longitude in your data below.",
)}
</TextWrapper>
</Warning>
<CoordinateWrapper>
<InputGroup label={t("Latitude Column Name")}>
<InputsWrapper>
<TextInput
value={lat}
placeholder={t("Column Name")}
onChange={value => setLat(value)}
/>
</InputsWrapper>
</InputGroup>
<InputGroup label={t("Longitude Column Name")}>
<InputsWrapper>
<TextInput
value={lng}
placeholder={t("Column Name")}
onChange={value => setLng(value)}
/>
</InputsWrapper>
</InputGroup>
</CoordinateWrapper>
</ContentWrapper>
<SubmitWrapper>
<Button
title={t("Add to Layer")}
disabled={!value || !lng || !lat}
appearance="primary"
onClick={handleSubmit}
/>
</SubmitWrapper>
</Wrapper>
);
};

const Warning = styled("div")(({ theme }) => ({
display: "flex",
gap: theme.spacing.small,
alignItems: "center",
}));

const TextWrapper = styled("div")(({ theme }) => ({
color: theme.warning.main,
fontSize: theme.fonts.sizes.body,
fontWeight: theme.fonts.weight.regular,
}));

const CoordinateWrapper = styled("div")(({ theme }) => ({
display: "flex",
gap: theme.spacing.small,
alignItems: "center",
width: "100%",
}));

export default CSV;
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { useState, useMemo, useCallback } from "react";

import { AcceptedFileFormat } from "@reearth/beta/features/Assets/types";
import { DataType } from "@reearth/core";
import { useT } from "@reearth/services/i18n";

import { DataProps, DataSourceOptType, SourceType } from "..";
import { generateTitle } from "../util";

export default ({ sceneId, onClose, onSubmit }: DataProps) => {
const t = useT();

const [sourceType, setSourceType] = useState<SourceType>("local");
const [fileFormat, setFileFormat] = useState<AcceptedFileFormat>("GeoJSON");

const [value, setValue] = useState("");
const [layerName, setLayerName] = useState("");
const [prioritizePerformance, setPrioritizePerformance] = useState(false);
const dataSourceTypeOptions: DataSourceOptType = useMemo(
() => [
{ label: t("From Assets"), value: "local" },
{ label: t("From Web"), value: "url" },
{ label: t("From Value"), value: "value" },
],
[t],
);

const fileFormatOptions = [
{
value: "GeoJSON",
label: "GeoJSON",
},
{
value: "KML",
label: "KML",
},
{
value: "CZML",
label: "CZML",
},
];

const isValidExtension = useCallback(() => {
if (sourceType === "url" || sourceType === "local") {
const extension = value.split(".").pop()?.toLowerCase();
return extension === fileFormat.toLowerCase();
}
return true;
}, [value, fileFormat, sourceType]);

const handleSubmit = () => {
let parsedValue = null;

if (sourceType === "value" && value !== "") {
if (fileFormat === "GeoJSON") {
try {
parsedValue = JSON.parse(value);
} catch (error) {
parsedValue = value;
}
} else {
parsedValue = "data:text/plain;charset=UTF-8," + encodeURIComponent(value);
}
}

onSubmit({
layerType: "simple",
sceneId,
title: generateTitle(value, layerName),
visible: true,
config: {
data: {
url:
(sourceType === "url" || sourceType === "local") && value !== ""
? value
: fileFormat === "CZML" || fileFormat === "KML"
? parsedValue
: undefined,
type: fileFormat.toLowerCase() as DataType,
value: parsedValue,
geojson: {
useAsResource: prioritizePerformance,
},
},
},
});
onClose();
};

const handleValueChange = useCallback((value?: string, name?: string) => {
setValue(value || "");
setLayerName(name || "");
}, []);

const handleFileFormatChange = useCallback((value: string | string[]) => {
setFileFormat(value as AcceptedFileFormat);
}, []);

const handleDataSourceTypeChange = useCallback((newValue: string) => {
setSourceType(newValue as SourceType);
setValue("");
}, []);

return {
value,
dataSourceTypeOptions,
fileFormatOptions,
fileFormat,
sourceType,
prioritizePerformance,
setPrioritizePerformance,
isValidExtension,
handleValueChange,
handleFileFormatChange,
handleDataSourceTypeChange,
handleSubmit,
};
};
Loading

0 comments on commit 8e3d8bc

Please sign in to comment.