Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LF-4691: UI to connect to ensemble #3675

Merged
merged 42 commits into from
Feb 7, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
e63c9ef
LF-4691 Add translations
SayakaOno Jan 27, 2025
1eec16d
LF-4691 Add esci logo
SayakaOno Jan 27, 2025
bd8b92e
LF-4691 Add color codes to colors.scss
SayakaOno Jan 27, 2025
8136adb
LF-4691 Add Partners component
SayakaOno Jan 28, 2025
56207c1
LF-4691 Add Partners container
SayakaOno Jan 28, 2025
c105c85
LF-4691 Navigate to sensor connection flow on sensor menu click
SayakaOno Jan 28, 2025
d3cfdbc
LF-4691 Replace hard-coded post sensor URL with constant in Routes
SayakaOno Jan 28, 2025
a8b47be
LF-4691 Add showPreviousButton prop to WithStepperProgressBar
SayakaOno Jan 28, 2025
8889eef
LF-4691 Style organization ID input properly
SayakaOno Jan 28, 2025
25c69e4
LF-4691 Use Partners component in PostSensor
SayakaOno Jan 29, 2025
07b5e28
LF-4691 Impelment validation for ESCI organisation ID
SayakaOno Jan 30, 2025
f67034d
LF-4691 Update ContextForm to accept formMode prop
SayakaOno Jan 30, 2025
d5ef4a6
LF-4691 Add formMode prop to ContextForm in PostSensor
SayakaOno Jan 30, 2025
6c9cb8f
LF-4691 Correct organisation spelling
SayakaOno Jan 30, 2025
7a97ea8
LF-4691 Adjust property names
SayakaOno Jan 30, 2025
9e9864e
LF-4691 FarmAddon API setup for RTK query
SayakaOno Jan 30, 2025
49572a2
LF-4691 Add/modify translations
SayakaOno Jan 30, 2025
66d9fdc
LF-4691 Integrate API POST /farm_addon
SayakaOno Jan 30, 2025
2e1932c
LF-4691 Export useLazyGetSensorsQuery from apiSlice
SayakaOno Jan 30, 2025
c1a33bd
LF-4691 'LazyGetSensors' in PostSensor onSave
SayakaOno Jan 30, 2025
14897dd
LF-4691 Add type for Add sensor form
SayakaOno Jan 30, 2025
38de118
LF-4691 Use constants and types for Add sensors form
SayakaOno Jan 30, 2025
728c6bf
LF-4691 Remove background-color: white from formWrapper
SayakaOno Jan 31, 2025
7eedc50
LF-4691 Extract CSSLength type
SayakaOno Jan 31, 2025
aa18bc5
LF-4691 Fix translation
SayakaOno Jan 31, 2025
5536d2a
LF-4691 Update routes and PostSensor to send isCompactSideMenu
SayakaOno Jan 31, 2025
3ab9969
LF-4691 Make Loading component fixed relative to viewport
SayakaOno Jan 31, 2025
33aa699
LF-4691 Send isCompactSideMenu prop to Loading in WithStepperProgressBar
SayakaOno Jan 31, 2025
108d707
LF-4691 Delete unused files and code for bulk sensor upload
SayakaOno Feb 3, 2025
c53bdf2
LF-4691 Add style for mobile view
SayakaOno Feb 3, 2025
ba93820
LF-4691 Cleanup
SayakaOno Feb 3, 2025
b1d1182
Revert "LF-4691 Delete unused files and code for bulk sensor upload"
SayakaOno Feb 4, 2025
1e4695d
LF-4691 Add constant for ESCI partner ID
SayakaOno Feb 4, 2025
b6aba3a
LF-4691 Update WithStepperProgressBar
SayakaOno Feb 5, 2025
a559b2f
LF-4691 Add sensors page URL
SayakaOno Feb 5, 2025
c6be0fb
LF-4691 Adjust PostSensor
SayakaOno Feb 5, 2025
9e49b22
LF-4691 Update PARTNERS constant
SayakaOno Feb 5, 2025
8bf9d80
LF-4691 Fix capitalization in 'Ensemble Scientific'
SayakaOno Feb 5, 2025
18a70d5
Merge branch 'integration' into LF-4691/UI_to_connect_to_Ensemble
SayakaOno Feb 5, 2025
76856ed
LF-4691 Add classNames prop to PageTitle
SayakaOno Feb 6, 2025
4df2984
LF-4691 Set overflow-y to auto in FixedHeaderContainer
SayakaOno Feb 6, 2025
43754f2
LF-4691 Fix CSS for padding
SayakaOno Feb 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/webapp/public/locales/en/common.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"HERE": "here",
"INVALID_DATE": "Invalid date",
"LOADING": "Loading...",
"MANAGE_ENTITY": "Manage {{entity}}",
"MARK_ABANDON": "Abandon",
"MARK_COMPLETE": "Mark Complete",
"MARK_COMPLETED": "Mark completed",
Expand Down Expand Up @@ -80,6 +81,7 @@
"SAVE": "Save",
"SAVE_CHANGES": "Save Changes",
"SEARCH": "Search",
"SEE_ON_MAP": "See on map",
"SELECT": "Select",
"SELECT_ALL": "Select all",
"SELECTED_COUNT": "{{count}} selected",
Expand Down
15 changes: 14 additions & 1 deletion packages/webapp/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1789,14 +1789,27 @@
"BRAND": "Brand",
"BRAND_TOOLTIP": "Brands that LiteFarm can integrate with are shown below. If you would no longer like to use this sensor brand, try retiring this sensor instead.",
"DEPTH": "Depth",
"DEVICE_TYPE": "Device type",
"DITECTED_FIELD": "We detected the field location to be:",
"EDIT": "Edit",
"EXTERNAL_ID_TOOLTIP": "This id is used to uniquely identify this sensor in other, integrated systems and cannot be changed. If it is no longer being used, try retiring this sensor and adding a new one.",
"EXTERNAL_IDENTIFIER": "External Identifier",
"LATITUDE": "Latitude",
"LONGITUDE": "Longitude",
"MODEL": "Model",
"NAME": "Sensor Name",
"RETIRE": "Retire"
"RETIRE": "Retire",
"SEE_FULL_SENSOR_SETUP": "See full sensor setup"
},
"ESCI": {
"ACTIVE_CONNECTION": "You have an active ESCI connection",
"CONNECT_NEW_SENSOR": "Connect a new sensor setup from ESCI",
"CURRENT_SUPPORT": "We currently only support sensors from \"Ensemble Scientific\"",
"ENSEMBLE_ESID": "Ensemble ESID",
"ENTER_ID": "Enter your Ensemble Scientific organisation ID",
"ORGANISATION_ID": "ESCI organisation ID",
"ORGANISATION_ID_ERROR": "Invalid Organisation ID",
"ORGANISATION_ID_GENERIC_ERROR": "Failed to connect to ESCI. Please try again later."
},
"EXTERNAL_IDENTIFIER": "External identifier",
"HOURS_AGO": "{{time}} hour(s) ago",
Expand Down
2 changes: 2 additions & 0 deletions packages/webapp/src/apiConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export const soilAmendmentMethodsUrl = `${URI}/soil_amendment_methods`;
export const soilAmendmentPurposesUrl = `${URI}/soil_amendment_purposes`;
export const soilAmendmentFertiliserTypesUrl = `${URI}/soil_amendment_fertiliser_types`;
export const productUrl = `${URI}/product`;
export const farmAddonUrl = `${URI}/farm_addon`;

