-
Notifications
You must be signed in to change notification settings - Fork 39
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
[MDS-5927] Bring Projects Form to CORE #3145
Changes from 7 commits
4586872
6c99c39
bdecc9d
9d4588c
3aaf367
c12ab4b
ac373c7
eee764e
ccdb035
f50477b
eef25ac
50e2930
1dc02b6
bf9b2b7
d49aeef
ee0c151
47bfc54
565b2a4
c20f887
d9e181b
510cdd7
74227b0
40c349e
5062083
98f42c5
5917ac8
bb802d4
c060f49
c863a13
4eb4949
6133eae
90920af
648d1f7
e1e2c6f
3185dd4
3c8bccb
f8afa66
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
import React, { FC } from "react"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One of many, many components to get moved or copied to common There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. More more more! |
||
|
||
export interface StepProps { | ||
disabled?: boolean; | ||
key: string; | ||
} | ||
|
||
const Step: FC<StepProps> = (props) => { | ||
return <>{props.children}</>; | ||
}; | ||
|
||
export default Step; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,54 +1,57 @@ | ||
import { Button, Col, Form, Menu, Popconfirm, Row } from "antd"; | ||
import React, { FC, ReactElement, useEffect, useState } from "react"; | ||
import { useSelector, useDispatch } from "react-redux"; | ||
import { getFormSyncErrors, getFormValues, submit } from "redux-form"; | ||
import { Button, Col, Menu, Popconfirm, Row, StepProps } from "antd"; | ||
import LeftOutlined from "@ant-design/icons/LeftOutlined"; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Basically, SteppedForm in this state:
|
||
import RightOutlined from "@ant-design/icons/RightOutlined"; | ||
import React, { useEffect, useState } from "react"; | ||
|
||
import PropTypes from "prop-types"; | ||
import { indexOf } from "lodash"; | ||
import { formatUrlToUpperCaseString } from "@mds/common/redux/utils/helpers"; | ||
|
||
const propTypes = { | ||
children: PropTypes.arrayOf(PropTypes.any).isRequired, | ||
handleTabChange: PropTypes.func.isRequired, | ||
handleSaveDraft: PropTypes.func, | ||
handleSaveData: PropTypes.func, | ||
handleCancel: PropTypes.func, | ||
activeTab: PropTypes.string.isRequired, | ||
errors: PropTypes.arrayOf(PropTypes.string), | ||
submitText: PropTypes.string, | ||
cancelText: PropTypes.string, | ||
cancelConfirmMessage: PropTypes.string, | ||
sectionChangeText: PropTypes.string, | ||
}; | ||
|
||
const defaultProps = { | ||
submitText: undefined, | ||
cancelText: undefined, | ||
handleSaveDraft: undefined, | ||
handleSaveData: undefined, | ||
handleCancel: undefined, | ||
cancelConfirmMessage: undefined, | ||
errors: [], | ||
sectionChangeText: undefined, | ||
}; | ||
|
||
const SteppedForm = (props) => { | ||
const { | ||
children, | ||
handleTabChange, | ||
activeTab, | ||
handleSaveDraft, | ||
handleSaveData, | ||
submitText, | ||
cancelText, | ||
handleCancel, | ||
cancelConfirmMessage, | ||
errors, | ||
sectionChangeText, | ||
} = props; | ||
import { flattenObject, formatUrlToUpperCaseString } from "@mds/common/redux/utils/helpers"; | ||
import FormWrapper from "./FormWrapper"; | ||
|
||
interface SteppedFormProps { | ||
formName: string; | ||
initialValues?: any; | ||
isEditMode?: boolean; | ||
children: Array<ReactElement<StepProps>>; | ||
handleTabChange: (newTab: string) => void | Promise<void>; | ||
handleSaveDraft?: (formValues) => Promise<void>; | ||
handleSaveData?: (values, newActiveTab?: string) => Promise<void>; | ||
handleCancel?: () => void | Promise<void>; | ||
transformPayload?: (values: any) => any; | ||
activeTab: string; | ||
submitText?: string; // "Submit" | ||
cancelText?: string; // "Cancel" | ||
cancelConfirmMessage?: string; | ||
sectionChangeText?: string; // Save & Continue | ||
nextText?: string; // "Next" | ||
disableTabsOnError?: boolean; | ||
} | ||
|
||
const SteppedForm: FC<SteppedFormProps> = ({ | ||
formName, | ||
initialValues, | ||
children, | ||
transformPayload, | ||
handleTabChange, | ||
handleSaveDraft, | ||
handleSaveData, | ||
handleCancel, | ||
activeTab, | ||
isEditMode = true, | ||
submitText = "Submit", | ||
cancelText = "Cancel", | ||
cancelConfirmMessage, | ||
sectionChangeText = "Save & Continue", | ||
nextText = "Next", | ||
disableTabsOnError = true, | ||
}) => { | ||
const [isSubmitting, setIsSubmitting] = useState(false); | ||
const [tabIndex, setTabIndex] = useState(0); | ||
const tabs = children.map((child) => child.key); | ||
const dispatch = useDispatch(); | ||
const formValues = useSelector(getFormValues(formName)); | ||
const formErrors = useSelector((state) => getFormSyncErrors(formName)(state)); | ||
const errors = Object.keys(flattenObject(formErrors)); | ||
|
||
useEffect(() => { | ||
setTabIndex(tabs.indexOf(activeTab)); | ||
|
@@ -70,17 +73,29 @@ const SteppedForm = (props) => { | |
} | ||
}; | ||
|
||
const handleNextClick = async (evt, tab) => { | ||
evt.preventDefault(); | ||
// checks for validation errors before saving draft or save & continues | ||
const saveCheck = async () => { | ||
await dispatch(submit(formName)); | ||
const valid = !errors.length; | ||
return valid; | ||
}; | ||
|
||
const getValues = (formValues) => { | ||
if (transformPayload) { | ||
return transformPayload(formValues); | ||
} | ||
return formValues; | ||
}; | ||
|
||
const handleDraftClick = async (evt, tab) => { | ||
evt.preventDefault(); | ||
setIsSubmitting(true); | ||
|
||
try { | ||
if (handleSaveData) { | ||
await handleSaveData(null, tab); | ||
if (handleSaveDraft && (await saveCheck())) { | ||
await handleSaveDraft(getValues(formValues)); | ||
} | ||
if (errors.length > 0) return; | ||
|
||
setTabIndex(indexOf(tabs, tab)); | ||
} finally { | ||
setIsSubmitting(false); | ||
|
@@ -90,12 +105,26 @@ const SteppedForm = (props) => { | |
const isFirst = tabIndex === 0; | ||
const isLast = tabs.length - 1 === tabIndex; | ||
|
||
const handleNextClick = async (evt, tab) => { | ||
evt.preventDefault(); | ||
setIsSubmitting(true); | ||
try { | ||
if (handleSaveData && (await saveCheck())) { | ||
await handleSaveData(getValues(formValues), tab); | ||
} | ||
if (errors.length > 0) return; | ||
setTabIndex(indexOf(tabs, tab)); | ||
} finally { | ||
setIsSubmitting(false); | ||
} | ||
}; | ||
|
||
const items = tabs.map((tab) => { | ||
const child = children.find((childTab) => childTab.key === tab); | ||
return { | ||
label: formatUrlToUpperCaseString(tab), | ||
key: tab, | ||
disabled: child?.props?.disabled, | ||
disabled: child?.props?.disabled || (disableTabsOnError && errors.length > 0), | ||
className: "stepped-menu-item", | ||
onClick: () => handleTabClick(tabs[indexOf(tabs, tab)]), | ||
}; | ||
|
@@ -104,12 +133,29 @@ const SteppedForm = (props) => { | |
return ( | ||
<Row> | ||
<Col span={6} className="stepped-form-menu-container"> | ||
<Menu className="stepped-form" mode="inline" selectedKeys={tabs[tabIndex]} items={items} /> | ||
<Menu | ||
className="stepped-form" | ||
mode="inline" | ||
selectedKeys={[tabs[tabIndex].toString()]} | ||
items={items} | ||
/> | ||
</Col> | ||
<Col span={18}> | ||
{children && ( | ||
<div className="stepped-form-form-container"> | ||
<Form layout="vertical">{children.find((child) => child.key === tabs[tabIndex])}</Form> | ||
<FormWrapper | ||
name={formName} | ||
onSubmit={() => {}} | ||
initialValues={initialValues} | ||
isEditMode={isEditMode} | ||
reduxFormConfig={{ | ||
touchOnBlur: true, | ||
touchOnChange: false, | ||
enableReinitialize: true, | ||
taraepp marked this conversation as resolved.
Show resolved
Hide resolved
|
||
}} | ||
> | ||
{children.find((child) => child.key === tabs[tabIndex])} | ||
</FormWrapper> | ||
<Row | ||
justify={isFirst && tabs.length > 1 ? "end" : "space-between"} | ||
className="stepped-form-button-row" | ||
|
@@ -137,30 +183,40 @@ const SteppedForm = (props) => { | |
</Popconfirm> | ||
)} | ||
|
||
{!isLast && ( | ||
{isEditMode && !isLast && ( | ||
<div> | ||
{handleSaveDraft && ( | ||
<Button | ||
type="text" | ||
className="full-mobile draft-button" | ||
onClick={handleSaveDraft} | ||
onClick={(e) => handleDraftClick(e, tabs[tabIndex + 1])} | ||
style={{ marginRight: 16 }} | ||
> | ||
Save Draft | ||
</Button> | ||
)} | ||
<Button | ||
type="primary" | ||
htmlType="button" | ||
disabled={isSubmitting} | ||
onClick={(e) => handleNextClick(e, tabs[tabIndex + 1])} | ||
> | ||
{sectionChangeText ?? <>Save & Continue</>} | ||
{sectionChangeText} | ||
<RightOutlined /> | ||
</Button> | ||
</div> | ||
)} | ||
{isLast && ( | ||
<Button type="primary" disabled={isSubmitting} onClick={handleSaveData}> | ||
{!isEditMode && !isLast && ( | ||
<Button type="primary" htmlType="button" onClick={() => setTabIndex(tabIndex + 1)}> | ||
{nextText} | ||
</Button> | ||
)} | ||
{isEditMode && isLast && ( | ||
<Button | ||
type="primary" | ||
onClick={(e) => handleNextClick(e, null)} | ||
disabled={isSubmitting} | ||
> | ||
{submitText || "Submit"} | ||
</Button> | ||
)} | ||
|
@@ -172,7 +228,4 @@ const SteppedForm = (props) => { | |
); | ||
}; | ||
|
||
SteppedForm.propTypes = propTypes; | ||
SteppedForm.defaultProps = defaultProps; | ||
|
||
export default SteppedForm; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just for Denise- making file-size show up by default.