I am just learning react and has come across a problem which has caused much trouble for me. I am using Form from semantic-ui along with the reduxForm.
EditCourseOffer.tsx
import React, { useEffect, useState } from 'react';
import { Button, Form, Modal, Input, TextArea, Radio, Confirm, Checkbox, Dropdown } from 'semantic-ui-react'
import RichText from '../../components/RichText/RichText';
// import { Multiselect } from 'multiselect-react-dropdown';
import * as store from 'store2';
import { Field, reduxForm, FieldArray, formValueSelector } from 'redux-form';
import { connect } from 'react-redux';
import updateCourseOffer from './services/updateCourseOffer';
import * as layoutServices from './../../components/Layout/Services/layoutService';
import * as expertService from './services/expertServices';
import { toastr } from 'react-redux-toastr';
import { withTranslation } from 'react-i18next';
import moment from 'moment';
const selectLanguage = [
{ key: 'Spanish', text: 'Spanish', value: 'Spanish' },
{ key: 'English', text: 'English', value: 'English' },
{ key: 'German', text: 'German', value: 'German' },
]
const selectCategory = [
{ key: 'Spanish', text: 'Spanish', value: 'Element 1' },
{ key: 'English', text: 'English', value: 'Element 2' },
{ key: 'German', text: 'German', value: 'Element 3' },
]
const selectSkills = [
{ key: 'Element 1', text: 'Element 1', id: 'Php' },
{ key: 'Element 2', text: 'Element 2', id: 'Wordpress' },
{ key: 'Element 3', text: 'Element 3', id: 'SEO' },
]
const state = {
options: selectSkills,
selectedValue: [],
skills: []
};
const todayDate = new Date().getFullYear() + "-" + ("0" + (new Date().getMonth() + 1)) + "-" + new Date().getDate();
const renderSelectField = ({ id, input, defaultValue, className, label, select, placeholder, children, type, options, meta: { touched, error } }) => (
<Form.Field>
<div>
<label>{label}<span className="requiredMark">*</span></label>
<div>
<Dropdown selection
search
size="mini"
multiple={label == 'Category' ? false : true}
onChange={(param, data) => { return input.onChange(input.value ? data.value : data.value) }}
placeholder={placeholder}
options={options}
className={className}
defaultValue={defaultValue}
/>
{touched && error && <span className="error-h">{error}</span>}
</div>
</div>
</Form.Field>
)
const renderInputField = ({ id, input, className, label, select, placeholder, children, type, options, meta: { touched, error } }) => (
<Form.Field>
<div>
{label != 'Min' && label != 'Max' ? <label>{label}<span className="requiredMark">*</span></label> : ''}
<div>
<Form.Field>
<div className="form-to style-2">
<div className="col">
<div className="">
<Input value={input} style={{ width: '30%' }} type={type} {...input} iconPosition='left' placeholder="00">
<span className="text">{label == 'Price' ? 'EUR' : label}</span>
<input className="text-right" />
</Input>
</div>
</div>
</div>
</Form.Field>
{touched && error && <span className="error-h">{error}</span>}
</div>
</div>
</Form.Field>
)
const renderInputDates = ({ input, className, id, icon, label, name, placeholder, value, type, meta: { touched, error } }) => (
<div className="col input-with-icon">
{/* {...input} onChange={(e)=>{return setDate(e,e.target)}} */}
{type == 'date'
? <input name={name} style={{ height: "70%", width: "99%", padding: "8px" }} min={todayDate} size="mini" {...input}
type="date" placeholder={placeholder} />
: <input name={name} id={id} style={{ height: "70%", width: "99%", padding: "8px" }} {...input} type={type} placeholder={placeholder} size="mini" />
}
{touched && error && <span className="error-h">{error}</span>}
</div>
)
const renderDates = ({ fields, label }) => (
<Form.Field>
<div style={{ position: 'relative', "marginBottom": '30px' }}>
<label>{label} <span className="requiredMark">*</span>
<span className="pull-right" style={{ float: 'right', position: 'absolute', right: '1rem' }}>
<Button type="button" size="small" onClick={() => fields.push({})} basic primary >Add</Button>
</span>
</label>
</div>
{fields.map((course, index) =>
<div key={index} className="three-inputs-h">
<Field
name={`${course}.date`}
type="date"
placeholder="Date"
icon={'insert_invitation'}
component={renderInputDates}
label="Date" />
<Field
name={`${course}.startTime`}
type="time"
icon="schedule"
id="start"
placeholder="Start Time"
component={renderInputDates}
label="Start Time" />
<Field
name={`${course}.endTime`}
type="time"
id="end"
icon="schedule"
placeholder="End Time"
component={renderInputDates}
label="End Time" />
<Button type="button" style={{ position: "absolute", borderRadius: "50%", margin: "1px", right: "-31px", height: "32px", width: "32px" }} negative icon='trash' onClick={() => fields.remove(index)} >
</Button>
</div>
)}
</Form.Field>
)
const required = value => (!value ? `FormMessage.Error` : undefined)
function EditCourseOffer(props) {
const { error, handleSubmit, pristine, dates, initialValues, reset, t, submitting, courseDetails } = props;
const [open, setOpen] = React.useState(false);
const [level, setLevel] = useState(props.courseDetails?.Level || 'Beginner')
const [todayDate, setTodayDate] = useState('');
const [category, setCategory] = useState([])
const [confirm, setConfirm] = useState(false);
const [check, setCheck] = useState(props.courseDetails?.IsDisabled || false);
const [courseDetail,setCourseDetail] = useState(props.courseDetails)
const [skills, setSkills] = React.useState([])
const renderField = ({ input, className, label, disabled, placeholder, value, type, meta: { touched, error } }) => (
<Form.Field>
<label>{label}<span className="requiredMark">*</span></label>
<div className={touched && error ? 'field-error' : className}>
{type == 'input'
?
<Input className="small" size="mini" disabled={disabled} value={input} {...input} placeholder={placeholder} type={type} />
:
<TextArea className="small" size="mini" disabled={disabled} value={input} {...input} placeholder={placeholder} type={type} />
}
</div>
{touched && error && <span className="error-h">{t(error)}</span>}
</Form.Field>
)
const updateFrom = (value) => {
props.dispatch({ type: '@@redux-form/CHANGE', meta: { field: "Description", form: "editCourseOffer", persistentSubmitErrors: false, touch: false }, payload: value })
}
useEffect(() => {
setLevel(props && props['courseDetails']['OfferLevel'])
setSkills(state.selectedValue);
const today = new Date().getFullYear() + '-' + ('0' + (new Date().getMonth() + 1)) + '-' + new Date().getDate();
setTodayDate(today);
// props.dispatch({ type: '@@redux-form/CHANGE', meta: { field: "OfferID", form: "editCourseOffer", persistentSubmitErrors: false, touch: false }, payload: props && props.courseDetails.OfferID });
}, []);
useEffect(()=>{
reset(courseDetails)
setTimeout(()=>{
setCourseDetail(courseDetails)
},2000)
},[props.courseDetails])
const getAllCategories = (currentLang: any) => {
layoutServices.getAllCategories({ sortType: currentLang || 'EN' }).then(data => data.json()).then(categories => {
if (categories.data && categories.data.res && categories.data.res.length > 0) {
const categoryData = categories.data.res.map((data, key) => {
return { key: key, value: data.EN, text: data.CategoryName }
})
setCategory(categoryData);
}
})
}
const [courseImage, setcourseImage] = useState('')
const selector = formValueSelector("editCourseOffer");
const value = selector(state, "CourseDates");
return (
<Modal
onClose={() => setOpen(false)}
onOpen={() => setOpen(true)}
open={open}
size={'large'}
className="form-modal"
trigger={<span className="material-icons edit-link">edit</span>}
>
<Form intialvalue={props.courseDetails} name="editCourseOffer" onSubmit={handleSubmit(updateCourseOffer)} className="w-100">
<Modal.Header className="modal-header">
<h6>Edit course offer</h6>
<div className="close-modal" onClick={() => setOpen(false)}>
<span className="material-icons">close</span>
</div>
</Modal.Header>
<Modal.Content className="modal-content">
<div className="course-inputinfo-area">
<div className="left-info">
<Field validate={[required]} label="Title" value={courseDetail.Title} component={renderField} placeholder='Enter title in 1-2 lines.' type="input" id="Title" name="Title">
</Field>
<Field label="Select one or more languages" className="mini" placeholder='Select' options={selectLanguage} defaultValue={props.courseDetails?.Language.split(',')} component={renderSelectField} id="Language" type="select" name="Language">
</Field>
<Field label="Overview" component={renderField} placeholder='Enter most important about this offer in maximum 3 lines.' type="textarea" id="Overview" name="Overview">
</Field>
<div className="divide"></div>
<FieldArray label="Add Date" name="CourseDates" component={renderDates} />
{/* <Form.Field>
<label>Add Date <span className="requiredMark">*</span></label>
<div className="three-inputs">
<div className="col input-with-icon">
<Input placeholder='Start Date' size="mini" />
<span className="material-icons icon">insert_invitation</span>
</div>
<div className="col input-with-icon">
<Input placeholder='End Date' size="mini" />
<span className="material-icons icon">insert_invitation</span>
</div>
<div className="col">
<Button size="small" basic primary >Add</Button>
</div>
</div>
</Form.Field> */}
<Form.Field>
<div className="three-inputs">
<div className="col input-with-icon">
<div className="select-check-date">
<div className="list">
<Checkbox checked className="mini" label="(DE time)" />
</div>
{/* ::::::<p>{dates && JSON.stringify(dates)}</p> */}
<p>{dates && dates instanceof Array && dates.map((data, key) => {
return <p key={key}>{data['endTime'] && `${data['date']}: ${data['startTime']} - ${data['endTime']} (DE Time)`} </p>
})}</p>
{
props.courseDetails?.OfferDate ? props.courseDetails?.OfferDate.map((data,key)=>{
return <p>
{moment(data.date).format('DD.MM.YYYY')} {data.startTime} - {data.endTime}
</p>
}) : ''
}
</div>
</div>
</div>
</Form.Field>
</div>
<div className="right-info">
<div className="form-to style-2">
<div className="col">
<Field label="Price" component={renderInputField} placeholder='Price' type="input" id="Price" name="Price"></Field>
</div>
<div className="col">
<label>Attendees</label>
<div className="repeat">
<Field label="Min" component={renderInputField} placeholder='Min Attendees' type="input" id="Min" name="Min"></Field>
</div>
<div className="repeat">
<Field label="Max" component={renderInputField} placeholder='Max Attendees' type="input" id="Max" name="Max"></Field>
</div>
</div>
</div>
</div>
</div>
</Modal.Content>
<Modal.Actions className="modal-btn-footer edit-mode style-3">
<div className="btn-area">
<Button size='small' type="submit" disabled={submitting} onClick={(e) => { e.stopPropagation() }}>
{submitting ? 'Please wait...' : 'Save'}
</Button>
<Button size='small' basic primary onClick={() => setOpen(false)}>
Cancel
</Button>
<div className="delete-btn-area">
<Button size='small' type="button" basic primary onClick={(e) => { e.preventDefault(); return setConfirm(true) }}>
Delete Offer
</Button>
<Confirm
open={confirm}
onCancel={() => setConfirm(false)}
onConfirm={() => handleOfferDelete("Delete")}
size="large"
content="Are you Sure? Click OK to proceed."
header="You are about to delete card permanently.If you are not sure disable now and can use in future."
/>
<p>You loose all offer data and reviews. You agree to <a href="#">HelpaaS's Conditions of Use</a> and <a href="#">Privacy Notice</a>.</p>
</div>
<div className="disable-info">
<div className="left">
<p>Disable offer</p>
<p className="small-text">All data and ratings are kept, but offer is not available anymore.</p>
</div>
<div className="right">
<Checkbox checked={check} onChange={handleOfferDisable} className="toggle checkbox-with-onoff" />
</div>
</div>
</div>
</Modal.Actions>
</Form>
</Modal>
)
}
type propTypes = {
courseDetails: any
}
const selector = formValueSelector('editCourseOffer')
const mapStateToProps = (props, state) => {
console.log(props,state['courseId'], "INCISDE MAP STATE TO PROPS",state)
return {
initialValues: {
Price: state['courseDetails'] && new Intl.NumberFormat('de-DE').format(state['courseDetails']['Price']),
Title: state['courseDetails'] && state['courseDetails']['Title'],
Language: state['courseDetails'] && state['courseDetails']['Language'],
Overview: state['courseDetails'] && state['courseDetails']['Overview'],
Min: state['courseDetails'] && state['courseDetails']['OfferAttendeesMin'] || 0,
Max: state['courseDetails'] && state['courseDetails']['OfferAttendeesMax'] || 0,
Level: state['courseDetails'] && state['courseDetails']['OfferLevel'],
Category: state['courseDetails'] && state['courseDetails']['Category'],
Description: state['courseDetails'] && state['courseDetails']['Description'],
CourseDates: [{ date: state['courseDetails']['OfferDate'], startTime: "", endTime: "" }],
ExpertID: store.get('userDetails')?.ExpertID || '',
ClientID: store.get('userDetails')?.ClientID || '',
isDisabled: false,
IsCourse: true,
Picture: state['courseDetails'] && state['courseDetails']['PictureURL'] || null,
AzureId: store.get('userDetails').id,
OfferID: state['courseDetails'] && state['courseDetails']['OfferID'],
internetLink : state['courseDetails'] && state['courseDetails']['OfferCourseLink'] || '',
},
dates: selector(state, 'CourseDates')
}
}
// export default EditExpertOffer;
export default withTranslation()(connect(mapStateToProps)(reduxForm({
form: 'editCourseOffer',enableReinitialize : false
})(EditCourseOffer)));
EditExpertProfile.tsx
{
allOffers && allOffers.map((data, key) => {
<div key={key} className={data.IsDisabled ? "card-block-area disabled" : "card-block-area"}>
<div className="card-block-header card-block-header-2">
<div className="card-top-right">
<div className="status-area">
<EditCourseOffer courseDetails={data} courseId={data.OfferID} />
</div>
</div>
<div className="action-btn">
<Button size='mini' className='full-width'>{t(`GlobalButtons.Buy`)}</Button>
<Button size='mini' basic primary className='full-width'>{t(`GlobalButtons.AddToCart`)}</Button>
</div>
</div>
</div>
})
}
Issues are :
If I click on any of the form the props value is correct but form displays the wrong binded values. In other words it always takes the value of first element of array and binds as initialValue to form.
I am unable to render the time fields as prefilled to the FieldArray.
Card with edit button in array.

Although I clicked on second card still it shows first card value inside Edit Form.