export const url = URI;

Expand Down Expand Up @@ -152,5 +153,6 @@ export default {
soilAmendmentPurposesUrl,
soilAmendmentFertiliserTypesUrl,
productUrl,
farmAddonUrl,
url,
};
4 changes: 4 additions & 0 deletions packages/webapp/src/assets/colors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@

--Colors-Primary-Primary-teal-50: #ebf5f4;
--Colors-Primary-Primary-teal-100: #c0e1dd;
--Colors-Primary-Primary-teal-200: #a2d2cd;
--Colors-Primary-Primary-teal-300: #78bdb6;
--Colors-Primary-Primary-teal-400: #5db1a8;
--Colors-Primary-Primary-teal-500: #359d92;
Expand Down Expand Up @@ -109,6 +110,8 @@
--Btn-primary-hover: #e8a700;
--Btn-primary-disabled: #e7ebf2;

--Colors-Backgrounds-Disabled-grey: #e7ebf2;

--Brand-Accents-colors-and-overlays-Accent-red: #eb6034;

--Colors-Accent-Accent-yellow-50: #fff8e6;
Expand All @@ -130,6 +133,7 @@
--Colors-Accent---singles-Purple-full: #8f26f0;

--Form-focus: #89d1c7;
--Box-bg: #f5fafa;

