Skip to content

Commit

Permalink
Merge pull request #4656 from openboxes/OBPIH-6329
Browse files Browse the repository at this point in the history
OBPIH-6329 Add details step of full outbound import form
  • Loading branch information
awalkowiak committed Jun 11, 2024
2 parents 7c2447a + 7439c0a commit dd8070f
Show file tree
Hide file tree
Showing 17 changed files with 580 additions and 35 deletions.
28 changes: 28 additions & 0 deletions grails-app/i18n/messages.properties
Original file line number Diff line number Diff line change
Expand Up @@ -4464,3 +4464,31 @@ react.rejectRequestModal.provideReason.label=Please provide a reason for rejecti
# React info bar descriptions
react.infoBar.stockTransfer.instructions.label=A Stock Transfer is an inventory tool that allows you to transfer stock from one bin location or zone to another. Use this inventory tool to reflect in OpenBoxes the physical location of inventory within your depot or warehouse.
react.infoBar.replenishment.instructions.label=A Stock Replenishment is an inventory tool that allows you to replenish stock from a bulk section into a set of bins designated for picking. Use this inventory tool to replenish the quantity of a product in a bin with a certain min or max level that you want to maintain.

# Outbound import feature
react.outboundImport.form.description.title=Description
react.outboundImport.form.origin.title=Origin
react.outboundImport.form.destination.title=Destination
react.outboundImport.form.requestedBy.title=Requested By
react.outboundImport.form.dateRequested.title=Date Requested
react.outboundImport.form.dateShipped.title=Date Shipped
react.outboundImport.form.shipmentType.title=Shipment Type
react.outboundImport.form.trackingNumber.title=Tracking number
react.outboundImport.form.expectedDeliveryDate.title=Expected delivery date
react.outboundImport.form.importPackingList.title=Import packing list
react.outboundImport.form.next.label=Next
react.outboundImport.form.details.label=Details
react.outboundImport.form.basicDetails.label=Basic details
react.outboundImport.form.sendingOptions.label=Sending options
react.outboundImport.steps.details.label=Create
react.outboundImport.steps.confirm.label=Confirm
react.outboundImport.header.title=Import completed outbound
react.outboundImport.validation.description.required.label=Description is required
react.outboundImport.validation.origin.required.label=Origin is required
react.outboundImport.validation.destination.required.label=Destination is required
react.outboundImport.validation.requestedBy.required.label=Requested by is required
react.outboundImport.validation.dateRequested.required.label=Date requested is required
react.outboundImport.validation.dateRequested.futureDate.label=The date cannot be in the future
react.outboundImport.validation.dateShipped.required.label=Date shipped is required
react.outboundImport.validation.shipmentType.required.label=Shipment type is required
react.outboundImport.validation.expectedDeliveryDate.required.label=Expected delivery date is required
4 changes: 4 additions & 0 deletions src/css/main.scss
Original file line number Diff line number Diff line change
Expand Up @@ -1622,3 +1622,7 @@ div.search-input:focus-within {
.jipt-login-dialog {
inset: 0 auto 0 !important;
}

.fit-content {
width: fit-content;
}
2 changes: 1 addition & 1 deletion src/js/components/Layout/v2/Section.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import './styles.scss';
const Section = ({ title, children, className }) => (
<div className={`v2-section ${className}`}>
<span className="v2-section-title text-uppercase">
<Translate id={title.label} defaultMessage={title.defaultMessage} />
<Translate id={title?.label} defaultMessage={title?.defaultMessage} />
</span>
{children}
</div>
Expand Down
24 changes: 19 additions & 5 deletions src/js/components/form-elements/v2/DateField.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import DatePicker from 'react-datepicker';

import DateFieldInput from 'components/form-elements/v2/DateFieldInput';
import { DateFormat, TimeFormat } from 'consts/timeFormat';
import useTranslate from 'hooks/useTranslate';
import InputWrapper from 'wrappers/InputWrapper';
import RootPortalWrapper from 'wrappers/RootPortalWrapper';

import 'react-datepicker/dist/react-datepicker.css';
import 'components/form-elements/DateFilter/DateFilter.scss';
import './style.scss';
import useTranslate from 'hooks/useTranslate';

const DateField = ({
title,
Expand All @@ -25,19 +25,30 @@ const DateField = ({
className,
value,
onChange,
showTimeSelect,
...fieldProps
}) => {
const translate = useTranslate();
const onClear = () => onChange(null);

const onChangeHandler = date => onChange(date?.format(DateFormat.MMM_DD_YYYY));
const onChangeHandler = (date) => {
if (showTimeSelect) {
onChange(date?.format(DateFormat.MMM_DD_YYYY_HH_MM_SS));
return;
}
onChange(date?.format(DateFormat.MMM_DD_YYYY));
};

const formatDate = (dateToFormat) => {
if (!dateToFormat) {
return null;
}

return moment(new Date(dateToFormat), DateFormat.MMM_DD_YYYY);
if (showTimeSelect) {
return moment(new Date(dateToFormat), DateFormat.MMM_DD_YYYY_HH_MM_SS);
}
return showTimeSelect
? moment(new Date(dateToFormat), DateFormat.MMM_DD_YYYY_HH_MM_SS)
: moment(new Date(dateToFormat), DateFormat.MMM_DD_YYYY);
};

const selectedDate = formatDate(value);
Expand All @@ -57,10 +68,11 @@ const DateField = ({
>
<DatePicker
{...fieldProps}
showTimeSelect={showTimeSelect}
customInput={<DateFieldInput onClear={onClear} />}
className={`form-element-input ${errorMessage ? 'has-errors' : ''} ${className}`}
dropdownMode="scroll"
dateFormat={DateFormat.MMM_DD_YYYY}
dateFormat={showTimeSelect ? DateFormat.MMM_DD_YYYY_HH_MM_SS : DateFormat.MMM_DD_YYYY}
timeFormat={TimeFormat.HH_MM}
disabled={disabled}
timeIntervals={15}
Expand Down Expand Up @@ -116,6 +128,7 @@ DateField.propTypes = {
className: PropTypes.string,
value: PropTypes.string,
onChange: PropTypes.func,
showTimeSelect: PropTypes.bool,
};

DateField.defaultProps = {
Expand All @@ -129,4 +142,5 @@ DateField.defaultProps = {
className: '',
value: null,
onChange: () => {},
showTimeSelect: false,
};
Original file line number Diff line number Diff line change
@@ -1,34 +1,44 @@
import React, { useMemo } from 'react';

import OutboundImportConfirm from 'components/stock-movement-wizard/outboundImport/OutboundImportConfirm';
import OutboundImportDetails from 'components/stock-movement-wizard/outboundImport/OutboundImportDetails';
import OutboundImportHeader from 'components/stock-movement-wizard/outboundImport/OutboundImportHeader';
import OutboundImportDetails from 'components/stock-movement-wizard/outboundImport/sections/OutboundImportDetails';
import WizardStepsV2 from 'components/wizard/v2/WizardStepsV2';
import useOutboundImportForm from 'hooks/outboundImport/useOutboundImportForm';
import useTranslate from 'hooks/useTranslate';
import useTranslation from 'hooks/useTranslation';
import useWizard from 'hooks/useWizard';
import PageWrapper from 'wrappers/PageWrapper';

import 'utils/utils.scss';

const OutboundImport = () => {
useTranslation('outboundImport');
const translate = useTranslate();

const OutboundImportStep = {
DETAILS: {
key: 'DETAILS',
// TODO: Make titles translatable in OBPIH-6329
title: 'Create',
title: translate('react.outboundImport.steps.details.label', 'Create'),
},
CONFIRM: {
key: 'CONFIRM',
title: 'Confirm',
title: translate('react.outboundImport.steps.confirm.label', 'Confirm'),
},
};

const steps = useMemo(() => [
{
key: OutboundImportStep.DETAILS.key,
title: OutboundImportStep.DETAILS.title,
Component: () => (<OutboundImportDetails />),
Component: (props) => (<OutboundImportDetails {...props} />),
},
{
key: OutboundImportStep.CONFIRM.key,
title: OutboundImportStep.CONFIRM.title,
Component: () => (<OutboundImportConfirm />),
Component: (props) => (<OutboundImportConfirm {...props} />),
},
], []);
], [translate]);

const stepsTitles = steps.map((step) => ({
title: step.title,
Expand All @@ -40,16 +50,34 @@ const OutboundImport = () => {
{
next,
previous,
is,
},
] = useWizard({ initialKey: OutboundImportStep.DETAILS.key, steps });

const {
errors,
control,
isValid,
handleSubmit,
onSubmit,
} = useOutboundImportForm({ next });

const detailsComponentProps = {
control,
errors,
isValid,
next,
};

return (
<div>
<PageWrapper>
<WizardStepsV2 steps={stepsTitles} currentStepKey={Step.key} />
<Step.Component />
<button type="button" onClick={() => previous()}>previous</button>
<button type="button" onClick={() => next()}>next</button>
</div>
<OutboundImportHeader />
<form onSubmit={handleSubmit(onSubmit)}>
{is(OutboundImportStep.DETAILS.key) && (<Step.Component {...detailsComponentProps} />)}
{is(OutboundImportStep.CONFIRM.key) && (<Step.Component previous={previous} />)}
</form>
</PageWrapper>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
import React from 'react';

const OutboundImportConfirm = () => {
return (
<div>
Confirm
</div>
);
};
import PropTypes from 'prop-types';

const OutboundImportConfirm = ({ previous }) => (
<div>
Confirm
<button type="button" onClick={() => previous()}>previous</button>
</div>
);

export default OutboundImportConfirm;

OutboundImportConfirm.propTypes = {
previous: PropTypes.func.isRequired,
};

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React from 'react';

import useTranslate from 'hooks/useTranslate';
import HeaderWrapper from 'wrappers/HeaderWrapper';

const OutboundImportHeader = () => {
const translate = useTranslate();
return (
<HeaderWrapper className="align-items-end h-100 pt-3">
<div className="create-page-title">
<span className="create-page-tile-main-content">
{translate('react.outboundImport.header.title', 'Import completed outbound')}
</span>
</div>
</HeaderWrapper>
);
};

export default OutboundImportHeader;
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';

import PropTypes from 'prop-types';

import Button from 'components/form-elements/Button';
import Section from 'components/Layout/v2/Section';
import OutboundImportBasicDetails
from 'components/stock-movement-wizard/outboundImport/subsections/OutboundImportBasicDetails';
import OutboundImportSendingOptions
from 'components/stock-movement-wizard/outboundImport/subsections/OutboundImportSendingOptions';
import { FormErrorPropType } from 'utils/propTypes';

const OutboundImportDetails = ({ control, errors, isValid }) => (
<Section
title={{
label: 'react.outboundImport.form.details.label',
defaultMessage: 'Details',
}}
>
<OutboundImportBasicDetails control={control} errors={errors} />
<OutboundImportSendingOptions control={control} errors={errors} />
<Button
label="react.outboundImport.form.next.label"
defaultLabel="Next"
variant="primary"
type="submit"
className="fit-content align-self-end"
disabled={!isValid}
/>
</Section>
);

export default OutboundImportDetails;

OutboundImportDetails.propTypes = {
errors: PropTypes.shape({
description: FormErrorPropType,
origin: FormErrorPropType,
destination: FormErrorPropType,
requestedBy: FormErrorPropType,
dateRequested: FormErrorPropType,
dateShipped: FormErrorPropType,
shipmentType: FormErrorPropType,
trackingNumber: FormErrorPropType,
expectedDeliveryDate: FormErrorPropType,
packingList: FormErrorPropType,
}).isRequired,
control: PropTypes.shape({}).isRequired,
isValid: PropTypes.bool.isRequired,
};
Loading

0 comments on commit dd8070f

Please sign in to comment.