I am having an issue when routing in Microsoft edge. I have 3 pages and they work like a wizard.
getting-started>start-date>proposer
The application jumps back to getting-started, when I go from start-date to proposer. really weird behaviour and only happing in Edge browser.
Please find the code below,
Start date:
import React, { Component } from "react";
import {
Button,
Form,
Header,
Container,
Grid,
Message
} from "semantic-ui-react";
import { WizardStepper } from "./WizardStepper";
import { startDateActions } from "../redux/actions/startdate-actions";
import { connect } from "react-redux";
import moment from "moment";
import { QuoteRequest } from "../models/quote-request";
import { IStoreState } from "../redux/reducers";
import { AuthResponse } from "../models/auth-response";
import { quoteActions } from "../redux/actions/quote-actions";
import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";
interface IStartDateProps {
history: any;
addQuoteStartDate(quoteStartDate: string): void;
clearErrors(quoteRequest: QuoteRequest): void;
quoteRequest: QuoteRequest;
quoteStartDate: string;
}
export class _StartDate extends Component<IStartDateProps> {
state = {
startDate: new Date(),
showDateEmptyError: false
};
constructor(props: IStartDateProps) {
super(props);
this.state.startDate = this.props.quoteStartDate
? moment(this.props.quoteStartDate).toDate()
: new Date();
}
render() {
return (
<Container fluid>
<WizardStepper
activeStep={2} />
<Container className="basic padded segment abg___main_content_wrapper">
<Header as="h1" className="page-title">
Choose the Start Date
</Header>
<p>
The start date for cover can be from today's date up to 45 days
ahead; we cannot back-date cover.
</p>
<div className="ui hidden divider" />
<Grid stackable>
<Grid.Row>
<Grid.Column mobile={16} tablet={9} computer={8}>
<Form>
<label>What date would you like the cover to start?</label>
<Container className="abg___datepicker">
<DatePicker
className={
this.state.showDateEmptyError ? "error-datepicker" : ""
}
autoComplete="off"
dateFormat="dd/MM/yyyy"
minDate={moment().toDate()}
maxDate={moment()
.add(45, "day")
.toDate()}
onChange={(date: any) => {
this.setState({ startDate: date });
}}
placeholderText="Start date (DD/MM/YYYY)"
selected={this.state.startDate}
/>
{this.state.showDateEmptyError === true ? (
<Message negative>
Please complete the highlighted mandatory field
</Message>
) : null}
<div className="ui hidden divider" />
<Button
size="large"
positive
className="right floated"
onClick={() => {
if (!this.state.startDate) {
this.setState({ showDateEmptyError: true });
} else {
this.setState({ showDateEmptyError: false });
this.props.addQuoteStartDate(
moment(this.state.startDate).format()
);
//Note:This will clear any errors if you had any errors in the next quote proposer screen
this.props.clearErrors(this.props.quoteRequest);
this.props.history.push("/quote/quote-proposer");
}
}}
>
Next
</Button>
</Container>
</Form>
</Grid.Column>
</Grid.Row>
</Grid>
</Container>
</Container>
);
}
}
const mapStateToProps = ({
quoteStartDate,
authResponse,
quoteRequest
}: IStoreState): {
quoteStartDate: string;
authResponse: AuthResponse;
quoteRequest: QuoteRequest;
} => {
return { quoteStartDate, authResponse, quoteRequest };
};
const mapDispatchToProps = (dispatch: any) => {
return {
addQuoteStartDate: (quoteStartDate: string) => {
return dispatch(startDateActions.addStartDate(quoteStartDate));
},
clearErrors: (quoteRequest: QuoteRequest) => {
return dispatch(quoteActions.clearErrors(quoteRequest));
}
};
};
export const StartDate = connect(
mapStateToProps,
mapDispatchToProps
)(_StartDate);
Proposer:
import React from "react";
import {
Button,
Form,
Header,
Container,
Message,
Grid
} from "semantic-ui-react";
import { WizardStepper } from "./WizardStepper";
import { QuoteRequest, Proposer } from "../models/quote-request";
import { connect } from "react-redux";
import { quoteActions } from "../redux/actions/quote-actions";
import { IStoreState } from "../redux/reducers";
import { QuoteType } from "../models/enums";
import { validation } from "../util/validation";
import ErrorMessage from "./validators/ErrorMessage";
import { TitleSelector } from "./shared/TitleSelector";
interface IQuoteProposerProps {
history: any;
quoteStartDate: string;
createQuote(quoteRequest: QuoteRequest): void;
updateQuote(quoteId: number, quoteRequest: QuoteRequest): void;
resetQuoteUpdate(quoteRequest: QuoteRequest): void;
quoteType: QuoteType;
quoteRequest: QuoteRequest;
clearErrors(quoteRequest: QuoteRequest): void;
}
export class _QuoteProposer extends React.Component<IQuoteProposerProps> {
state = {
title: "",
firstName: "",
surname: "",
companyName: "",
contactEmail: "",
contactPhone: "",
showFirstNameEmptyError: false,
showSurNameEmptyError: false,
isTitleSelected: "",
showInvalidEmailError: false,
showInvalidPhoneError: false,
isValidForm: null,
areMandatoryFieldsEmpty: false
};
constructor(props: IQuoteProposerProps) {
super(props);
if (this.props.quoteRequest.proposer) {
this.state.companyName = this.props.quoteRequest.proposer.companyName
? this.props.quoteRequest.proposer.companyName
: "";
this.state.title = this.props.quoteRequest.proposer.salutation
? this.props.quoteRequest.proposer.salutation
: "";
this.state.firstName = this.props.quoteRequest.proposer.firstName
? this.props.quoteRequest.proposer.firstName
: "";
this.state.surname = this.props.quoteRequest.proposer.lastName
? this.props.quoteRequest.proposer.lastName
: "";
this.state.contactEmail = this.props.quoteRequest.proposer.contactEmail
? this.props.quoteRequest.proposer.contactEmail
: "";
this.state.contactPhone = this.props.quoteRequest.proposer.contactPhone
? this.props.quoteRequest.proposer.contactPhone
: "";
}
}
handleCreateQuote = (event: any) => {
event.preventDefault();
this.checkMandatoryFieldsEmpty();
if (this.isValidForm()) {
let quoteRequest = new QuoteRequest();
quoteRequest.startDate = this.props.quoteStartDate;
quoteRequest.proposer = new Proposer();
quoteRequest.proposer.companyName = !this.state.companyName
? null
: this.state.companyName;
quoteRequest.proposer.firstName = this.state.firstName;
quoteRequest.proposer.lastName = this.state.surname;
quoteRequest.proposer.salutation = this.state.title;
quoteRequest.proposer.contactEmail = !this.state.contactEmail
? null
: this.state.contactEmail;
quoteRequest.proposer.contactPhone = !this.state.contactPhone
? null
: this.state.contactPhone;
if (
this.props.quoteRequest.quoteDetails &&
this.props.quoteRequest.quoteDetails.quoteId
) {
this.props.updateQuote(
this.props.quoteRequest.quoteDetails.quoteId,
quoteRequest
);
} else {
this.props.createQuote(quoteRequest);
}
} else {
this.setState({ isValidForm: false });
}
};
getSnapshotBeforeUpdate(prevProps: IQuoteProposerProps, prevState: any) {
return null;
}
componentDidUpdate(
prevProps: IQuoteProposerProps,
prevState: any,
snapshot: any
) {
//When creating
if (
prevProps.quoteRequest.isQuoteCreated !==
this.props.quoteRequest.isQuoteCreated
) {
if (this.props.quoteRequest.isQuoteCreated) {
this.props.clearErrors(this.props.quoteRequest);
if (this.props.quoteType === QuoteType.Simple) {
this.props.history.push("/quote/simple-risk");
} else {
this.props.history.push("/quote/complex-risk");
}
}
}
//When updating
if (
prevProps.quoteRequest.isQuoteUpdated !==
this.props.quoteRequest.isQuoteUpdated
) {
if (this.props.quoteRequest.isQuoteUpdated) {
this.props.clearErrors(this.props.quoteRequest);
this.props.clearErrors(this.props.quoteRequest);
if (this.props.quoteType === QuoteType.Simple) {
this.props.history.push("/quote/simple-risk");
} else {
this.props.history.push("/quote/complex-risk");
}
}
}
}
isValidForm = (): boolean => {
let isValid = true;
if (validation.isEmpty(this.state.firstName)) {
this.setState({ showFirstNameEmptyError: true });
isValid = false;
} else {
this.setState({ showFirstNameEmptyError: false });
}
if (validation.isEmpty(this.state.surname)) {
this.setState({ showSurNameEmptyError: true });
isValid = false;
} else {
this.setState({ showSurNameEmptyError: false });
}
if (validation.isEmpty(this.state.title)) {
this.setState({ isTitleSelected: "false" });
isValid = false;
} else {
this.setState({ isTitleSelected: "true" });
}
if (
!validation.isEmpty(this.state.contactEmail) &&
!validation.isEmail(this.state.contactEmail)
) {
isValid = false;
this.setState({ showInvalidEmailError: true });
} else {
this.setState({ showInvalidEmailError: false });
}
if (
!validation.isEmpty(this.state.contactPhone) &&
!validation.isPhone(this.state.contactPhone)
) {
isValid = false;
this.setState({ showInvalidPhoneError: true });
} else {
this.setState({ showInvalidPhoneError: false });
}
return isValid;
};
checkMandatoryFieldsEmpty = () => {
if (
validation.isEmpty(this.state.firstName) ||
validation.isEmpty(this.state.surname) ||
this.state.isTitleSelected === "false"
) {
this.setState({ areMandatoryFieldsEmpty: true });
} else {
this.setState({ areMandatoryFieldsEmpty: false });
}
};
handleMandatoryFieldsCheck = (event: any) => {
this.checkMandatoryFieldsEmpty();
};
render() {
return (
<Container fluid>
<WizardStepper activeStep={3} />
<Container className="padded abg___main_content_wrapper">
<Header as="h1" className="page-title">
About the Proposer
</Header>
<p>Please tell us about the proposer.</p>
<div className="ui hidden divider" />
<Grid stackable doubling>
<Grid.Row>
<Grid.Column mobile={16} tablet={9} computer={8}>
<Form
onSubmit={this.handleCreateQuote}
autoComplete="off"
noValidate
>
<Container>
<Form.Field>
<label>Company name</label>
<Form.Input
type="text"
maxLength={30}
name="company-name"
value={this.state.companyName}
placeholder="Company Name"
onChange={(event: any) => {
this.setState({
companyName: event.target.value
});
}}
/>
</Form.Field>
<Form.Field>
<TitleSelector
onClick={async (data: any) => {
await this.setState({
title: data
});
this.setState({
isTitleSelected: !validation.isEmpty(
this.state.title
)
? "true"
: "false"
});
}}
showTitleNotSelectedError={
this.state.isTitleSelected === "false"
}
titles={["Mr", "Mrs", "Miss", "Ms"]}
selectedTitle={this.state.title}
cssClasses="abg___button-options"
/>
</Form.Field>
<Form.Field>
<label>First name</label>
<Form.Input
type="text"
name="first-name"
value={this.state.firstName}
maxLength={30}
error={this.state.showFirstNameEmptyError}
placeholder="First Name"
onChange={async (event: any) => {
await this.setState({
firstName: event.target.value
});
if (!validation.isEmpty(this.state.firstName)) {
this.setState({ showFirstNameEmptyError: false });
}
}}
/>
</Form.Field>
<Form.Field>
<label>Surname</label>
<Form.Input
type="text"
name="surname"
maxLength={30}
value={this.state.surname}
error={this.state.showSurNameEmptyError}
placeholder="Surname"
onChange={async (event: any) => {
await this.setState({ surname: event.target.value });
if (!validation.isEmpty(this.state.surname)) {
this.setState({ showSurNameEmptyError: false });
}
}}
/>
</Form.Field>
<Form.Field>
<label>Contact email</label>
<Form.Input
type="email"
name="email"
maxLength={30}
value={this.state.contactEmail}
error={this.state.showInvalidEmailError}
placeholder="Contact email"
onChange={(event: any) => {
this.setState({ contactEmail: event.target.value });
}}
onBlur={(event: any) => {
this.setState({
showInvalidEmailError: !validation.isEmail(
this.state.contactEmail
)
});
}}
/>
<ErrorMessage
show={this.state.showInvalidEmailError}
message="Invalid email"
/>
</Form.Field>
<Form.Field>
<label>Contact phone</label>
<Form.Input
type="text"
name="tel"
maxLength={30}
value={this.state.contactPhone}
error={this.state.showInvalidPhoneError}
placeholder="Contact phone"
onChange={(event: any) => {
this.setState({ contactPhone: event.target.value });
}}
onBlur={(event: any) => {
this.setState({
showInvalidPhoneError: !validation.isPhone(
this.state.contactPhone
)
});
}}
/>
<ErrorMessage
show={this.state.showInvalidPhoneError}
message="Invalid phone"
/>
</Form.Field>
{this.props.quoteRequest.quoteCreateError ||
this.props.quoteRequest.quoteUpdateError ? (
<Message negative>Server Error, please try again</Message>
) : null}
{this.state.areMandatoryFieldsEmpty ? (
<Message negative>
Please complete the highlighted mandatory fields
</Message>
) : null}
</Container>
<div className="ui hidden divider" />
<Container>
<Button
size="large"
type="submit"
floated="right"
positive
loading={
this.props.quoteRequest.isCreatingQuote ||
this.props.quoteRequest.isUpdatingQuote
}
>
Next
</Button>
</Container>
</Form>
</Grid.Column>
</Grid.Row>
</Grid>
</Container>
</Container>
);
}
}
function mapStateToProps(state: IStoreState) {
return {
quoteStartDate: state.quoteStartDate,
quoteType: state.quoteType,
quoteRequest: state.quoteRequest
};
}
const mapDispatchToProps = (dispatch: any) => {
return {
createQuote: (quoteRequest: QuoteRequest) => {
return dispatch(quoteActions.createQuote(quoteRequest));
},
updateQuote: (quoteId: number, quoteRequest: QuoteRequest) => {
return dispatch(quoteActions.updateQuote(quoteId, quoteRequest));
},
resetQuoteUpdate: (quoteRequest: QuoteRequest) => {
return dispatch(quoteActions.resetQuoteUpdate(quoteRequest));
},
clearErrors: (quoteRequest: QuoteRequest) => {
return dispatch(quoteActions.clearErrors(quoteRequest));
}
};
};
export const QuoteProposer = connect(
mapStateToProps,
mapDispatchToProps
)(_QuoteProposer);
Layout page routes:
render() {
return (
<div id="page-container">
<div id="content-wrap" className="clearfix">
<PageHeaderBar />
<Switch>
<Route
exact
path="/login"
component={Login}
authenticatedRedirect="/quote/getting-started"
/>
<PrivateRoute exact path="/" component={GettingStarted} />
<PrivateRoute
exact
path="/quote/getting-started"
component={GettingStarted}
/>
<PrivateWizardRoute
exact
path="/quote/start-date"
component={StartDate}
wizard={this.props.wizard}
/>
<PrivateWizardRoute
exact
path="/quote/quote-proposer"
component={QuoteProposer}
wizard={this.props.wizard}
/>
<PrivateWizardRoute
exact
path="/quote/simple-risk"
component={SimpleRisk}
wizard={this.props.wizard}
/>
<PrivateWizardRoute
exact
path="/quote/complex-risk"
component={ComplexRisk}
wizard={this.props.wizard}
/>
<PrivateRoute exact path="/quote/summary" component={Summary} />
</Switch>
<PageFooter />
</div>
</div>
);
}
}
PrivateWizardRoute:
import React from "react";
import { Redirect, Route, RouteProps } from "react-router-dom";
import { Wizard } from "../models/wizard";
import { WizardStage } from "../models/enums";
interface IPrivateWizardRouteProps {
wizard: Wizard;
}
export class PrivateWizardRoute extends React.Component<
IPrivateWizardRouteProps & RouteProps
> {
renderRoute = () => {
let isAuthenticated = localStorage.getItem("authResponse") ? true : false;
if (isAuthenticated) {
if (this.props.wizard.wizardStage === WizardStage.InProgress) {
const { path, exact, component } = this.props;
return <Route path={path} exact={exact} component={component} />;
} else {
return (
<Redirect
to={{
pathname: "/quote/getting-started"
}}
/>
);
}
} else {
return <Redirect to={{ pathname: "/login" }} />;
}
};
render() {
return this.renderRoute();
}
}
export default PrivateWizardRoute;
I was missing event.preventDefault StartDate button click.
Related
I have passed my user ID into my 'OrderMessages' component but in my function says undefined. When my user submits a messages using the form in the handleFormSubmit function I need the UserID and the datetime of the message. I have managed to get the date and time but when trying to console log to get the UserID I keep getting an error. I have tried this.props.... and this.state but both say undefined, can you please help. In my constructor I have tested using const UserId = props.location.state.UserID; and in debug I can see this has correctly got the UserID so im not sure how to get it into my hadleFormSubmit function.
import React from "react";
import Moment from "moment";
import { Form, Button } from "react-bootstrap";
class OrderMessages extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
isLoading: false,
checkboxes: [],
selectedId: [],
formLableSelected: "",
formSelectedSubject: "",
formSelectedSubjectId: "",
formNewSubject: "",
formChainID: "",
formMessageBody: "",
userId: '',
};
const UserId = props.location.state.UserID;
}
componentDidMount() {
this.setState({ isLoading: true });
const proxyurl = "https://cors-anywhere.herokuapp.com/";
const url =
"myURL" +
this.props.location.state.orderNumber;
fetch(proxyurl + url)
.then((res) => res.json())
.then((data) => this.setState({ data: data, isLoading: false }));
}
handleClick = (id) => {
if (this.state.selectedId !== id) {
this.setState({ selectedId: id });
} else {
this.setState({ selectedId: null });
}
};
setformSubjectID(messageSubject) {
if (messageSubject.subject === this.state.formSelectedSubject) {
this.setState({ formSelectedSubjectId: messageSubject.messageSubjectId });
}
}
handleChangeSubject = (event) => {
this.setState({ formSelectedSubject: event.target.value });
this.state.data.message_Subjects.map((ms) => this.setformSubjectID(ms));
};
handleFormSubmit(e) {
e.preventDefault();
// get current time
let submit_time = Moment().format("ddd DD MMM YYYY HH:mm:ss");
console.log("messageDatetime", submit_time);
// get user id THIS IS WHAT DOESN’T WORK
console.log("messageSentFrom", this.state.userId);
console.log("messageSentFrom", this.props.location.state.UserID);
}
render() {
const { data, isLoading } = this.state;
if (isLoading) {
return <p>Loading ...</p>;
}
if (data.length === 0) {
return <p> no data found</p>;
}
console.log("mess: ", data);
return (
<div>
<div className="sendMessageContent">
<Form className="sendMessageForm" onSubmit={this.handleFormSubmit}>
<Form.Group className="formRadio">
<Form.Check
className="formRadiob"
type="radio"
label="New chat"
value="new"
name="neworexisitng"
id="New Message"
onChange={this.onFormMessageChanged}
defaultChecked
/>
<Form.Check
className="formRadiob"
type="radio"
label="Reply to exisiting chat"
value="reply"
name="neworexisitng"
id="exisiting Message"
onChange={this.onFormMessageChanged}
/>
</Form.Group>
{this.returnCorrectFormFields(data)}
<Form.Group>
<Form.Label>Message Body</Form.Label>
<Form.Control as="textarea" rows={3} />
</Form.Group>
<Button variant="primary" type="submit">
Send Message
</Button>
</Form>
</div>
</div>
);
}
returnCorrectFormFields(data) {
if (this.state.formLableSelected === "new") {
return this.newMessageSubject(data);
} else {
return this.choseMessageSubject(data);
}
}
choseMessageSubject(data) {
return (
<Form.Group>
<Form.Label>Select the message subject</Form.Label>
<Form.Control as="select" onChange={this.handleChangeSubject}>
<option value="0">Choose...</option>
{data.message_Subjects.map((ms) => (
<option value={ms.subject}>{ms.subject}</option>
))}
</Form.Control>
</Form.Group>
);
}
newMessageSubject(data) {
return (
<Form.Group>
<Form.Label>Enter Message Subject</Form.Label>
<Form.Control type="text" placeholder="Enter message subject" />
</Form.Group>
);
}
onFormMessageChanged = (event) => {
this.setState({
formLableSelected: event.target.value,
});
};
getAllMessageInChain(messageChain) {
return (
<div className="messageHistory">
<div className="messageHistoryHeader">
<div className="innerMS-history-body">Message</div>
<div className="innerMS">Date and Time</div>
<div className="innerMS">Message sent by</div>
</div>
{messageChain.map((ms) => (
<div className="messageHistoryBody">
<div className="innerMS-history-body">{ms.messageBody}</div>
<div className="innerMS">
{Moment(ms.dateTime).format("ddd DD MMM YYYY hh:mm:ss")}
</div>
<div className="innerMS">{ms.sentFromId}</div>
</div>
))}
</div>
);
}
getLatestMessageDateTime(messageChain) {
const lastmessage = messageChain.length - 1;
Moment.locale("en");
var dt = messageChain[lastmessage].dateTime;
return Moment(dt).format("ddd DD MMM YYYY hh:mm:ss");
}
}
export default OrderMessages;
The scope of this isn't the component in the function you're using.
Either change handleFormSubmit to this to bind this automatically.
handleFormSubmit = (e) => {
// .. your code
}
or bind this manually in the constructor
constructor() {
// ..other code
this.handleFormSubmit = this.handleFormSubmit.bind(this)
}
I have two pages and two components LibraryPageFilters.tsx (url: /courses) and UserVideoCreatePage.tsx (url: /ugc/courses/${course.id}).
In component LibraryPageFilters.tsx
useEffect(() => {
console.log(course.id)
if (course.id) {
console.log(544)
dispatch(push(`/ugc/courses/${course.id}`));
}
}, [course]);
i have a check that if course.id present in the store, then we make a redirect.
In component UserVideoCreatePage.tsx
useEffect(() => {
return () => {
console.log(333344444)
dispatch(courseDelete());
};
}, []);
i am deleting a course from the store when componentUnmount.
why does unmount happen after a redirect? as a result, I am redirected back. Because the course is not removed from the store at the moment of unmount, and the check (if (course.id)) shows that the course is in the store and a redirect occurs back (dispatch(push(/ugc/courses/${course.id})))
UserVideoCreatePage.tsx
import React, { useEffect, useRef, useState } from 'react';
import { shallowEqual, useDispatch, useSelector } from 'react-redux';
import { useParams } from 'react-router';
import { Link } from 'react-router-dom';
import { Container } from 'Core/components/Container/Container';
import { Svg } from 'Core/components/Svg';
import { Button } from 'Core/Molecules/Button';
import { Select } from 'Core/Molecules/Select';
import {
agreementCourse, categoriesSelector,
courseDelete,
courseEditorCourseSelector,
courseUpdateApi, getCategories,
getCourse,
updateCourseApi,
} from 'Learnings/store/courseEdit';
import { CourseComments } from 'Learnings/screens/CoursePlayPage/CourseBottom/CourseComments/CourseComments';
import { AddItem } from './AddItem';
import s from 'Admin/Pages/Course/Description/index.scss';
import './UserVideoCreatePage.scss';
export const UserVideoCreatePage: React.FC = () => {
const dispatch = useDispatch();
const { id: idCourse } = useParams();
const course = useSelector(courseEditorCourseSelector, shallowEqual);
const categories = useSelector(categoriesSelector, shallowEqual);
const [value, valueSet] = useState({ name: '', description: '', categories: [], lectures: [], materials: [] });
const [tab, tabSet] = useState('program');
const inputFileRef = useRef<HTMLInputElement>(null);
const img = course.gallery_items && course.gallery_items[0];
console.log(categories);
const handleBtnClick = () => {
if (inputFileRef && inputFileRef.current) {
inputFileRef.current.click();
}
};
useEffect(() => {
dispatch(getCourse(idCourse));
dispatch(getCategories());
}, [idCourse]);
useEffect(() => {
valueSet({
name: course.name,
description: course.description,
categories: course.categories && course.categories[0] && course.categories[0].id,
lectures: course.lectures,
materials: course.materials,
});
}, [course]);
useEffect(() => {
return () => {
console.log(333344444)
dispatch(courseDelete());
};
}, []);
return (
<Container className="createCourse">
<Link to="/" className="gallery__back">
<Svg name="arrow_back" width={26} height={20} className="gallery__svg"/>
<span>Назад</span>
</Link>
<div className="createCourse__twoColumn">
<div className="createCourse__twoColumn-left">
<div className="inputBlock">
<label className="inputBlock__label" htmlFor="video">
Название видео-курса
</label>
<input
id="video"
type="text"
placeholder="Введите название вашего видео"
className="inputBlock__input"
value={value.name || ''}
onChange={e =>
valueSet({
...value,
name: e.target.value,
})
}
onBlur={e => {
if (e.target.value && course.name !== e.target.value) {
dispatch(updateCourseApi(idCourse, { name: e.target.value }));
}
}}
/>
</div>
<div className="inputBlock">
<label className="inputBlock__label" htmlFor="opisanie">
Описание видео-курса
</label>
<textarea
id="opisanie"
placeholder="Введите краткое описание вашего видео"
className="inputBlock__input"
value={value.description || ''}
onChange={e =>
valueSet({
...value,
description: e.target.value,
})
}
onBlur={e => {
if (e.target.value && course.description !== e.target.value) {
dispatch(updateCourseApi(idCourse, { description: e.target.value }));
}
}}
/>
</div>
<Select
title="Категории видео-курса"
placeholder="Категории видео-курса"
value={value.categories}
options={categories.map(category => ({ value: category.id, label: category.name }))}
onChange={val => {
valueSet({
...value,
categories: val,
});
dispatch(
updateCourseApi(idCourse, {
category_ids: val,
courses_curators: {
'': {
user_id: val,
},
},
}),
);
}}
search
/>
</div>
<div className="createCourse__twoColumn-right">
<div className="loadVideo">
<div className="loadVideo__field">
<div className="loadVideo__field--block">
{!img && (
<>
<Svg className="loadVideo__field--block-icon" name="icn-load" width={104} height={69}/>
<p className="loadVideo__field--block-text">Загрузите обложку к видео</p>
</>
)}
{img && <img src={img && img.image_url} alt=""/>}
</div>
</div>
<div className="loadVideo__under">
<div className="loadVideo__under--left">
<div className="loadVideo__under--text">
<span className="loadVideo__under--text-grey">*Рекомендуемый формат</span>
<span className="loadVideo__under--text-bold"> 356х100</span>
</div>
<div className="loadVideo__under--text">
<span className="loadVideo__under--text-grey">*Вес не должен превышать</span>
<span className="loadVideo__under--text-bold"> 10 Мб</span>
</div>
</div>
<div className="loadVideo__under--right">
<input
onChange={val => {
if (val.target.files[0]) {
if (img) {
dispatch(
updateCourseApi(idCourse, {
gallery_items: {
'': {
image: val.target.files[0],
id: img.id,
},
},
}),
);
} else {
dispatch(
updateCourseApi(idCourse, {
gallery_items: {
'': {
image: val.target.files[0],
},
},
}),
);
}
}
}}
type="file"
ref={inputFileRef}
className="Library__btn"
/>
<Button
onClick={() => {
handleBtnClick();
}}
>
Библиотека обложек
</Button>
</div>
</div>
</div>
</div>
</div>
<div className={`block-switcher block-switcher--courseCreate`}>
<div
className={`block-switcher__item ${tab === 'program' && 'block-switcher__item_active'}`}
onClick={() => tabSet('program')}
>
Программы
</div>
<div
className={`block-switcher__item ${tab === 'comments' && 'block-switcher__item_active'}`}
onClick={() => tabSet('comments')}
>
Комментарии эксперта
</div>
</div>
{tab === 'program' && (
<>
<AddItem
accept="video/mp4,video/x-m4v,video/*"
fieldName="name"
addType="lecture_type"
title="Видео-курсы"
addBtn="Добавить видео"
type="lectures"
file="video"
lecturesArg={course.lectures}
value={value}
onChangeInput={lecturesNew => {
valueSet({
...value,
lectures: lecturesNew,
});
}}
onVideoUpdate={(params: any) => {
dispatch(updateCourseApi(idCourse, params));
}}
posMove={(lectures: any) => {
dispatch(courseUpdateApi({ id: idCourse, lectures: lectures }, true));
}}
/>
<AddItem
accept=""
fieldName="title"
addType="material_type"
title="Материалы к видео-курсам"
addBtn="Добавить файл"
type="materials"
file="document"
lecturesArg={course.materials}
value={value}
onChangeInput={lecturesNew => {
valueSet({
...value,
materials: lecturesNew,
});
}}
onVideoUpdate={(params: any) => {
dispatch(updateCourseApi(idCourse, params));
}}
posMove={(lectures: any) => {
dispatch(courseUpdateApi({ id: idCourse, materials: lectures }, true));
}}
/>
</>
)}
{tab === 'comments' && <CourseComments title="Обсуждение"/>}
<Button
className={`${s.button} agreement__btn`}
size="big"
onClick={() =>
dispatch(
agreementCourse(idCourse, {
visibility_all_users: true,
}),
)
}
>
Отправить на согласование
</Button>
</Container>
);
};
LibraryPageFilters.tsx
import React, { useEffect, useState } from 'react';
import { useDispatch, useSelector, shallowEqual } from 'react-redux';
import { push } from 'connected-react-router';
import { getSettingsGlobalSelector } from 'Core/store/settings';
import { Svg } from 'Core/components/Svg';
import { NavBar } from 'Core/Organisms/NavBar';
import { Button } from 'Core/Molecules/Button';
import { CategoriesFilter } from 'Core/Organisms/Filters/components/CategoriesFilter';
import { courseDelete, courseEditorCourseSelector, createNewCourse } from 'Learnings/store/courseEdit';
import { FILTERS, LINKS } from '../../libraryPageConstants';
import { setLibraryPageQuery } from '../../actions/libraryPageActions';
import { getLibraryPageQuerySelector } from '../../libraryPageSelectors';
import s from './index.scss';
import { languageTranslateSelector } from 'Core/store/language';
import { LanguageType } from 'Core/models/LanguageSchema';
import { Status, Tabs } from 'Core/components/Tabs/Tabs';
const statuses: Array<Status> = [
{
key: 'Filter/all',
link: '/courses' || '/courses',
type: 'all' || '',
},
{
key: 'Filter/online',
link: '/courses/online',
type: 'online',
},
{
key: 'Filter/offline',
link: '/courses/offline',
type: 'offline',
},
{
key: 'Filter/complete',
link: '/courses/complete',
type: 'complete',
},
];
export const LibraryPageFilters = () => {
const dispatch = useDispatch();
const [searchTerm, setSearchTerm] = useState('');
const [isBtnDisabled, setIsBtnDisabled] = useState(false);
const course = useSelector(courseEditorCourseSelector, shallowEqual);
const global = useSelector(getSettingsGlobalSelector);
const query = useSelector(getLibraryPageQuerySelector, shallowEqual);
const courseCreateButtonText = useSelector(
languageTranslateSelector('CoursePage/courseCreateButton'),
) as LanguageType;
const { category_id: categoryID } = query;
console.log(course)
useEffect(() => {
console.log(course.id)
if (course.id) {
console.log(544)
dispatch(push(`/ugc/courses/${course.id}`));
}
}, [course]);
useEffect(() => {
return () => {
setIsBtnDisabled(false);
dispatch(courseDelete());
};
}, []);
const onFilter = (values: any) => {
return false;
};
const handleActiveCategory = (id: number) => {
const categoryParam = {
...query,
offset: 0,
category_id: id,
};
if (id === categoryID) {
delete categoryParam.category_id;
}
dispatch(setLibraryPageQuery(categoryParam));
};
const handleSearch = () => {
dispatch(setLibraryPageQuery({ query: searchTerm }));
};
return (
<React.Fragment>
<div className={s.filters}>
{global.coursesPage?.filters.length ? (
<NavBar
className={s.navBar}
links={global.coursesPage.filtersLinks.map(linkType => LINKS[linkType])}
filters={global.coursesPage.filters.map(filterType => FILTERS[filterType])}
onFilter={onFilter}
postfix={
global.coursesPage.courseCreateButton && global.coursesPage.courseCreateButton.enable ? (
<Button
className="coursePageCreateButton"
onClick={() => {
dispatch(createNewCourse());
setIsBtnDisabled(true);
}}
disabled={isBtnDisabled}
>
{courseCreateButtonText['CoursePage/courseCreateButton']}
</Button>
) : null
}
/>
) : (
<div className="track-page__header" data-tut="track-header">
<Tabs statuses={statuses} />
<div className={s.filtersSearch}>
<Svg className={s.filtersSearchIcon} name="search_alternative" width={18} height={18} />
<input
type="text"
placeholder="Поиск"
className={s.filtersSearchInput}
value={searchTerm}
onChange={event => setSearchTerm(event.target.value)}
/>
<button type="button" className={s.filtersButton} onClick={handleSearch}>
Найти
</button>
</div>
</div>
)}
</div>
<CategoriesFilter onChange={handleActiveCategory} selectedID={categoryID} />
</React.Fragment>
);
};
Although react suggests to use Functional Component, try Class Component, I faced similar issues, this was resolved easily in Class Component :
componentDidMount();
componentDidUpdate(prevProps, prevState, snapshot);
These two will solve your problem. Ask me if anything you need.
I'm trying to make a multi-step form using React.js and material UI. for validation purpose I am using Joi-Browser. But I am getting error from Joi while validation, stating that error: ValidationError: "value" must be an object
I am very new to React.js Please guide me what I am doing wrong here.
here what I have tried so far.
class ServiceRequestForm extends Component {
state = {
step: 1,
service_category: [],
user : [
{
full_name: '',
address_one: '',
}
],
hasError: false
}
schema = Joi.object().keys({
full_name: Joi.string().alphanum().min(3).max(100).required(),
address_one: Joi.string().required(),
});
validate = () => {
const result = Joi.validate(this.state.user, this.schema)
console.log(result)
}
// Proceed to next step
nextStep = () => {
const { step } = this.state;
this.setState({
step: step + 1
});
}
// Proceed to prev step
prevStep = () => {
const { step } = this.state;
this.setState({
step: step - 1
});
}
// handle select
handleChange = (event)=> {
this.setState(oldValues => ({
...oldValues,
[event.target.name]: event.target.value,
}));
}
// handle input
handleChangeInput = name => event => {
this.setState({ [name]: event.target.value });
};
handleSubmit = ()=>{
this.validate();
}
render() {
const { step } = this.state;
const { service_category } = this.state;
const { full_name, address_one } = this.state.user;
const values = { service_category, full_name, address_one };
switch (step) {
case 1:
return (
<CategoryForm
nextStep={this.nextStep}
handleChange={this.handleChange}
values={values}
/>
);
case 2:
return (
<AddressForm
prevStep={this.prevStep}
handleChangeInput={this.handleChangeInput}
handleSubmit={this.handleSubmit}
values={values}
/>
);
case 3:
return (
<ThankYouPage
/>
);
}
}
}
export default ServiceRequestForm;
// Category form
export default class CategoryForm extends Component {
continue = e => {
e.preventDefault();
this.setState({ hasError: false });
if (!this.props.values.service_category) {
console.log(this.props.hasError);
this.setState({ hasError: true });
}
else {
this.props.nextStep();
}
}
render() {
const { handleChange, values, classes, nextStep, hasError } = this.props;
return (
<div>
<h4>Select service you want</h4>
<form>
<FormControl error={hasError}>
<Select
value={values.service_category}
onChange={handleChange}
inputProps={{
name: 'service_category'
}}
>
<MenuItem value="">
<em>Select Category</em>
</MenuItem>
<MenuItem value={10}>House Maid</MenuItem>
<MenuItem value={20}>Electricians</MenuItem>
<MenuItem value={30}>Plumber</MenuItem>
</Select>
<FormHelperText>Please select service category</FormHelperText>
{hasError && <FormHelperText>This is required!</FormHelperText>}
</FormControl>
</form>
<br />
<Button variant="contained" color="primary" onClick={this.continue}>Next</Button>
</div>
)
}
}
// address form
export default class AddressForm extends Component {
back = e => {
e.preventDefault();
this.props.prevStep();
}
render() {
const { handleChangeInput, values, classes, handleSubmit, prevStep, hasError, full_name } = this.props;
return (
<div>
<h1>Address</h1>
<TextField
label="Full Name"
//className={classes.textField}
value={values.full_name}
onChange={handleChangeInput('full_name')}
margin="normal"
variant="outlined"
/>
<TextField
label="Address Line 1"
//className={classes.textField}
value={values.address_one}
onChange={handleChangeInput('address_one')}
margin="normal"
variant="outlined"
/>
<Button variant="contained" color="primary" onClick={handleSubmit}>Submit</Button>
<Button variant="contained" color="primary" onClick={prevStep}>Back</Button>
</div>
);
}
}
Schema can be just an object.
Try using like below.
{
full_name: Joi.string().alphanum().min(3).max(100).required(),
address_one: Joi.string().required(),
}
No need to specify
Joi.object().keys(
I'm currently working on my React with REdux application for ASP.NET Core using the Kendo React UI from Telerik. I'm using their grid widget, which, seems to be working ok until you try to edit one of the rows. When you try to edit a row you get the following error:
Warning: Failed prop type: Invalid prop value of type String
supplied to DatePicker, expected instance of Date.
in DatePicker
I searched for an answer to this problem and found a couple of possibilities.
The first was to set the default value defaultValue to null which didn't work.
The second answer suggested setting the format to null i.e. format={null} but that didn't work either.
Here is my code.
ContactContainer
import * as React from 'react';
import { GridColumn, Grid } from '#progress/kendo-react-grid';
import { withState } from './ContactComponent';
import { CommandCell } from './CommandCell';
const ContactsGrid = withState(Grid);
class ContactContainer extends React.Component {
render() {
return (
<div>
<ContactsGrid
sortlable
pageable
pageSize={10}
editField="inEdit">
<GridColumn field="Id" title="Id" editable={false} width={100} />
<GridColumn field="FirstName" title="First Name" />
<GridColumn field="LastName" title="Last Name" />
<GridColumn field="Email" title="Email" />
<GridColumn field="CreatedUser" title="Created By" />
<GridColumn field="CreatedDate" title="Created Date" editor="date" format="{0:d}" defaultValue={null} />
<GridColumn
groupable={false}
sortable={false}
filterable={false}
resizable={false}
field="_command"
title=" "
width="180px"
cell={CommandCell}
/>
</ContactsGrid>
</div>
);
}
}
export default ContactContainer;
ContactComponent
import React from 'react';
import { toDataSourceRequestString, translateDataSourceResultGroups } from '#progress/kendo-data-query';
import { Grid, GridToolbar } from '#progress/kendo-react-grid';
import AddIcon from '#material-ui/icons/Add';
import Fab from '#material-ui/core/Fab';
export function withState() {
return class StatefullGrid extends React.Component {
constructor(props) {
super(props);
if (props.pageable === false) {
this.state = {};
} else {
this.state = {
dataState: {
skip: 0,
take: 20
}
};
}
}
render() {
return (
<Grid
editField="_command"
{...this.props}
{...this.state.dataState}
total={this.state.total}
data={this.state.result}
onItemChange={this.itemChange}
onDataStateChange={this.onDataStateChange}>
<GridToolbar>
<Fab size="small" color="secondary" aria-label="Add" onClick={this.addContact}>
<AddIcon />
</Fab>
</GridToolbar>
{this.props.children}
</Grid>
);
}
componentDidMount() {
this.fetchData(this.state.dataState);
}
addContact = () => {
const data = this.state.result;
data.unshift({ "_command": true, inEdit: true });
this.setState({
result: data
})
};
enterEdit = (item) => {
this.itemInEdit = Object.assign(item, {});
item.inEdit = true;
this.forceUpdate();
};
cancelEdit = (item) => {
let data = this.state.result
let mappedData = data.map(record => {
if (record.Id === this.itemInEdit.Id) {
record = this.itemInEdit;
record.inEdit = false
}
return record
})
this.setState({
result: mappedData
})
};
handleDataStateChange = (changeEvent) => {
this.setState({ dataState: changeEvent.Data });
this.fetchData(changeEvent.data);
};
onDataStateChange = (changeEvent) => {
this.setState({ dataState: changeEvent.Data });
this.fetchData(changeEvent.Data);
};
serialize = (obj) => {
var str = [];
for (var p in obj)
if (obj.hasOwnProperty(p)) {
str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
}
return str.join("&");
};
itemChange = (event) => {
switch (event.value) {
case "edit":
this.enterEdit(event.dataItem)
break;
case "delete":
this.deleteItem(event.dataItem)
break;
case "update":
if (event.dataItem.Id) {
this.updateItem(event.dataItem)
} else {
this.addContact(event.dataItem)
}
break;
case "cancel":
this.cancelEdit(event.dataItem)
break;
default:
const data = this.state.result.slice();
const index = data.findIndex(d => d.id === event.dataItem.id);
data[index] = { ...data[index], [event.field]: event.value };
this.setState({
result: data
});
}
};
fetchData(dataState) {
const queryStr = `${toDataSourceRequestString(dataState)}`;
const hasGroups = dataState.group && dataState.group.length;
const base_url = 'api/Contact/GetContacts';
const init = { method: 'GET', accept: 'application/json', headers: {} };
fetch(`${base_url}?${queryStr}`, init)
.then(response => response.json())
.then(({ Data, total }) => {
this.setState({
result: hasGroups ? translateDataSourceResultGroups(Data) : Data,
total,
dataState
});
});
};
}
}
CommandCell
import React from 'react';
import { GridCell } from '#progress/kendo-react-grid';
import IconButton from '#material-ui/core/IconButton';
import Fab from '#material-ui/core/Fab';
import EditIcon from '#material-ui/icons/Edit';
import DeleteIcon from '#material-ui/icons/Delete';
import DoneIcon from '#material-ui/icons/Done';
import CloseIcon from '#material-ui/icons/Close';
export class CommandCell extends GridCell {
buttonClick = (e, command) => {
this.props.onChange({ dataItem: this.props.dataItem, e, field: this.props.field, value: command });
}
render() {
if (this.props.rowType !== "data") {
return null;
}
if (this.props.dataItem.inEdit) {
return (
<td>
<IconButton color="secondary" className="k-grid-save-command"
onClick={(e) => this.buttonClick(e, "update")}>
<DoneIcon />
</IconButton>
<IconButton color="inherit" className="k-grid-cancel-command"
onClick={(e) => this.buttonClick(e, "cancel")}>
<CloseIcon />
</IconButton>
</td>
);
}
return (
<td>
<Fab color="secondary" aria-label="Edit" className="k-grid-edit-command" onClick={(e) => this.buttonClick(e, "edit")}>
<EditIcon />
</Fab>
<Fab color="secondary" aria-label="Delete" className="k-grid-remove-command" onClick={(e) => window.confirm('Confirm deleting: ' + this.props.dataItem.Name) && this.buttonClick(e, "delete")}>
<DeleteIcon />
</Fab>
</td>
);
}
}
Can anyone help me with a solution to this problem or a workaround?
i think problem is here you have assigned defaultValue={null} which throw warning. try passing date in defaultValue
<GridColumn field="CreatedDate" title="Created Date" editor="date" format="{0:d}" defaultValue={new Date()} />
I'm using material-ui to list group of violations to the user to select one or multiple violations, then during the selection i extract from each violation it's id and update the state so as a result i'll have an array of ids to send it to backend
here is my code
import React from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import get from 'lodash/get';
// Material-UI
import MaterialTable, { MTableToolbar } from 'material-table';
import { withStyles } from '#material-ui/core/styles';
import Grid from '#material-ui/core/Grid';
import Paper from '#material-ui/core/Paper';
import Button from '#material-ui/core/Button';
import SaveIcon from '#material-ui/icons/Save';
import CancelIcon from '#material-ui/icons/Cancel';
// Forms
import Entity from '~/Components/Entity';
import { BaseFormComponent, Form, FormContainer, FormItem } from '~/Components/FormComponent';
import { LabelAndValue, LookupString } from '~/Components/FormComponent/Controls';
import {
isRequired,
minNumbers,
maxNumbers,
onlyNumbers,
noEnglish
} from '~/Services/Validators';
import Navigate from '~/Services/Navigate';
import Notifications from '~/Services/Notifications';
import Message from '~/Components/Message';
import Strings from '~/Services/Strings';
import styles from './styles';
#withStyles(styles)
class violationEditorScreen extends BaseFormComponent {
constructor(props) {
super(props);
this.initState({
error: false,
errorMsg: '',
requestId: null,
complaintId: null,
penalityTypeId: null,
violations: [],
inistitutionsData: [],
selectedViolationsId: [],
form: {
id: {
type: this.types.number,
value: 0,
},
districtId: {
type: this.types.number,
value: 1,
UIOnly: true
},
cityId: {
type: this.types.number,
value: 1,
UIOnly: true
},
institutionTypeId: {
type: this.types.number,
value: 2,
UIOnly: true
},
complaintTitle: {
type: this.types.string,
validators: [ isRequired(), noEnglish() ],
},
complaintDescription: {
type: this.types.string,
validators: [ isRequired(), noEnglish() ],
},
institutionId: {
type: this.types.number,
validators: [ isRequired() ],
},
}
});
}
componentDidMount() {
super.componentDidMount();
// const id = get(this, 'props.match.params.id', null);
// if (id) {
// this.addFormFields({
// });
// }
this.getInstitutionsList();
}
getInstitutionsList() {
const { form } = this.state;
this.getInstitutionsEntity.get({
cityId: form.cityId.value,
districtId: form.districtId.value,
institutionTypeId: form.institutionTypeId.value
});
}
// On Institution Change
onHandleInstitutionChange(institutionId) {
this.getRequestIdEntity.post({ institutionId });
}
getRequestIdEntityPosted(data) {
const requestId = data.requestId;
const complaintId = data.id;
this.setState({
requestId,
complaintId
}, () => {
this.getViolationsEntity.get({
complaintId
});
});
}
onViolationsEntityReceived(data) {
const violations = [];
if(data && data.length > 0) {
data.map(item => {
violations.push({ ...item });
});
this.setState({ violations });
}
this.setState({ violations });
}
onInstitutionEntityReceived(data) {
if(data && data.licensingInstitutionsModel && data.licensingInstitutionsModel.length > 0) {
const arr = [];
data.licensingInstitutionsModel.map(item => {
arr.push({
id: item.institutionId,
nameAr: item.fullName
});
});
this.setState({ inistitutionsData: arr });
}
}
onEntityPosted(data) {
const requestId = data.requestId;
Notifications.notify('success', Strings.complaintHasBeenSuccessfullyPublished);
this.getViolationsEntity.post({ requestId });
}
onSubmit() {
const id = get(this, 'props.match.params.id', null);
const { selectedViolationsId, requestId } = this.state;
if (this.isFormValid) {
if(selectedViolationsId.length === 0) {
this.setState({
error: true,
errorMsg: Strings.addAtLeastOneViolation
});
}else {
const payload = {
...this.formValues,
selectedViolationsId,
requestId,
id: id ? id : 0
};
this.entity.post(payload);
}
} else {
this.showFormErrors();
}
}
handleSelectedRows(rows) {
const selectedViolationsId = [];
const penalityTypeIds = [];
if(rows.length > 0) {
rows.map(row => {
selectedViolationsId.push(row.id);
penalityTypeIds.push(row.penaltyTypeId);
});
this.setState({ selectedViolationsId }, () => {
if(penalityTypeIds.length > 0) {
const validators= [
isRequired(),
minNumbers(1),
onlyNumbers()
];
const penalityTypeId = penalityTypeIds.sort((a, b) => {
if(a > b) return -1;
if(b > a) return 1;
})[0];
if(penalityTypeId === 1 || penalityTypeId === 2) {
validators.push(maxNumbers(30));
} else {
validators.push(maxNumbers(60));
}
this.addFormFields({
settlementPeriodInDays: {
type: this.types.number,
validators
},
});
this.setState({ penalityTypeId });
} else {
this.setState({ penalityTypeId: null });
}
});
} else {
this.setState({
selectedViolationsId: [],
penalityTypeId: null
});
}
}
get localization() {
return {
header: {
actions: Strings.listActionsLabel,
},
body: {
emptyDataSourceMessage: Strings.listEmptyLabel,
},
pagination: {
labelRowsPerPage: Strings.rowsPerPageLabel,
labelDisplayedRows: `{from}-{to} ${Strings.fromText} {count}`,
},
toolbar: {
nRowsSelected: `${Strings.nSelected} {0} ${Strings.selectedViolations}`
}
};
}
get options() {
return {
actionsColumnIndex: -1,
pageSize: 10,
selection: true,
filtering: true,
columnsButton: true,
maxBodyHeight: 600,
pageSizeOptions: [ 5, 10 ] ,
doubleHorizontalScroll: true,
rowStyle: row => {
if ( row.tableData.id % 2 ) {
return { backgroundColor: '#f2f2f2' };
}
}
};
}
get columns() {
return [
{ title: Strings.violationReferenceNumber, field: 'referenceNumber', cellStyle: { width: 120 } },
{ title: Strings.violationDescription, field: 'description' },
];
}
get components() {
const { classes } = this.props;
return {
Toolbar: props => (
<div className={classes.toolbar}>
<MTableToolbar {...props} />
</div>
),
};
}
render() {
const { form, error, errorMsg, inistitutionsData, violations, penalityTypeId } = this.state;
const { classes } = this.props;
const {
TextField,
LookupSelectField,
SelectAutocompleteField,
} = this;
return (
<React.Fragment>
<Entity
storeId={'Supervision-Complaints-Editor'}
entityRef={ref => { this.entity = ref; }}
onEntityReceived={data => this.onEntityReceived(data)}
onEntityPosted={data => this.onEntityPosted(data)}
onEntityPostedError={data => this.onEntityPostedError(data)}
render={store => (
<React.Fragment>
<If condition={error}>
<Grid item xs={12}>
<Message variant={'error'} text={errorMsg} />
</Grid>
</If>
<Form loading={store.loading}>
<Grid container spacing={24}>
<Grid item xs={9}>
<Paper elevation={1} className={classes.box1}>
<fieldset className={classes.fieldSet}>
<legend>{Strings.complaintDetails}</legend>
<FormContainer>
<FormItem lg={4}>
<LookupSelectField
name={'districtId'}
label={Strings.selectDistrictToSearch}
lookup={'Districts'}
onChange={() => this.getInstitutionsList()}
autocomplete
/>
</FormItem>
<FormItem lg={4}>
<LookupSelectField
name={'cityId'}
label={Strings.selectCityToSearch}
lookup={`City/LookupItemsByParentId/${form.districtId.value}`}
onChange={() => this.getInstitutionsList()}
autocomplete
/>
</FormItem>
<FormItem lg={4}>
<LookupSelectField
name={'institutionTypeId'}
label={Strings.selectInstitutionTypeToSearch}
lookup={'InstitutionTypes'}
onChange={() => this.getInstitutionsList()}
/>
</FormItem>
<FormItem lg={4}>
<div className={classnames(classes.placeholder, {})}>
<SelectAutocompleteField
name={'institutionId'}
label={Strings.assignmentInstitutionName}
emptyString={Strings.searchByNameAndLicense}
data={inistitutionsData}
onChange={field => this.onHandleInstitutionChange(field.value)}
/>
</div>
</FormItem>
<FormItem lg={4}>
<TextField
name={'complaintTitle'}
label={Strings.complaintTitle}
setBorder={false}
/>
</FormItem>
<If condition={penalityTypeId}>
<FormItem lg={4}>
<TextField
name={'settlementPeriodInDays'}
label={Strings.insertSettlementPeriodInDays}
setBorder={false}
/>
</FormItem>
</If>
<FormItem fullWidth>
<TextField
multiline
name={'complaintDescription'}
label={Strings.complaintDescription}
/>
</FormItem>
</FormContainer>
</fieldset>
</Paper>
<Paper elevation={1} className={classes.box}>
<fieldset className={classes.fieldSet}>
<legend>{Strings.complaintAttachments}</legend>
<FormContainer>
</FormContainer>
</fieldset>
{/* Attachment Here */}
</Paper>
<If condition={violations.length > 0}>
<Paper elevation={1} className={classes.box}>
<MaterialTable
title={Strings.complaintsAddViolationList}
data={violations}
options={this.options}
localization={this.localization}
columns={this.columns}
components={this.components}
onSelectionChange={rows => this.handleSelectedRows(rows)}
/>
</Paper>
</If>
</Grid>
<Grid item xs={3}>
{/* =========== Sidebar ============= */}
<If condition={penalityTypeId}>
<Paper elevation={1} className={classes.box}>
<FormItem fullWidth style={{ marginBottom: 10 }}>
<LabelAndValue
label={Strings.earnedPenality}
className={classes.deservedPenality}
value={(<LookupString
lookup={'PenaltyType'}
value={penalityTypeId}
/>)}
/>
</FormItem>
</Paper>
</If>
<Paper elevation={1} className={classes.box}>
<FormItem fullWidth style={{ marginBottom: 10 }}>
<Button
fullWidth
size={'large'}
color={'primary'}
variant={'contained'}
className={classes.submitButton}
onClick={() => this.onSubmit()}
>
<SaveIcon className={classes.rightIcon} />
{Strings.saveText}
</Button>
<Button
fullWidth
size={'large'}
color={'secondary'}
variant={'contained'}
className={classes.cancelButton}
onClick={() => Navigate.goBack()}
>
<CancelIcon className={classes.rightIcon} />
{Strings.cancelText}
</Button>
</FormItem>
</Paper>
</Grid>
</Grid>
</Form>
</React.Fragment>
)}
/>
{/* Get Institutions */}
<Entity
storeId={'Supervision-PlannedVisit-Schedule-List'}
entityRef={ref => { this.getInstitutionsEntity = ref; }}
onEntityReceived={data => this.onInstitutionEntityReceived(data)}
/>
{/* Get Request Id */}
<Entity
storeId={'Supervision-Complaints-GetRequestId'}
entityRef={ref => { this.getRequestIdEntity = ref; }}
onEntityPosted={data => this.getRequestIdEntityPosted(data)}
/>
{/* Get Violation By Request Id --- And Initiate Request in Admin Screens */}
<Entity
storeId={'Supervision-Complaints-Violations-By-ComplaintId'}
entityRef={ref => { this.getViolationsEntity = ref; }}
onEntityReceived={data => this.onViolationsEntityReceived(data)}
onEntityPosted={data => Navigate.goBack()}
/>
</React.Fragment>
);
}
}
violationEditorScreen.propTypes = {
classes: PropTypes.object,
};
export default violationEditorScreen;
componentDidMount() {
if(id) {
// grap the data from back end and upadte the table with checked rows that matches the ids that i got from Back-End
}
}
i expect receive array of Ids then mark each row that it's id is in the array Of Ids to let the user knows What he selected before.
Thx in Advance.
if I understand you correct, you want change the style of the row if it selected, so could you check this url and see the last example in order to modify it to adapt to your situation?
https://material-table.com/#/docs/features/styling