// Named in Figma but not in design system
--Colors-Primary-green: #247360;
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
.overflowStyle {
display: flex;
justify-content: center;
overflow-y: scroll;
overflow-y: auto;
}

.childrenWrapper {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,9 @@
*/

import clsx from 'clsx';
import { CSSLength } from '../../types';
import styles from './styles.module.scss';

type CSSLength = `${number}px` | `${number}%` | `${number}vw` | `${number}vh` | 'auto';

interface FloatingContainerProps {
isCompactSideMenu: boolean;
children: React.ReactNode;
Expand Down
41 changes: 34 additions & 7 deletions packages/webapp/src/components/Form/ContextForm/Loading.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,25 +13,52 @@
* GNU General Public License for more details, see <https://www.gnu.org/licenses/>.
*/

import { CSSProperties } from 'react';
import clsx from 'clsx';
import { useTranslation } from 'react-i18next';
import Spinner from '../../Spinner';
import FloatingContainer from '../../FloatingContainer';
import type { CSSLength } from '../../../types';
import styles from './styles.module.scss';

interface LoadingProps {
dataName?: string;
isCompactSideMenu: boolean;
verticalMargin?: CSSLength;
horizontalMargin?: CSSLength;
mobileMargin?: CSSLength;
}

const Loading = ({ dataName = '' }: LoadingProps) => {
const Loading = ({
dataName = '',
isCompactSideMenu,
verticalMargin = '36px',
horizontalMargin = '64px',
mobileMargin = '16px',
}: LoadingProps) => {
const { t } = useTranslation(['translation', 'common']);
const style = {
'--vertical-margin': verticalMargin,
'--horizontal-margin': horizontalMargin,
'--mobile-margin': mobileMargin,
} as CSSProperties;

return (
<div className={styles.loadingScreen}>
<div>
<Spinner />
<FloatingContainer isCompactSideMenu={isCompactSideMenu} distanceFromBottom={verticalMargin}>
<div
className={clsx(
styles.loadingScreen,
isCompactSideMenu ? styles.withCompactSideMenu : styles.withExpandedSideMenu,
)}
style={style}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is inline styles temporary?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's permanent. This is the only way I know to use dynamic px values via props in CSS, but if you know a better way, please let me know!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, I didn't see the props being used by any parents yet so thought maybe it was just for testing. Would a className not be able to override variables too?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I see! It should be possible, but we'd have to do isCompactSideMenu ? styles.withCompactSideMenu : styles.withExpandedSideMenu in the parent component and write this much of CSS for a className, so using style seems more intuitive and simpler.

.className {
  height: calc(100vh - var(--global-navbar-height) - var(--vertical-margin) * 2);

  &.withCompactSideMenu {
    width: calc(100vw - var(--global-compact-side-menu-width) - var(--horizontal-margin) * 2);
  }
  &.withExpandedSideMenu {
    width: calc(100vw - var(--global-side-menu-width) - var(--horizontal-margin) * 2);
  }

  @include xs-breakpoint {
    &.withCompactSideMenu,
    &.withExpandedSideMenu {
      width: calc(100vw - var(--mobile-margin) * 2);
      height: calc(100vh - var(--global-navbar-height) - var(--mobile-margin) * 2);
      margin: var(--mobile-margin);
    }
  }
}

>
<div>
<Spinner />
</div>
<div className={styles.loadingText}>{t('common:LOADING')}</div>
<div className={styles.loadingMessage}>{t('common:FETCHING_YOUR_DATA', { dataName })}</div>
</div>
<div className={styles.loadingText}>{t('common:LOADING')}</div>
<div className={styles.loadingMessage}>{t('common:FETCHING_YOUR_DATA', { dataName })}</div>
</div>
</FloatingContainer>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ interface WithStepperProgressBarProps {
steps: {
formContent: ReactNode;
title: string;
onContinueAction?: (values: any) => Promise<void>;
dataName?: string;
}[];
activeStepIndex: number;
Expand Down Expand Up @@ -66,6 +65,9 @@ interface WithStepperProgressBarProps {
showCancelFlow?: boolean;
setShowCancelFlow?: React.Dispatch<React.SetStateAction<boolean>>;
headerComponent?: ((props: HeaderProps) => JSX.Element) | null;
showPreviousButton?: boolean;
showLoading?: boolean;
onAfterSave?: () => void;
}

export const WithStepperProgressBar = ({
Expand All @@ -92,29 +94,39 @@ export const WithStepperProgressBar = ({
showCancelFlow,
setShowCancelFlow,
headerComponent = StepperProgressBar,
showPreviousButton = true,
showLoading,
onAfterSave,
}: WithStepperProgressBarProps) => {
const [transition, setTransition] = useState<{ unblock?: () => void; retry?: () => void }>({
unblock: undefined,
retry: undefined,
});
const [isSaving, setIsSaving] = useState(false);
const [isLoading, setIsLoading] = useState(false);
const [isSaved, setIsSaved] = useState(false);

const isSummaryPage = hasSummaryWithinForm && activeStepIndex === steps.length - 1;
const isSingleStep = steps.length === 1;

// Block the page transition
// https://github.com/remix-run/history/blob/dev/docs/blocking-transitions.md
useEffect(() => {
if (isSummaryPage || !isDirty) {
if (isSummaryPage || !isDirty || isSaved) {
return;
}
const unblock = history.block((tx) => {
setTransition({ unblock, retry: tx.retry });
});

return () => unblock();
}, [isSummaryPage, isDirty, history]);
}, [isSummaryPage, isDirty, history, isSaved]);

useEffect(() => {
if (isSaved && onAfterSave) {
onAfterSave();
}
}, [isSaved, onAfterSave]);

useEffect(() => {
// Reset loading state whenever the step changes
Expand All @@ -139,23 +151,16 @@ export const WithStepperProgressBar = ({
};

const onContinue = async () => {
const { onContinueAction } = steps[activeStepIndex];

if (onContinueAction) {
if (isFinalStep) {
setIsLoading(true);
setIsSaving(true);
try {
// Execute the custom action for the current step before proceeding to the next one
await onContinueAction(getValues());
await handleSubmit((data: FieldValues) => onSave(data, onSuccess, setFormResultData))();
setIsSaved(true);
} catch (error) {
console.error(error);
setIsLoading(false);
return;
console.error(error);
}
}

if (isFinalStep) {
setIsSaving(true);
await handleSubmit((data: FieldValues) => onSave(data, onSuccess, setFormResultData))();
setIsSaving(false);
return;
}
Expand All @@ -179,8 +184,10 @@ export const WithStepperProgressBar = ({
setShowCancelFlow?.(false);
};

if (isLoading) {
return <Loading dataName={steps[activeStepIndex].dataName} />;
if (showLoading && isLoading) {
return (
<Loading dataName={steps[activeStepIndex].dataName} isCompactSideMenu={isCompactSideMenu} />
);
}

return (
Expand All @@ -200,7 +207,7 @@ export const WithStepperProgressBar = ({
<FormNavigationButtons
onContinue={onContinue}
onCancel={onCancel}
onPrevious={isSingleStep ? undefined : onGoBack}
onPrevious={isSingleStep || !showPreviousButton ? undefined : onGoBack}
isFirstStep={!activeStepIndex}
isFinalStep={isFinalStep}
isDisabled={!isValid || isSaving}
Expand Down Expand Up @@ -235,7 +242,7 @@ const StepperProgressBarWrapper = ({
headerComponent,
...stepperProgressBarProps
}: StepperProgressBarWrapperProps) => {
if (isSingleStep) {
if (isSingleStep && !headerComponent) {
return <>{children}</>;
}

Expand Down
6 changes: 4 additions & 2 deletions packages/webapp/src/components/Form/ContextForm/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
*/

import { useState, useMemo } from 'react';
import { FormProvider, useForm } from 'react-hook-form';
import { FormProvider, useForm, ValidationMode } from 'react-hook-form';
import { WithPageTitle } from './WithPageTitle';
import { WithStepperProgressBar } from './WithStepperProgressBar';

Expand All @@ -35,6 +35,7 @@ interface ContextFormProps {
variant?: Variant;
isEditing?: boolean;
setIsEditing?: React.Dispatch<React.SetStateAction<boolean>>;
formMode?: keyof ValidationMode;
[key: string]: any;
}

Expand All @@ -45,6 +46,7 @@ export const ContextForm = ({
variant = Variant.PAGE_TITLE,
isEditing = true,
setIsEditing,
formMode = 'onBlur',
...props
}: ContextFormProps) => {
const [activeStepIndex, setActiveStepIndex] = useState(0);
Expand All @@ -53,7 +55,7 @@ export const ContextForm = ({
const [showCancelFlow, setShowCancelFlow] = useState(false);

const form = useForm({
mode: 'onBlur',
mode: formMode,
defaultValues: defaultFormValues,
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,29 @@
flex-direction: column;
justify-content: center;
align-items: center;

padding: 16px;
background-color: var(--White);
border-radius: 8px;
box-shadow: 0px 0px 1px 0px #2b303a4d;

height: calc(100vh - var(--global-navbar-height) - var(--vertical-margin) * 2);

&.withCompactSideMenu {
width: calc(100vw - var(--global-compact-side-menu-width) - var(--horizontal-margin) * 2);
}
&.withExpandedSideMenu {
width: calc(100vw - var(--global-side-menu-width) - var(--horizontal-margin) * 2);
}

@include xs-breakpoint {
&.withCompactSideMenu,
&.withExpandedSideMenu {
width: calc(100vw - var(--mobile-margin) * 2);
height: calc(100vh - var(--global-navbar-height) - var(--mobile-margin) * 2);
margin: var(--mobile-margin);
}
}
}

.loadingText {
Expand Down
8 changes: 6 additions & 2 deletions packages/webapp/src/components/PageTitle/v2/index.jsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
import { Title } from '../../Typography';
import React, { useState } from 'react';
import clsx from 'clsx';
import styles from './styles.module.scss';
import { BsChevronLeft } from 'react-icons/bs';
import PropTypes from 'prop-types';
import { CancelButton } from '../CancelButton';

function PageTitle({ title, onGoBack, onCancel, style, cancelModalTitle, label }) {
function PageTitle({ title, onGoBack, onCancel, style, cancelModalTitle, label, classNames = {} }) {
const [showConfirmCancelModal, setShowConfirmCancelModal] = useState(false);
return (
<div className={styles.container} style={style}>
<div className={clsx(styles.container, classNames.wrapper)} style={style}>
<div className={styles.leftContainer} style={{ overflow: 'hidden', wordBreak: 'break-word' }}>
{onGoBack && (
<button type={'button'} className={styles.buttonContainer} onClick={onGoBack}>
Expand Down Expand Up @@ -41,4 +42,7 @@ PageTitle.propTypes = {
style: PropTypes.object,
label: PropTypes.node,
cancelModalTitle: PropTypes.string,
classNames: {
wrapper: PropTypes.string,
},
};
Loading
Loading