import React, { useState } from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { useTranslation } from 'react-i18next'; import { Formik, Field, Form, FormikHelpers } from 'formik'; import { TextField, CheckboxWithLabel } from 'formik-material-ui'; import { Paper, Typography, FormControl, Grid, Button, useTheme, makeStyles, createStyles } from '@material-ui/core'; import { Skeleton } from '@material-ui/lab'; import { CloudUpload } from '@material-ui/icons'; import { DeviceStatus, IExternalDeviceId } from '@energyweb/origin-backend-core'; import { getConfiguration } from '../../features/configuration'; import { PowerFormatter } from '../../utils/PowerFormatter'; import { useValidation } from '../../utils/validation'; import { areDeviceSpecificPropertiesValid } from '../../utils/device'; import { usePermissions } from '../../utils/permissions'; import { Moment } from '../../utils/time'; import { showNotification, NotificationTypeEnum } from '../../utils/notifications'; import { FormikDatePicker, FormInput, HierarchicalMultiSelect } from '../Form'; import { Upload, IUploadedFile } from '../Documents'; import { Requirements } from '../Layout'; import { DeviceSelectors } from './DeviceSelectors'; import { createDevice } from '../../features/devices'; import { fromGeneralSelectors } from '../../features'; interface IFormValues { facilityName: string; capacity: string; commissioningDate: Moment; registrationDate: Moment; address: string; latitude: string; longitude: string; supported: boolean; projectStory: string; } const INITIAL_FORM_VALUES: IFormValues = { facilityName: '', capacity: '', commissioningDate: null, registrationDate: null, address: '', latitude: '', longitude: '', supported: false, projectStory: '' }; export const AddDevice = () => { const configuration = useSelector(getConfiguration); const compliance = useSelector(fromGeneralSelectors.getCompliance); const country = useSelector(fromGeneralSelectors.getCountry); const backendClient = useSelector(fromGeneralSelectors.getBackendClient); const externalDeviceIdTypes = useSelector(fromGeneralSelectors.getExternalDeviceIdTypes); const environment = useSelector(fromGeneralSelectors.getEnvironment); const dispatch = useDispatch(); const { t } = useTranslation(); const { Yup, yupLocaleInitialized } = useValidation(); const [selectedDeviceType, setSelectedDeviceType] = useState([]); const [selectedLocation, setSelectedLocation] = useState([]); const [selectedGridOperator, setSelectedGridOperator] = useState([]); const [imagesUploaded, setImagesUploaded] = useState(false); const [imagesUploadedList, setImagesUploadedList] = useState([]); const { canAccessPage } = usePermissions(); const [docfiles, setFiles] = useState([]); const uploadedDocFiles = docfiles .filter((f) => !f.removed && f.uploadedName) .reduce( (arr, x) => { arr.filenames.push(x.uploadedName); return arr; }, { filenames: [] } ); const useStyles = makeStyles(() => createStyles({ container: { padding: '10px' }, selectContainer: { paddingTop: '10px' }, fileUploadInput: { display: 'none' } }) ); const classes = useStyles(useTheme()); const externalIdSchema = {}; if (externalDeviceIdTypes) { const requiredDeviceIdTypes = externalDeviceIdTypes.filter( (id) => id?.required && !id?.autogenerated ); for (const externalId of requiredDeviceIdTypes) { externalIdSchema[externalId.type] = Yup.string().required(); } } const VALIDATION_SCHEMA = Yup.object().shape({ facilityName: Yup.string().label(t('device.properties.facilityName')).required(), capacity: Yup.number() .label(`${t('device.properties.capacity')} (${PowerFormatter.displayUnit})`) .required() .positive(), commissioningDate: Yup.date().required(), registrationDate: Yup.date().required(), address: Yup.string().label(t('device.properties.address')).required(), latitude: Yup.number().label(t('device.properties.latitude')).required().min(-90).max(90), longitude: Yup.number() .label(t('device.properties.longitude')) .required() .min(-180) .max(180), supported: Yup.boolean(), projectStory: Yup.string(), ...externalIdSchema }); async function submitForm( values: typeof INITIAL_FORM_VALUES, formikActions: FormikHelpers ): Promise { const deviceType = selectedDeviceType.sort((a, b) => b.length - a.length)[0]; formikActions.setSubmitting(true); const [region, province] = selectedLocation; const externalDeviceIds: IExternalDeviceId[] = externalDeviceIdTypes.map(({ type }) => { return { id: values[type], type }; }); dispatch( createDevice({ status: DeviceStatus.Submitted, deviceType, complianceRegistry: compliance, facilityName: values.facilityName, capacityInW: PowerFormatter.getBaseValueFromValueInDisplayUnit( parseFloat(values.capacity) ), country, address: values.address, region: region || '', province: province ? province.split(';')[1] : '', gpsLatitude: values.latitude, gpsLongitude: values.longitude, timezone: 'Asia/Bangkok', operationalSince: values.commissioningDate?.unix(), otherGreenAttributes: '', typeOfPublicSupport: '', description: values.projectStory, images: JSON.stringify(imagesUploadedList), files: JSON.stringify(uploadedDocFiles.filenames), externalDeviceIds, gridOperator: (selectedGridOperator && selectedGridOperator[0]) || '' }) ); formikActions.setSubmitting(false); } async function uploadImages(files: FileList) { if (files.length > 10) { showNotification( t('device.feedback.pleaseSelectUpToXImages', { limit: 10, actual: files.length }), NotificationTypeEnum.Error ); return; } try { const { data: uploadedFiles } = await backendClient.fileClient.upload( Array.from(files) as Blob[] ); setImagesUploaded(true); setImagesUploadedList(uploadedFiles); } catch (error) { console.log(error); showNotification( t('device.feedback.unexpectedErrorWhenUploadingImages'), NotificationTypeEnum.Error ); } } if (!configuration || !yupLocaleInitialized) { return ; } if (!canAccessPage?.value) { return ; } const initialFormValues: IFormValues = INITIAL_FORM_VALUES; return ( {(formikProps) => { const { isValid, isSubmitting, setFieldValue, validateField } = formikProps; const fieldDisabled = isSubmitting; const buttonDisabled = isSubmitting || !isValid || selectedDeviceType.length === 0 || !areDeviceSpecificPropertiesValid( selectedLocation, selectedGridOperator, environment ); return (
{t('device.info.general')}
setSelectedDeviceType(value) } allValues={configuration.deviceTypeService.deviceTypes} selectOptions={[ { label: t('device.properties.deviceType'), placeholder: t('device.info.selectDeviceType') }, { label: t('device.properties.deviceType'), placeholder: t('device.info.selectDeviceType') }, { label: t('device.properties.deviceType'), placeholder: t('device.info.selectDeviceType') } ]} disabled={fieldDisabled} singleChoice={true} required={true} />
{ const parsedValue = parseFloat( (e.target as any)?.value ); if (!isNaN(parsedValue)) { setFieldValue( 'latitude', parsedValue.toFixed(2) ); } validateField('latitude'); } }} /> { const parsedValue = parseFloat( (e.target as any)?.value ); if (!isNaN(parsedValue)) { setFieldValue( 'longitude', parsedValue.toFixed(2) ); } validateField('longitude'); } }} />
{t('device.properties.story')} {externalDeviceIdTypes.map((externalDeviceIdType, index) => { if (externalDeviceIdType.autogenerated) { return null; } return ( ); })} {t('device.properties.images')} {imagesUploaded ? (

{t('device.feedback.imagesUploaded')}

{t('device.info.pleaseFillOtherFields')}

) : (
uploadImages(e.target.files)} multiple disabled={imagesUploaded} />
)} setFiles(newFiles)} />
); }}
); };