Open kongweiying2 opened 3 years ago
Hi @TheAussieStew Geopoint support is currently not in the roadmap. In any case, you should be able to implement your own custom field supporting it :) https://firecms.co/docs/entities/custom_fields Let me know if you have an implementation so we can try to merge it into the library
Sounds good!
I am marking this feature as a good first issue. It can be implemented in the same way that a developer would implement a "custom field": https://firecms.co/docs/entities/custom_fields That means that it is not necessary to develop the feature in the source code (though that would be the best!)
Anyone manage to get a working implementation before I go and make one myself tonight? Worth an ask :)
H @SKLn-Rad, as far as I know this has not been implemented yet! It would be great if you can share it when you are done so we can add it to the core
Any news on the status of this? Would love to see all Firestore data types supported. Could somebody please share a code snippet that would be required to add support for Firestore geopoints? Thanks!
This feature is not planned at this moment. We are happy to merge PRs or to do sponsored developments!
Ok, thanks for your reply. Could you share how the workaround you suggested, using custom fields would work? Something really simple, like giving the user a text field where comma separated latitude,longitude
can be entered would work. Thanks!
Hi @jbxbergdev You have an example on how to implement a custom field here: https://firecms.co/docs/properties/custom_fields
@fgatti675 hm ok. I tried a custom field implementation as per your link for the type GeoPoint. However, in the CMS, I still get the error "Currently the field geopoint is not supported". Any idea what I'm doing wrong? Code:
export default function GeopointField({
property,
value,
setValue,
customProps,
touched,
error,
isSubmitting,
context,
...props
}: FieldProps<GeoPoint, any>) {
return (
<>
<TextField required={property.validation?.required}
error={!!error}
disabled={isSubmitting}
label={property.name}
value={ value.latitude + "," + value.longitude }
onChange={(evt: any) => {
const latLon: string[] = evt.target.value.split(",");
const lat: number = parseFloat(latLon[0]);
const lon: number = parseFloat(latLon[1]);
const geopoint = new GeoPoint(lat, lon);
setValue(geopoint);
}}
helperText={error}
fullWidth
variant={"filled"}/>
<FieldDescription property={property}/>
</>
);
}
// ....
const eventCollection = buildCollection<Event>({
// (...)
properties: {
// (...)
location: {
name: "Ort",
dataType: "geopoint",
Field: GeopointField
},
// (...)
});
Hi @jbxbergdev did you also link the field in your corresponding property?
{ dataType: "geopoint", name: "...", Field: GeopointField}
@fgatti675 ah yeah, I did. I'll update the code snippet. So in the create/edit view the field is showing the error message.
Here is a working implementation. I have made the following react jsx element.
interface Location {
lat: number;
lng: number;
}
interface MapProps {
apiKey: string;
location: Location;
zoom: number;
onLocationChange: (location: Location) => void;
onZoomChange: (zoom: number) => void;
}
const GoogleMapLocationPicker = ({
apiKey,
location,
zoom,
onLocationChange,
onZoomChange,
}: MapProps) => {
const [map, setMap] = useState<google.maps.Map | null>(null);
const [marker, setMarker] = useState<google.maps.Marker | null>(null);
useEffect(() => {
const initMap = () => {
const mapOptions: google.maps.MapOptions = {
center: location,
zoom: zoom,
};
const map = new google.maps.Map(
document.getElementById("map")!,
mapOptions
);
setMap(map);
const marker = new google.maps.Marker({
position: location,
map: map,
draggable: true,
});
setMarker(marker);
marker.addListener("dragend", () => {
const position = marker.getPosition();
const location = {
lat: position!.lat(),
lng: position!.lng(),
};
onLocationChange(location);
});
map.addListener("zoom_changed", () => {
const zoom = map.getZoom();
onZoomChange(zoom!);
});
};
if (!window.google) {
const script = document.createElement("script");
script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}`;
script.onload = initMap;
document.body.appendChild(script);
} else {
initMap();
}
}, [apiKey, location, onLocationChange, onZoomChange, zoom]);
return <div id="map" style={{ height: "500px" }} />;
};
export default GoogleMapLocationPicker;
This can be used in a custom field as follows:
const DEFAULT_GEO_POINT = {
lat: 37.749692,
lng:-122.415284
};
export default function GeopointField({
property,
value = new GeoPoint(DEFAULT_GEO_POINT.lat, DEFAULT_GEO_POINT.lng),
setValue,
customProps,
touched,
error,
isSubmitting,
context,
...props
}: FieldProps<GeoPoint, any>) {
const [defaultposition, setDefaultPosition] = useState(DEFAULT_GEO_POINT);
const [defaultzoom, setDefaultZoom] = useState(15);
return (
<>
<p>{property.name}</p>
<GoogleMapLocationPicker
apiKey={import.meta.env.VITE_GOOGLE_MAPS_API_KEY}
location={
value["_lat"]
? { lat: value["_lat"], lng: value["_long"] }
: defaultposition
}
zoom={defaultzoom}
onZoomChange={(zoom) => {
setDefaultZoom(zoom);
}}
onLocationChange={(location) => {
setDefaultPosition({ lat: location.lat, lng: location.lng });
setValue(new GeoPoint(location.lat, location.lng));
}}
/>
<FieldDescription property={property} />
</>
);
}
This can be added to your collection as follows:
export const interventionCollection = buildCollection<Intervention>({
...
properties: {
...
location: buildProperty({
name: "User Location",
Field: GeopointField,
validation: { required: true },
dataType: "geopoint",
description: "Select the location",
}),
},
});
Awesome! Think you could submit a PR? You can start by checking how other fields are integrated in this file: form_field_configs.tsx
Sure, I'll try and do that sometime this week @fgatti675 .
@singhvedant111 Did you ever get around to this?
@singhvedant111 – I like your map implementation. I ended up working something out based on yours that's a simple text input, accepting a comma separated latitude, longitude.
import React, { FunctionComponent } from "react";
import { FieldDescription, FieldProps, GeoPoint } from "firecms";
import {TextField} from "@mui/material";
const GeoPointField: FunctionComponent<FieldProps<GeoPoint>> = ({
property,
value,
setValue,
error,
isSubmitting,
}) => {
const geoPointToString = (geoPoint: GeoPoint) : string => {
return `${geoPoint.latitude}, ${geoPoint.longitude}`;
}
const stringToGeoPoint = (str: string) : GeoPoint => {
const [latitude, longitude] = str.split(',');
return new GeoPoint(parseFloat(latitude), parseFloat(longitude));
}
return (
<>
<TextField
required={property.validation?.required}
error={!!error}
disabled={isSubmitting}
label={property.name}
helperText={error}
fullWidth
variant={"filled"}
value={value?.latitude && value.longitude ? geoPointToString(value) : ''} onChange={(evt) => {
setValue(
stringToGeoPoint(evt.target.value)
);
}}/>
<FieldDescription property={property} />
</>
);
}
export default GeoPointField;
I'm having a bit of trouble implementing this custom field. The implementation complains that the field is not supported. Currently I have fallen back to using the string dataType and mapping in the component.
Are custom fields not supported? How does one use a different datatype?
I understand that Geopoint isn't currently supported, however is there a potential roadmap for adding support? Or does the custom view support allow us to add it ourselves?