Farmbot-Web-App/frontend/farmware/images/photos.tsx

145 lines
4.4 KiB
TypeScript
Raw Normal View History

2017-06-29 12:54:02 -06:00
import * as React from "react";
2019-02-04 13:54:17 -07:00
import moment from "moment";
2019-06-24 15:39:49 -06:00
import { success, error } from "../../toast/toast";
2017-07-28 15:24:21 -06:00
import { ImageFlipper } from "./image_flipper";
2019-02-10 22:10:58 -07:00
import { PhotosProps, PhotoButtonsProps } from "./interfaces";
2017-10-10 11:59:08 -06:00
import { getDevice } from "../../device";
2018-06-21 15:04:21 -06:00
import { Content } from "../../constants";
2017-07-28 15:24:21 -06:00
import { selectImage } from "./actions";
2019-04-09 23:17:03 -06:00
import { safeStringFetch, timeFormatString } from "../../util";
2017-08-29 21:01:15 -06:00
import { destroy } from "../../api/crud";
import {
downloadProgress
} from "../../devices/components/fbos_settings/os_update_button";
2019-02-10 22:10:58 -07:00
import { TaggedImage } from "farmbot";
2019-02-04 07:32:26 -07:00
import { startCase } from "lodash";
2019-02-10 22:10:58 -07:00
import { MustBeOnline } from "../../devices/must_be_online";
2019-04-02 13:59:37 -06:00
import { t } from "../../i18next_wrapper";
2019-04-09 23:17:03 -06:00
import { TimeSettings } from "../../interfaces";
2019-12-27 11:37:54 -07:00
import {
cameraBtnProps
} from "../../devices/components/fbos_settings/camera_selection";
2017-07-07 04:49:03 -06:00
interface MetaInfoProps {
/** Default conversion is `attr_name ==> Attr Name`.
2018-12-18 11:25:17 -07:00
* Setting a label property will over ride it to a different value.
2017-07-07 04:49:03 -06:00
*/
label?: string;
attr: string;
2017-08-28 06:23:53 -06:00
// tslint:disable-next-line:no-any
2017-07-07 04:49:03 -06:00
obj: any; /** Really, it's OK here! See safeStringFetch */
}
function MetaInfo({ obj, attr, label }: MetaInfoProps) {
2019-02-04 07:32:26 -07:00
const top = label || startCase(attr.split("_").join());
2017-08-28 05:49:13 -06:00
const bottom = safeStringFetch(obj, attr);
return <div>
<label>{top}:</label>
2018-07-19 23:48:32 -06:00
<span>{bottom || t("unknown")}</span>
</div>;
2017-07-07 04:49:03 -06:00
}
2017-06-29 12:54:02 -06:00
const PhotoMetaData = ({ image }: { image: TaggedImage | undefined }) =>
<div className="image-metadata">
{image
? Object.keys(image.body.meta)
.filter(key => ["x", "y", "z"].includes(key))
.sort()
.map((key, index) =>
<MetaInfo key={index} attr={key} obj={image.body.meta} />)
: <MetaInfo
label={t("Image")}
attr={"image"}
obj={{ image: t("No meta data.") }} />}
</div>;
2019-02-10 22:10:58 -07:00
const PhotoButtons = (props: PhotoButtonsProps) => {
const imageUploadJobProgress = downloadProgress(props.imageJobs[0]);
2019-12-27 11:37:54 -07:00
const camDisabled = cameraBtnProps(props.env);
return <div className="farmware-button">
2019-02-10 22:10:58 -07:00
<MustBeOnline
syncStatus={props.syncStatus}
networkState={props.botToMqttStatus}
hideBanner={true}
lockOpen={process.env.NODE_ENV !== "production"}>
<button
2019-12-27 11:37:54 -07:00
className={`fb-button green ${camDisabled.class}`}
title={camDisabled.title}
onClick={camDisabled.click || props.takePhoto}>
2019-02-10 22:10:58 -07:00
{t("Take Photo")}
</button>
</MustBeOnline>
<button
className="fb-button red"
onClick={props.deletePhoto}>
{t("Delete Photo")}
</button>
<p>
{imageUploadJobProgress &&
`${t("uploading photo")}...${imageUploadJobProgress}`}
</p>
</div>;
};
2019-04-09 23:17:03 -06:00
interface PhotoFooterProps {
image: TaggedImage | undefined;
timeSettings: TimeSettings;
}
export const PhotoFooter = ({ image, timeSettings }: PhotoFooterProps) => {
const created_at = image
? moment(image.body.created_at)
2019-04-09 23:17:03 -06:00
.utcOffset(timeSettings.utcOffset)
.format(`MMMM Do, YYYY ${timeFormatString(timeSettings)}`)
: "";
return <div className="photos-footer">
{/** Separated from <MetaInfo /> for stylistic purposes. */}
{image ?
<div className="image-created-at">
<label>{t("Created At:")}</label>
<span>
{created_at}
</span>
</div>
: ""}
<PhotoMetaData image={image} />
</div>;
};
2017-06-30 10:07:30 -06:00
export class Photos extends React.Component<PhotosProps, {}> {
2017-06-29 12:54:02 -06:00
takePhoto = () => {
2019-07-02 11:03:16 -06:00
const ok = () => success(t(Content.PROCESSING_PHOTO));
const no = () => error(t("Error taking photo"));
2017-10-10 11:59:08 -06:00
getDevice().takePhoto().then(ok, no);
2017-06-29 12:54:02 -06:00
}
deletePhoto = () => {
2017-08-29 21:01:15 -06:00
const img = this.props.currentImage || this.props.images[0];
2020-01-03 13:04:45 -07:00
if (img?.uuid) {
2017-08-29 21:01:15 -06:00
this.props.dispatch(destroy(img.uuid))
2019-07-02 11:03:16 -06:00
.then(() => success(t("Image Deleted.")))
.catch(() => error(t("Could not delete image.")));
2017-08-29 21:01:15 -06:00
}
}
2017-06-29 12:54:02 -06:00
render() {
2018-06-21 15:04:21 -06:00
return <div className="photos">
<PhotoButtons
2019-02-10 22:10:58 -07:00
syncStatus={this.props.syncStatus}
botToMqttStatus={this.props.botToMqttStatus}
takePhoto={this.takePhoto}
deletePhoto={this.deletePhoto}
2019-12-27 11:37:54 -07:00
env={this.props.env}
imageJobs={this.props.imageJobs} />
2018-06-21 15:04:21 -06:00
<ImageFlipper
onFlip={id => this.props.dispatch(selectImage(id))}
2018-06-21 15:04:21 -06:00
currentImage={this.props.currentImage}
images={this.props.images} />
<PhotoFooter
image={this.props.currentImage}
2019-04-09 23:17:03 -06:00
timeSettings={this.props.timeSettings} />
2018-06-21 15:04:21 -06:00
</div>;
2017-06-29 12:54:02 -06:00
}
}