I want to bring a customized full calnedar and connect it with Google canlander api, but I don't know because it's customized Help me
The full calendar site says we can apply the code below, but I don't know where to put the code.
let calendar = new Calendar(calendarEl, {
plugins: [ googleCalendarPlugin ],
googleCalendarApiKey: '<YOUR API KEY>',
events: {
googleCalendarId: 'abcd1234#group.calendar.google.com',
className: 'gcal-event' // an option!
}
});
Below is my current code.
import React, { useState, useRef } from "react";
import "./style.module.css";
import FullCalendar from "#fullcalendar/react";
import timeGridPlugin from "#fullcalendar/timegrid";
import dayGridPlugin from "#fullcalendar/daygrid";
import interactionPlugin from "#fullcalendar/interaction";
import { nanoid } from "nanoid";
import {
Row,
Col,
Button,
FormGroup,
Label,
Input,
Container
} from "reactstrap";
import Select from "react-select";
import DateRangePicker from "react-bootstrap-daterangepicker";
import googleCalendarPlugin from "#fullcalendar/google-calendar"; //google calendar api
import "./custom.module.css";
import events from "./events";
import CustomModal from "../Components/CustomModal";
let todayStr = new Date().toISOString().replace(/T.*$/, "");
export default function Calendar() {
const [weekendsVisible, setWeekendsVisible] = useState(true);
const [currentEvents, setCurrentEvents] = useState([]);
const [modal, setModal] = useState(false);
const [confirmModal, setConfirmModal] = useState(false);
const calendarRef = useRef(null);
const [title, setTitle] = useState("");
const [start, setStart] = useState(new Date());
const [end, setEnd] = useState(new Date());
const handleCloseModal = () => {
handleClose();
setModal(false);
};
function handleDateClick(arg) {
};
function handleDateSelect(selectInfo) {
if (
selectInfo.view.type === "timeGridWeek" ||
selectInfo.view.type === "timeGridDay"
) {
selectInfo.view.calendar.unselect();
setState({ selectInfo, state: "create" });
// Open modal create
console.log("open modal create");
// console.log(selectInfo);
setStart(selectInfo.start);
setEnd(selectInfo.end);
setModal(true);
}
}
function renderEventContent(eventInfo) {
return (
<div>
<i
style={{
whiteSpace: "nowrap",
overflow: "hidden",
textOverflow: "ellipsis"
}}
>
{eventInfo.event.title}
</i>
</div>
);
}
function handleEventClick(clickInfo) {
setState({ clickInfo, state: "update" });
setTitle(clickInfo.event.title);
setStart(clickInfo.event.start);
setEnd(clickInfo.event.end);
setModal(true);
}
function handleEvents(events) {
setCurrentEvents(events);
}
function handleEventDrop(checkInfo) {
setState({ checkInfo, state: "drop" });
setConfirmModal(true);
}
function handleEventResize(checkInfo) {
setState({ checkInfo, state: "resize" });
setConfirmModal(true);
}
function handleEdit() {
state.clickInfo.event.setStart(start);
state.clickInfo.event.setEnd(end);
state.clickInfo.event.mutate({
standardProps: { title }
});
handleClose();
}
function handleSubmit() {
const newEvent = {
id: nanoid(),
title,
start: state.selectInfo?.startStr || start.toISOString(),
end: state.selectInfo?.endStr || end.toISOString(),
allDay: state.selectInfo?.allDay || false
};
calendarApi.addEvent(newEvent);
handleClose();
}
function handleDelete() {
state.clickInfo.event.remove();
handleClose();
}
function handleClose() {
setTitle("");
setStart(new Date());
setEnd(new Date());
setState({});
setModal(false);
}
const [state, setState] = useState({});
const [departments, setDepartments] = useState([
{ value: "1", label: "All" },
{ value: "2", label: "BPA Technical" },
{ value: "3", label: "Aqua 2 Cleaning" }
]);
function onFilter(element) {
console.log(element.value);
}
return (
<div className="App">
<Container>
<Row style={{ marginTop: 150 }}>
<h1 style={{color:'white', textAlign:'center', marginBottom:50}}>Make a Booking</h1>
</Row>
<Row>
<Col md={12}>
<FullCalendar
ref={calendarRef}
plugins={[dayGridPlugin,timeGridPlugin, interactionPlugin]}
headerToolbar={{
left: "prev,today,next",
center: "title",
right: "dayGridMonth,timeGridWeek,timeGridDay"
}}
buttonText={{
today: "Today's Time Table",
month: "month",
week: "week",
day: "day",
list: "list"
}}
initialView="timeGridWeek"
editable={true}
selectable={true}
selectMirror={true}
dayMaxEvents={true}
weekends={weekendsVisible}
//
initialEvents={[
{
},
{
id: nanoid(),
title: "All-day event",
start: todayStr
},
{
id: nanoid(),
title: "Timed event",
start: todayStr + "T12:00:00",
end: todayStr + "T12:30:00"
}
]}
select={handleDateSelect}
eventContent={renderEventContent} // custom render function
eventClick={handleEventClick}
eventsSet={() => handleEvents(events)}
eventDrop={handleEventDrop}
eventResize={handleEventResize}
//
dateClick={handleDateClick}
eventAdd={(e) => {
console.log("eventAdd", e);
}}
eventChange={(e) => {
console.log("eventChange", e);
}}
eventRemove={(e) => {
console.log("eventRemove", e);
}}
/>
</Col>
</Row>
</Container>
<CustomModal
title={state.state === "update" ? "Update Booking" : "Make a Booking"}
isOpen={modal}
toggle={handleCloseModal}
onCancel={handleCloseModal}
onSubmit={state.clickInfo ? handleEdit : handleSubmit}
submitText={state.clickInfo ? "Update" : "Save"}
onDelete={state.clickInfo && handleDelete}
deleteText="Delete"
>
<FormGroup>
<Label for="#gmail.com">Trainer</Label>
<br/>
<select className="form-control" name="title"
value={title} onChange={(e) => setTitle(e.target.value)}>
<option></option>
<option></option>
<option></option>
<option></option>
</select>
</FormGroup>
<FormGroup>
<Label for="#gmail.com">Start Time - End Time</Label>
<DateRangePicker
initialSettings={{
locale: {
format: "M/DD hh:mm A"
},
startDate: start,
endDate: end,
timePicker: true
}}
onApply={(event, picker) => {
setStart(new Date(picker.startDate));
setEnd(new Date(picker.endDate));
}}
>
<input className="form-control" type="text" />
</DateRangePicker>
</FormGroup>
</CustomModal>
<CustomModal
title={state.state === "resize" ? "Resize Event" : "Drop Event"}
isOpen={confirmModal}
toggle={() => {
state.checkInfo.revert();
setConfirmModal(false);
}}
onCancel={() => {
state.checkInfo.revert();
setConfirmModal(false);
}}
cancelText="Cancel"
onSubmit={() => setConfirmModal(false)}
submitText={"OK"}
>
Do you want to {state.state} this event?
</CustomModal>
</div>
);
}
I tried to apply the code below to my code by applying calendar id and api key on Google, but I don't know.
let calendar = new Calendar(calendarEl, {
plugins: [ googleCalendarPlugin ],
googleCalendarApiKey: '<YOUR API KEY>',
events: {
googleCalendarId: 'abcd1234#group.calendar.google.com',
className: 'gcal-event' // an option!
}
});
Related
I have a project, and this project contains several interfaces, and among these interfaces there is an interface for uploading an image, and the problem is in the deletion icon. When you click on it, a modal appears, but the element is deleted before the modal appears.
How can i solve the problem?
this file display a list of instructions that contains upload Image
import '../../../styles/input/index.scss';
import '../../../styles/dropzone/index.scss';
import { Button, Col, message, Modal, Row, Spin, Upload, UploadFile } from 'antd';
import { FunctionComponent, useCallback, useRef, useState } from 'react';
import { motion, useAnimation } from 'framer-motion';
import { defaultTranstion } from '../../../constants/framer';
import { Controller } from 'react-hook-form';
import FromElemnetWrapper from '../form-element-wrapper';
import { Delete, UploadCloud } from 'react-feather';
import { getBase64 } from '../../../utils/get-base64';
import _ from 'lodash';
import config from '../../../api/nuclearMedicineApi/config';
import { FormattedMessage } from 'react-intl';
import BasicModal from '../modal';
import { UploadOutlined } from '#ant-design/icons';
import axios from 'axios';
import { IFormError } from '../general-form-containner';
interface DropzoneProps {
name: string;
control: any;
rules?: any;
label: string;
disabled?: boolean;
multiple?: boolean;
accept?: string;
refType?: number;
defaultFileList?: any;
onRemove?: any;
customRequest?: (option: any) => void;
onProgress?: any;
}
const Dropzone: FunctionComponent<DropzoneProps> = ({
name,
control,
rules,
label,
disabled,
multiple,
accept,
refType,
defaultFileList,
onRemove,
customRequest,
onProgress
}) => {
const focusController = useAnimation();
const errorController = useAnimation();
const [previewVisible, setpreviewVisible] = useState(false);
const [previewImage, setpreviewImage] = useState('');
const handleCancel = () => setpreviewVisible(false);
const handlePreview = async (file: any) => {
if (!file.url && !file.preview) {
file.preview = await getBase64(file.originFileObj);
}
setpreviewImage(file?.preview ?? file.url);
setpreviewVisible(true);
};
const [isModalOpen, setIsModalOpen] = useState(false);
const [errors, setErrors] = useState<IFormError[]>([]);
const [visibleModal, setVisibleModal] = useState(false);
const [removePromise, setRemovePromise] = useState();
const [deleteVisible, setdeleteVisible] = useState<boolean>(false);
const onDeleteHandle = () => {
setdeleteVisible(false);
};
const deletehandleCancel = () => {
setdeleteVisible(false);
};
let resolvePromiseRef = useRef<((value: boolean) => void) | undefined>();
// let resolvePromiseRef = useRef<HTMLInputElement | null>(null)
const handleRemove = useCallback(() =>{
const promise = new Promise(resolve => {
resolvePromiseRef.current = resolve
});
setVisibleModal(true);
return promise;
}, [])
const handleOkModalRemove = useCallback(() => {
if (resolvePromiseRef.current) {
resolvePromiseRef.current(true)
}
}, [removePromise]);
const handleCancelModalRemove = useCallback(() => {
if (resolvePromiseRef.current) {
resolvePromiseRef.current(false);
setVisibleModal(false)
}
}, [removePromise]);
return (
<>
<FromElemnetWrapper
focusController={focusController}
errorController={errorController}
label={label}
required={rules.required?.value}
>
<Controller
control={control}
name={name}
rules={rules}
render={({
field: { onChange, onBlur, value, name, ref },
fieldState: { invalid, error },
}) => {
if (invalid) {
errorController.start({ scale: 80 });
} else {
errorController.start(
{ scale: 0 },
{ ease: defaultTranstion.ease.reverse() },
);
}
return (
<div
onBlur={() => {
onBlur();
focusController.start({ scale: 0 });
}}
onFocus={() => {
focusController.start({ scale: 80 });
}}
className='relative'
>
<div className='upload-container'>
<form
className='dropzone needsclick'
id='demo-upload'
action='/upload'
>
{/* <> */}
<Upload
action={`${config.baseUrl}api/services/app/Attachment/Upload`}
headers={config.headers}
ref={ref}
multiple={multiple}
disabled={disabled}
data={{ RefType: refType }}
listType='picture'
fileList={value}
id={name}
accept={accept}
onPreview={handlePreview}
onRemove={handleRemove}
iconRender={
() => {
return <Spin style={{ marginBottom: '12px', paddingBottom: '12px' }}></Spin>
}
}
progress={{
strokeWidth: 3,
strokeColor: {
"0%": "#f0f",
"100%": "#ff0"
},
style: { top: 12 }
}}
beforeUpload={
(file) => {
console.log({ file });
return true
}
}
// onProgress= {(event: any) => (event.loaded / event.total) * 100}
// onChange={(e) =>
// onChange(e.fileList)
// }
// onChange={(response) => {
// console.log('response: ', response);
// if (response.file.status !== 'uploading') {
// console.log(response.file, response.fileList);
// }
// if (response.file.status === 'done') {
// message.success(`${response.file.name}
// file uploaded successfully`);
// } else if (response.file.status === 'error') {
// message.error(`${response.file.name}
// file upload failed.`);
// }
// else if (response.file.status === 'removed') {
// message.error(`${response.file.name}
// file upload removed.`);
// }
// }}
>
<div className='upload-button'>
<div className='wrapper'>
<motion.div
className='fas fa-angle-double-up'
whileHover={{
y: [
0, -2, 2,
0,
],
transition: {
duration: 1.5,
ease: 'easeInOut',
yoyo: Infinity,
},
}}
>
<UploadCloud
style={{
margin: '.2rem',
display:
'inline-block',
}}
color='white'
size={20}
/>
Upload
</motion.div>
</div>
</div>
</Upload>
{/*
<Modal
title="Are you sure?"
visible={visibleModal}
onOk={handleOkModalRemove}
onCancel={handleCancelModalRemove}
/> */}
<BasicModal
header={
<>
<FormattedMessage id={'confirmdeletion'} />
</>
}
headerType='error'
content={
<>
<Row>
<Col span={8} offset={4}>
<Button
type='primary'
className='savebtn'
onClick={onDeleteHandle}
style={{
cursor:
Object.keys(errors).length !==
0
? 'not-allowed'
: 'pointer',
}}
>
<FormattedMessage id={'affirmation'} />
</Button>
</Col>
<Col span={8} offset={4}>
<Button
type='default'
className='savebtn'
onClick={deletehandleCancel}
style={{
cursor:
Object.keys(errors).length !==
0
? 'not-allowed'
: 'pointer',
}}
>
<FormattedMessage id={'cancel'} />
</Button>
</Col>
</Row>
</>
}
isOpen={visibleModal}
footer={false}
width='35vw'
handleCancel={handleCancelModalRemove}
handleOk={handleOkModalRemove}
/>
{/* {_.isEmpty(value) && (
<div className='dz-message needsclick'>
<FormattedMessage id='dropfileshere' />
</div>
)} */}
<BasicModal
isOpen={previewVisible}
header={<FormattedMessage id="Preview image" />}
footer={false}
handleCancel={handleCancel}
content={<img
alt='example'
style={{ width: '100%' }}
src={previewImage}
/>}
/>
{/* </> */}
</form>
</div>
{invalid && (
<p className='form-element-error'>
{error?.message}
</p>
)}
</div>
);
}}
/>
</FromElemnetWrapper>
</>
);
};
export default Dropzone;
Why it doesn't work?
https://ant.design/components/upload
onRemove - A callback function, will be executed when removing file button is clicked, remove event will be prevented when return value is false or a Promise which resolve(false) or reject
You have to return a promise which resolves to false or return false
How to solve it?
You have to return a promise so first of all, you need a ref or a state to store resolve function of that promise so you can call it in modal
const resolvePromiseRef = useRef<((value: boolean) => void) | undefined>();
Then you will need to assign the resolve function to the ref and return the promise
Now onRemove will wait for your promise to resolve
const handleRemove = () =>{
const promise = new Promise(resolve => {
resolvePromiseRef.current = resolve
});
setVisibleModal(true);
return promise;
}
Now your functions handlers
const handleOkModalRemove = useCallback(() => {
if (resolvePromiseRef.current) {
resolvePromiseRef.current(true)
}
}, [removePromise]);
const handleCancelModalRemove = useCallback(() => {
if (resolvePromiseRef.current) {
resolvePromiseRef.current(false)
}
}, [removePromise]);
You can also use the state, but I recommend ref because it doesn't rerender the component when changed.
Newer to React. I have this column in a ReactTable which has an input textbox. I understand that changing the state is re-rending the form just not sure how to prevent that. Appreciate any guidance!
<ReactTable
key={googlecampaigndata?.length}
data={googlecampaigndata}
loading={googlecampaignloading}
sortable={false}
filterable={false}
columns={[
{
Header: "Account Name",
accessor: "customer_name"
},
{
Header: "Campaign Name",
accessor: "campaign_name"
},
{
Header: "Campaign Type",
accessor: "campaign_type"
},
{
Header: "Status",
accessor: "status"
},
{
Header: "Monthly Budget",
accessor: "monthly_budget"
},
{
Header: "Update Monthly Budget",
accessor: "update_monthly_budget",
Cell: ({ original }) => {
return (
<form
onSubmit={e => {
e.preventDefault();
if(submissionData !== {} && submitGoogleCampaignMonthlyBudgetForm()){
refetch();
}
}
}
>
<input
id={`monthly_budget${original.id}`}
type="text"
maxLength="12"
size="8"
style={{ float: "left" }}
onChange = {updateFieldHandler("monthly_budget", original.id)}
inputprops={{
type: "string",
required: true,
value: original['monthly_budget'] ? original['monthly_budget'] : ""
}}
/><Button
color="primary"
type="submit"
style={{ float: "right" }}
>
Submit
</Button>
</form>
);
},
},
{
Header: "Cycle Start Date",
accessor: "date"
}
]}
defaultPageSize={Math.min(pageSize, googlecampaigndata?.length || 2)}
showPaginationTop
showPaginationBottom={false}
onPageSizeChange={ps => setPageSize(ps)}
className="-striped -highlight"
/>
#EDIT
I tried returning my input field from outside of MyAccounts but I'm still losing focus on the input when typing. More of my updated code below.
import React, { useState, useContext, useEffect } from "react";
import { useQuery, useMutation } from "#apollo/react-hooks";
import { intersection, omit } from "lodash";
// #material-ui/core components
import { makeStyles } from "#material-ui/core/styles";
// #material-ui/icons
import Assignment from "#material-ui/icons/Assignment";
// core components
import GridContainer from "components/Grid/GridContainer";
import GridItem from "components/Grid/GridItem";
import Card from "components/Card/Card";
import CardBody from "components/Card/CardBody";
import CardIcon from "components/Card/CardIcon";
import CardHeader from "components/Card/CardHeader";
import ReactTable from "components/CustomReactTable";
import Button from "components/CustomButtons/Button";
import { cardTitle } from "assets/jss/material-dashboard-pro-react";
import { SUBMIT_GOOGLE_CAMPAIGN_MONTHLY_BUDGET_FORM } from "queries/formSubmission";
import { LIST_BUDGETS } from "queries/budget";
import { GET_GOOGLE_CAMPAIGNS } from "queries/budget";
import { Context } from "redux/store";
const styles = {
cardIconTitle: {
...cardTitle,
marginTop: "15px",
marginBottom: "0px"
}
};
const useStyles = makeStyles(styles);
const GoogleCampaignMonthlyBudgetInput = ({ original, setSubmissionData, submissionData, state, onChange }) => {
return (
<input
id={`monthly_budget${original.id}`}
type="text"
maxLength="12"
size="8"
style={{ float: "left" }}
key={original.id}
onChange={ onChange }
value={submissionData.id === original.id ? submissionData.monthly_budget : original.monthly_budget ? (original.monthly_budget / (1 - (state.customers?.selected?.margin / 100.0))) / 1000000 : ""}
inputprops={{
type: "string",
required: true,
}}
/>
);
}
const MyAccounts = () => {
const [state] = useContext(Context);
const [pageSize, setPageSize] = useState(20);
const customer_id = state.customers?.selected?.id;
const [submissionData, setSubmissionData] = useState({});
let { loading, data } = useQuery(LIST_BUDGETS);
let { loading: googlecampaignloading, data: googlecampaigndata, refetch } = useQuery(GET_GOOGLE_CAMPAIGNS);
googlecampaigndata = googlecampaigndata?.getGoogleCampaigns || [];
data = data?.listBudgets || [];
data = data.map((row, index) => {
let customer_name = "";
let product_line = "";
if (
index % pageSize === 0 ||
row.customer_name !== data[index - 1].customer_name
) {
customer_name = row.customer_name;
}
if (
index % pageSize === 0 ||
row.product_line !== data[index - 1].product_line
) {
product_line = row.product_line;
}
return {
...row,
customer_name,
product_line
};
});
const [submitGoogleCampaignMonthlyBudgetForm, { loading: submitting }] = useMutation(
SUBMIT_GOOGLE_CAMPAIGN_MONTHLY_BUDGET_FORM,
{
variables: {
customerId: customer_id,
data: submissionData
},
onCompleted: () => {
return true;
}
}
);
const classes = useStyles();
return (
<GridContainer>
<GridItem xs={12}>
<Card>
<CardHeader color="trackedKeywords" icon>
<CardIcon>
<Assignment />
</CardIcon>
<h4 className={classes.cardIconTitle}>Google Campaigns</h4>
</CardHeader>
<CardBody>
<ReactTable
key={googlecampaigndata?.length}
data={googlecampaigndata}
loading={googlecampaignloading}
sortable={false}
filterable={false}
columns={[
{
Header: "Monthly Budget",
accessor: "monthly_budget",
Cell: ({ original }) => {
return (
<div>{original.monthly_budget ? (original.monthly_budget / (1 - (state.customers?.selected?.margin / 100.0))) / 1000000 : ""}</div>
);
},
},
{
Header: "Update Monthly Budget",
accessor: "update_monthly_budget",
Cell: ({ original }) => {
return (
<form
onSubmit={e => {
e.preventDefault();
if(submissionData !== {} && submitGoogleCampaignMonthlyBudgetForm()){
refetch();
}
}
}
>
<GoogleCampaignMonthlyBudgetInput original={original} onChange={e => setSubmissionData({...submissionData, "monthly_budget": parseFloat(e.target.value), "id": original.id })} setSubmissionData={setSubmissionData} submissionData={submissionData} state={state} key={original.id} />
<Button
color="primary"
type="submit"
style={{ float: "right" }}
>
Submit
</Button>
</form>
);
},
},
{
Header: "Cycle Start Date",
accessor: "date"
}
]}
defaultPageSize={Math.min(pageSize, googlecampaigndata?.length || 2)}
showPaginationTop
showPaginationBottom={false}
onPageSizeChange={ps => setPageSize(ps)}
className="-striped -highlight"
/>
</CardBody>
</Card>
</GridItem>
</GridContainer>
);
};
export default MyAccounts;
Edit 2: code that I got working with inwerpsel's help!
{
Header: "Monthly Budget",
accessor: "monthly_budget",
Cell: ({ original }) => {
return (
<div>{submissionData.id === original.id ? submissionData.monthly_budget : original.monthly_budget ? (original.monthly_budget / (1 - (state.customers?.selected?.margin / 100.0))) / 1000000 : ""}</div>
);
},
},
{
Header: "Update Monthly Budget",
accessor: "update_monthly_budget",
Cell: ({ original }) => {
const [textInput, setTextInput] = useState(null);
const [submitGoogleCampaignMonthlyBudgetForm, { loading: submitting }] = useMutation(
SUBMIT_GOOGLE_CAMPAIGN_MONTHLY_BUDGET_FORM,
{
variables: {
customerId: customer_id,
data: submissionData
},
onCompleted: () => {
refetch();
return true;
}
}
);
return (
<form
key={"form"+original.id}
onSubmit={e => {
e.preventDefault();
if(Number.isNaN(textInput) || textInput === "" || textInput === null){
setSubmissionData({});
return;
}
submissionData["monthly_budget"] = parseFloat(textInput);
submissionData["id"] = original.id;
if(submissionData !== {} && submitGoogleCampaignMonthlyBudgetForm()){
refetch();
setSubmissionData({});
}
}
}
>
<input
id={`monthly_budget${original.id}`}
type="text"
maxLength="12"
size="8"
style={{ float: "left" }}
key={original.id}
onChange = {event => { setTextInput(event.target.value) }}
defaultValue={submissionData.id === original.id ? submissionData.monthly_budget : original.monthly_budget ? (original.monthly_budget / (1 - (state.customers?.selected?.margin / 100.0))) / 1000000 : ""}
inutprops={{
type: "string",
required: true,
}}
/>
<Button
color="primary"
type="submit"
style={{ float: "right" }}
>
Submit
</Button>
</form>
);
},
},
This GitHub issue seems to indicate that indeed cells will remount as your data changes, even if it's a small change.
In other words, as you type it replaces the whole row with a new instance every character. The new instance has no link to the previous one, even though it should contain the data you typed. As a result it won't have focus.
It seems potentially hard to get around, though I'm not that familiar with react-table.
However, as you already have a form with a submit handler set up, I guess you can just store the input in a local state, and only set it on submit.
Cell: ({ original }) => {
const [textInput, setTextInput] = useState(null);
return (
<form
onSubmit={e => {
e.preventDefault();
// Call the update handler here instead.
const handler = updateFieldHandler("monthly_budget", original.id);
handler(textInput);
if(submissionData !== {} && submitGoogleCampaignMonthlyBudgetForm()){
refetch();
}
}
}
>
<input
// ...
onChange = {event => { setTextInput(event.target.value) }}
// ...
/><Button
color="primary"
type="submit"
style={{ float: "right" }}
>
Submit
</Button>
</form>
);
I am working on fullCalendar. I want to implement something like this:
After dragging and dropping an event, a popup shows
If we cancel the event it needs to go back to its previous position
But the issue I am facing is that I am not able to find a way to return event back to its original position after dragging.
I am thinking to store the start dragging position and store also store the drop position. But I don't know if it is the right why to do that. Is there is any built in feature to do that or set the event back?
import React, { useState, useRef, useEffect } from "react";
import FullCalendar from "#fullcalendar/react"; // must go before plugins
import dayGridPlugin from "#fullcalendar/daygrid"; // a plugin!
import interactionPlugin, { Draggable } from "#fullcalendar/interaction"; // needed for dayClick
import timeGridPlugin from "#fullcalendar/timegrid";
import { resources } from "./records/resources";
import { events } from "./records/events";
import { Col, Row } from "react-bootstrap";
import "#fullcalendar/daygrid/main.css";
import "#fullcalendar/timegrid/main.css";
import "bootstrap/dist/css/bootstrap.css";
import { AlertBox } from "./atertBox";
import resourceTimelinePlugin from "#fullcalendar/resource-timeline";
function App() {
const [tableState, setTableState] = useState(events);
const [show, setShow] = useState(false);
const [showModal, setShowModal] = useState(false);
const dateRef = useRef();
const addEvent = (e) => {
const newEvent = {
id: tableState.length + 1,
title: e.target.title.value,
start: e.target.startdate.value + ":00+00:00",
end: e.target.enddate.value + ":00+00:00",
resourceId: "d",
// resourceEditable: false, to Preventing shifting between resources
};
setTableState((prev) => {
console.log(...prev);
console.log();
console.log(newEvent);
return [...prev, newEvent];
});
e.preventDefault();
};
const handleDateClick = (arg) => {
console.log("Arg", arg.dateStr);
};
const saveRecord = (record) => {
var today = new Date(record);
// var dd = String(today.getDate()).padStart(2, "0");
// var mm = String(today.getMonth() + 1).padStart(2, "0"); //January is 0!
// var yyyy = today.getFullYear();
// today = yyyy + "-" + mm + "-" + dd;
console.log(today, "today");
dateRef.current = { today };
setShow(true);
};
const injectwithButton = (args) => {
return (
<div>
<button onClick={() => saveRecord(args.date)}>
{args.dayNumberText}
</button>
</div>
);
};
useEffect(() => {
let draggableEl = document.getElementById("external-events");
new Draggable(draggableEl, {
itemSelector: ".fc-event",
minDistance: 5,
eventData: function (eventEl) {
console.log("drag element ", eventEl);
let title = eventEl.getAttribute("title");
let id = eventEl.getAttribute("data");
return {
title: title,
id: id,
};
},
});
}, []);
const eventClicked = (event) => {
console.log("event",event)
};
return (
<div className="animated fadeIn p-4 demo-app">
<Row>
<Col lg={3} sm={3} md={3}>
<div
id="external-events"
style={{
padding: "10px",
width: "20%",
height: "auto",
}}
>
<p align="center">
<strong> Events</strong>
</p>
{events.map((event, index) => (
<div
className="fc-event"
title={event.title}
data={event.id}
key={index}
>
{event.title}
</div>
))}
</div>
</Col>
<Col lg={9} sm={9} md={9}>
<div className="demo-app-calendar" id="mycalendartest">
<FullCalendar
plugins={[
dayGridPlugin,
timeGridPlugin,
interactionPlugin,
resourceTimelinePlugin,
]}
initialView="resourceTimeline"
headerToolbar={{
left: "today,prev,next",
center: "title",
right:
"new dayGridMonth,timeGridWeek,timeGridDay,resourceTimeline",
}}
customButtons={{
new: {
text: "add new event",
click: (e) => setShow(true),
},
}}
eventColor="grey"
nowIndicator={true}
events={tableState}
resources={resources}
dateClick={handleDateClick}
eventClick={eventClicked}
editable={true}
eventDragStart={(e) => console.log("ee", e)}
eventDrop={(drop) => {
console.log("drop", drop.oldEvent._instance.range);
console.log("drop", drop.oldEvent._def.publicId);
}}
eventResizableFromStart={true}
eventResize={(resize) => console.log("resize", resize)}
dayCellContent={injectwithButton}
schedulerLicenseKey="CC-Attribution-NonCommercial-NoDerivatives"
droppable={true}
// eventReceive={(e) => {
// console.log("receive", e);
// console.log("receive", e.event._instance.range);
// }}
drop={(drop) => {
console.log("external drop", drop);
}}
/>
</div>
</Col>
</Row>
</div>
);
}
export default App;
If you're talking about dragging an existing calendar event to a new position, then eventDrop provides a revert callback which, if called, will send the event back to its previous position.
If you're talking about dragging an external event onto the calendar, eventReceive provides a revert callback which, if called, will reverse the action and the event will not be dropped onto the calendar.
I'm trying to make an Autocomplete input for categories from an API response and allow the user to be able to create one if he didn't find
a match.
Issues:
1- How to avoid Non-unique when I have same key which is name can I make on ID cause it's unique?
Warning: Encountered two children with the same key, `Flour & Bread Mixes`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behaviour is unsupported and could change in a future version.
2- The dialog for entring new category doesn't open and I don't see any errors in the console
Code Sandbox
https://codesandbox.io/s/asynchronous-material-demo-forked-70eff?file=/demo.js
import React, {useState} from "react";
import TextField from '#mui/material/TextField';
import Autocomplete , { createFilterOptions } from '#mui/material/Autocomplete';
import CircularProgress from '#mui/material/CircularProgress';
import parse from 'autosuggest-highlight/parse';
import match from 'autosuggest-highlight/match';
import axios from "axios";
import Dialog from '#mui/material/Dialog';
import DialogTitle from '#mui/material/DialogTitle';
import DialogContent from '#mui/material/DialogContent';
import DialogContentText from '#mui/material/DialogContentText';
import DialogActions from '#mui/material/DialogActions';
import Button from '#mui/material/Button';
import { Input } from "#material-ui/core";
export default function Asynchronous() {
const filter = createFilterOptions();
const [open, setOpen] = React.useState(false);
const [options, setOptions] = React.useState([]);
const loading = open && options.length === 0;
const [categories, setCategories] = useState([]);
const [openDialog, toggleOpenDialog] = React.useState(false);
const handleClose = () => {
setDialogValue({
name: '',
slug: '',
image: '',
});
toggleOpenDialog(false);
};
const handleSubmit = (event) => {
event.preventDefault();
setCategories({
name: dialogValue.name,
slug: dialogValue.slug,
image: dialogValue.image
});
handleClose();
};
const [dialogValue, setDialogValue] = React.useState({
name: '',
slug: '',
image: '',
});
React.useEffect(() => {
let active = true;
if (!loading) {
return undefined;
}
(async () => {
var config = {
method: 'get',
url: 'https://null.free.mockoapp.net/getCategories',
};
axios(config)
.then(function (response) {
response.data = response.data.filter((category) => category.name)
if (active) {
setOptions([...response.data]);
}
})
.catch(function (error) {
console.log(error);
});
})();
return () => {
active = false;
};
}, [loading]);
React.useEffect(() => {
if (!open) {
setOptions([]);
}
}, [open]);
return (
<>
<Autocomplete
id="asynchronous-demo"
open={open}
limitTags={3}
onOpen={() => {
setOpen(true);
}}
onClose={() => {
setOpen(false);
}}
isOptionEqualToValue={(option, value) => option.name === value.name}
getOptionLabel={(option) => {
// Value selected with enter, right from the input
if (typeof option === 'string') {
return option;
}
// Add "xxx" option created dynamically
if (option.inputValue) {
return option.inputValue;
}
// Regular option
return option.name;
}}
options={options}
loading={loading}
multiple
renderInput={(params) => (
<>
<TextField
{...params}
label="Asynchronous"
InputProps={{
...params.InputProps,
endAdornment: (
<React.Fragment>
{loading ? <CircularProgress color="inherit" size={20} /> : null}
{params.InputProps.endAdornment}
</React.Fragment>
),
}}
/>
{console.log(options)}
</>
)}
renderOption={(props, option, { inputValue }) => {
const matches = match(option.name, inputValue);
const parts = parse(option.name, matches);
return (
<li {...props}>
<div>
{parts.map((part, index) => (
<span
key={index}
style={{
color: part.highlight ? "red" : 'inherit',
fontWeight: part.highlight ? 700 : 400,
}}
>
{part.text}
</span>
))}
</div>
</li>
);
}}
value={categories}
onChange={(event, newValue) => {
if (typeof newValue === 'string') {
// timeout to avoid instant validation of the dialog's form.
setTimeout(() => {
toggleOpenDialog(true);
setDialogValue({
name: newValue,
slug: '',
image: ''
});
});
} else if (newValue && newValue.inputValue) {
toggleOpenDialog(true);
setDialogValue({
name: newValue.inputValue,
slug: '',
image: ''
});
} else {
setCategories(newValue);
}
}}
filterOptions={(options, params) => {
const filtered = filter(options, params);
const { inputValue } = params;
const isExisting = options.some((option) => inputValue === option.name);
if (inputValue !== '' && !isExisting) {
filtered.push({
inputValue:inputValue,
name: `Add "${inputValue}"`,
});
}
return filtered;
}}
selectOnFocus
clearOnBlur
handleHomeEndKeys
/>
<Dialog open={openDialog} onClose={handleClose}>
<form onSubmit={handleSubmit}>
<DialogTitle>Add a new film</DialogTitle>
<DialogContent>
<DialogContentText>
Did you miss any film in our list? Please, add it!
</DialogContentText>
<TextField
autoFocus
margin="dense"
id="name"
value={dialogValue.name}
onChange={(event) =>
setDialogValue({
...dialogValue,
name: event.target.value,
})
}
label="title"
type="text"
variant="standard"
/>
<TextField
margin="dense"
id="slug"
value={dialogValue.slug}
onChange={(event) =>
setDialogValue({
...dialogValue,
slug: event.target.value,
})
}
label="slug"
type="text"
variant="standard"
/>
<Input
margin="dense"
id="image"
value={dialogValue.image}
onChange={(event) =>
setDialogValue({
...dialogValue,
image: event.target.value,
})
}
label="image"
type="file"
variant="standard"
/>
</DialogContent>
<DialogActions>
<Button onClick={handleClose}>Cancel</Button>
<Button type="submit">Add</Button>
</DialogActions>
</form>
</Dialog>
</>
);
}
I found a lot of mistakes in your code so I made a new working fork on Codesandbox
https://codesandbox.io/s/asynchronous-material-demo-forked-oeg2p?file=/demo.js
Notes:
save the api response in a state instead of doing an API call
whenever the user opens the dropdown.
you could make an API request in handleSubmit function to create a new category in the back-end
handleFormSubmit will output the value of Autocomplete.
Let me know if you have any questions.
Read more about autocomplete at
https://mui.com/components/autocomplete/#asynchronous-requests
Starter in React-hook project
I need to call openModal() from column.js which is defined in Table.js and need to fetch data and open the new modal form Table.js. Its react-hook project
column.js
// ** React Imports
import { Link } from 'react-router-dom'
// ** Custom Components
import Avatar from '#components/avatar'
// ** Store & Actions
import { getUser, deleteUser } from '../store/action'
import { store } from '#store/storeConfig/store'
import { useSelector } from 'react-redux'
// ** Third Party Components
import { Badge, UncontrolledDropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap'
import { Slack, User, Settings, Database, Edit2, MoreVertical, FileText, Trash2, Archive } from 'react-feather'
// ** Renders Client Columns
const renderClient = row => {
const stateNum = Math.floor(Math.random() * 6),
states = ['light-success', 'light-danger', 'light-warning', 'light-info', 'light-primary', 'light-secondary'],
color = states[stateNum]
if (row.user_avatar.length) {
const server_base_url = "http://localhost:3001/uploads/"
return <Avatar className='mr-1' img={`${server_base_url}${row.user_avatar}`} width='32' height='32' />
} else {
return <Avatar color={color || 'primary'} className='mr-1' content={row.user_fullname || 'John Doe'} initials />
}
}
const renderSerialNo = row => {
const param = useSelector(state => state.users.params)
const serial = ((param.page - 1) * param.perPage) + row + 1
return (serial)
}
// ** Renders Role Columns
const renderRole = row => {
const roleObj = {
subscriber: {
class: 'text-primary',
icon: User
},
maintainer: {
class: 'text-success',
icon: Database
},
editor: {
class: 'text-info',
icon: Edit2
},
author: {
class: 'text-warning',
icon: Settings
},
admin: {
class: 'text-danger',
icon: Slack
}
}
const Icon = roleObj[row.type_name] ? roleObj[row.type_name].icon : Edit2
return (
<span className='text-truncate text-capitalize align-middle'>
<Icon size={18} className={`${roleObj[row.type_name] ? roleObj[row.type_name].class : ''} mr-50`} />
{row.type_name}
</span>
)
}
const statusObj = {
2: 'light-warning',
0: 'light-success',
1: 'light-secondary'
}
export const columns = (openModal) => [
{
name: '#',
maxWidth: '3px',
selector: 'serial',
sortable: true,
cell: (row, index) => (renderSerialNo(index))
},
{
name: 'User',
minWidth: '300px',
selector: 'fullName',
sortable: true,
cell: row => (
<div className='d-flex justify-content-left align-items-center'>
{renderClient(row)}
<div className='d-flex flex-column'>
<Link
to={`/apps/user/view/${row.id}`}
className='user-name text-truncate mb-0'
onClick={() => store.dispatch(getUser(row.user_id))}
>
<span className='font-weight-bold'>{row.user_fullname}</span>
</Link>
<small className='text-truncate text-muted mb-0'>#{row.user_name}</small>
</div>
</div>
)
},
{
name: 'Email',
minWidth: '220px',
selector: 'email',
sortable: true,
cell: row => row.user_email
},
{
name: 'Role',
minWidth: '172px',
selector: 'role',
sortable: true,
cell: row => renderRole(row)
},
{
name: 'Status',
minWidth: '138px',
selector: 'status',
sortable: true,
cell: row => (
<Badge className='text-capitalize' color={statusObj[row.user_status]} pill>
{row.user_status_text}
</Badge>
)
},
{
name: 'Actions',
minWidth: '10px',
cell: row => (
<UncontrolledDropdown>
<DropdownToggle tag='div' className='btn btn-sm'>
<MoreVertical size={14} className='cursor-pointer' />
</DropdownToggle>
<DropdownMenu right>
<DropdownItem
tag={Link}
to={`/apps/user/view/${row.user_id}`}
className='w-100'
onClick={() => store.dispatch(getUser(row.user_id))}
>
<FileText size={14} className='mr-50' />
<span className='align-middle'>Details</span>
</DropdownItem>
<DropdownItem
tag={Link}
to={`/apps/user/edit/${row.user_id}`}
className='w-100'
onClick={() => store.dispatch(getUser(row.user_id))}
>
<Archive size={14} className='mr-50' />
<span className='align-middle'>Edit</span>
</DropdownItem>
<DropdownItem className='w-100' onClick={() => openModal(row)}>
<Trash2 size={14} className='mr-50' />
<span className='align-middle'>Delete</span>
</DropdownItem>
</DropdownMenu>
</UncontrolledDropdown>
)
}
]
Table.js
// ** React Imports
import { Fragment, useState, useEffect } from 'react'
// ** Invoice List Sidebar
import Sidebar from './Sidebar'
// ** Columns
import { columns } from './columns'
// ** Store & Actions
import { getAllData, getData } from '../store/action'
import { useDispatch, useSelector } from 'react-redux'
// ** Third Party Components
import Select from 'react-select'
import ReactPaginate from 'react-paginate'
import { ChevronDown } from 'react-feather'
import DataTable from 'react-data-table-component'
import { selectThemeColors } from '#utils'
import { Card, CardHeader, CardTitle, CardBody, Input, Row, Col, Label, CustomInput, Button } from 'reactstrap'
// ** Styles
import '#styles/react/libs/react-select/_react-select.scss'
import '#styles/react/libs/tables/react-dataTable-component.scss'
// ** Table Header
const CustomHeader = ({ toggleSidebar, handlePerPage, rowsPerPage, handleFilter, searchTerm }) => {
return (
<div className='invoice-list-table-header w-100 mr-1 ml-50 mt-2 mb-75'>
<Row>
<Col xl='6' className='d-flex align-items-center p-0'>
<div className='d-flex align-items-center w-100'>
<Label for='rows-per-page'>Show</Label>
<CustomInput
className='form-control mx-50'
type='select'
id='rows-per-page'
value={rowsPerPage}
onChange={handlePerPage}
style={{
width: '5rem',
padding: '0 0.8rem',
backgroundPosition: 'calc(100% - 3px) 11px, calc(100% - 20px) 13px, 100% 0'
}}
>
<option value='10'>10</option>
<option value='25'>25</option>
<option value='50'>50</option>
</CustomInput>
<Label for='rows-per-page'>Entries</Label>
</div>
</Col>
<Col
xl='6'
className='d-flex align-items-sm-center justify-content-lg-end justify-content-start flex-lg-nowrap flex-wrap flex-sm-row flex-column pr-lg-1 p-0 mt-lg-0 mt-1'
>
<div className='d-flex align-items-center mb-sm-0 mb-1 mr-1'>
<Label className='mb-0' for='search-invoice'>
Search:
</Label>
<Input
id='search-invoice'
className='ml-50 w-100'
type='text'
value={searchTerm}
onChange={e => handleFilter(e.target.value)}
/>
</div>
<Button.Ripple color='primary' onClick={toggleSidebar}>
Add New User
</Button.Ripple>
</Col>
</Row>
</div>
)
}
const UsersList = () => {
// ** Store Vars
const dispatch = useDispatch()
const store = useSelector(state => state.users)
// ** States
const [searchTerm, setSearchTerm] = useState('')
const [currentPage, setCurrentPage] = useState(1)
const [rowsPerPage, setRowsPerPage] = useState(10)
const [sidebarOpen, setSidebarOpen] = useState(false)
const [currentRole, setCurrentRole] = useState({ value: '', label: 'Select Role' })
const [currentPlan, setCurrentPlan] = useState({ value: '', label: 'Select Plan' })
const [currentStatus, setCurrentStatus] = useState({ value: '', label: 'Select Status', number: 0 })
// ** Function to toggle sidebar
const toggleSidebar = () => setSidebarOpen(!sidebarOpen)
// ** Get data on mount
useEffect(() => {
dispatch(getAllData())
dispatch(
getData({
page: currentPage,
perPage: rowsPerPage,
role: currentRole.value,
currentPlan: currentPlan.value,
status: currentStatus.value,
q: searchTerm
})
)
}, [dispatch, store.data.length])
// ** User filter options
const roleOptions = useSelector(state => state.users.roleOptions)
const statusOptions = [
{ value: '', label: 'Select Status', number: 0 },
{ value: '2', label: 'Pending', number: 1 },
{ value: '0', label: 'Active', number: 2 },
{ value: '1', label: 'Inactive', number: 3 }
]
// ** Function in get data on page change
const handlePagination = page => {
dispatch(
getData({
page: page.selected + 1,
perPage: rowsPerPage,
role: currentRole.value,
currentPlan: currentPlan.value,
status: currentStatus.value,
q: searchTerm
})
)
setCurrentPage(page.selected + 1)
}
// ** Function in get data on rows per page
const handlePerPage = e => {
const value = parseInt(e.currentTarget.value)
dispatch(
getData({
page: currentPage,
perPage: value,
role: currentRole.value,
currentPlan: currentPlan.value,
status: currentStatus.value,
q: searchTerm
})
)
setRowsPerPage(value)
}
// ** Function in get data on search query change
const handleFilter = val => {
setSearchTerm(val)
dispatch(
getData({
page: currentPage,
perPage: rowsPerPage,
role: currentRole.value,
currentPlan: currentPlan.value,
status: currentStatus.value,
q: val
})
)
}
// ** Custom Pagination
const CustomPagination = () => {
const count = Number(Math.ceil(store.total / rowsPerPage))
return (
<ReactPaginate
previousLabel={''}
nextLabel={''}
pageCount={count || 1}
activeClassName='active'
forcePage={currentPage !== 0 ? currentPage - 1 : 0}
onPageChange={page => handlePagination(page)}
pageClassName={'page-item'}
nextLinkClassName={'page-link'}
nextClassName={'page-item next'}
previousClassName={'page-item prev'}
previousLinkClassName={'page-link'}
pageLinkClassName={'page-link'}
containerClassName={'pagination react-paginate justify-content-end my-2 pr-1'}
/>
)
}
// ** Table data to render
const dataToRender = () => {
const filters = {
role: currentRole.value,
currentPlan: currentPlan.value,
status: currentStatus.value,
q: searchTerm
}
const isFiltered = Object.keys(filters).some(function (k) {
return filters[k].length > 0
})
if (store.data.length > 0) {
return store.data
} else if (store.data.length === 0 && isFiltered) {
return []
} else {
return store.allData.slice(0, rowsPerPage)
}
}
// ** Opening modal
const openModal= (row) => {
//Here i need to get the value
console.log(openModal)
}
return (
<Fragment>
<Card>
<CardHeader>
<CardTitle tag='h4'>User Lists</CardTitle>
</CardHeader>
<CardBody>
<Row>
<Col md='4'>
<Select
isClearable={false}
theme={selectThemeColors}
className='react-select'
classNamePrefix='select'
options={roleOptions}
value={currentRole}
onChange={data => {
setCurrentRole(data)
dispatch(
getData({
page: currentPage,
perPage: rowsPerPage,
role: data.value,
currentPlan: currentPlan.value,
status: currentStatus.value,
q: searchTerm
})
)
}}
/>
</Col>
<Col md='4'>
<Select
theme={selectThemeColors}
isClearable={false}
className='react-select'
classNamePrefix='select'
options={statusOptions}
value={currentStatus}
onChange={data => {
setCurrentStatus(data)
dispatch(
getData({
page: currentPage,
perPage: rowsPerPage,
role: currentRole.value,
currentPlan: currentPlan.value,
status: data.value,
q: searchTerm
})
)
}}
/>
</Col>
</Row>
</CardBody>
</Card>
<Card>
<DataTable
noHeader
pagination
subHeader
responsive
paginationServer
columns={columns(openModal)}
sortIcon={<ChevronDown />}
className='react-dataTable'
paginationComponent={CustomPagination}
data={dataToRender()}
subHeaderComponent={
<CustomHeader
toggleSidebar={toggleSidebar}
handlePerPage={handlePerPage}
rowsPerPage={rowsPerPage}
searchTerm={searchTerm}
handleFilter={handleFilter}
/>
}
/>
</Card>
<Sidebar open={sidebarOpen} toggleSidebar={toggleSidebar} />
</Fragment>
)
}
export default UsersList
I'm trying to implement this in react-hook project. Need to get resolved to open the modal and data need to be showed in modal.Tried everything and need to call useState() for define modal but in column.js its showing its violation of hooks components also its just need to export the column so need to get the openModal() event trgger in Table.js
Your code will look like this:
**column.js**
// ** React Imports
import { Link } from 'react-router-dom'
// ** Custom Components
import Avatar from '#components/avatar'
// ** Store & Actions
import { getUser, deleteUser } from '../store/action'
import { store } from '#store/storeConfig/store'
import { useSelector } from 'react-redux'
// ** Third Party Components
import { Badge, UncontrolledDropdown, DropdownToggle, DropdownMenu, DropdownItem } from 'reactstrap'
import { Slack, User, Settings, Database, Edit2, MoreVertical, FileText, Trash2, Archive } from 'react-feather'
export const columns = (openModal) => [
{
name: '#',
maxWidth: '3px',
selector: 'serial',
sortable: true,
cell: (row, index) => (renderSerialNo(index))
},
{
name: 'User',
minWidth: '138px',
selector: 'user',
sortable: true,
cell: row => (
<Badge className='text-capitalize' color={statusObj[row.user_status]} pill>
{row.user_status_text}
</Badge>
)
},
{
name: 'Actions',
minWidth: '10px',
cell: row => (
<UncontrolledDropdown>
<DropdownItem className='w-100' onClick={() => openModal(row)}>
<Trash2 size={14} className='mr-50' />
<span className='align-middle'>Delete</span>
</DropdownItem>
</DropdownMenu>
</UncontrolledDropdown>
)
}
]```
**Table.js**
```// ** React Imports
import { Fragment, useState, useEffect } from 'react'
// ** Columns
import { columns } from './columns'
// ** Store & Actions
import { getAllData, getData } from '../store/action'
import { useDispatch, useSelector } from 'react-redux'
// ** Third Party Components
import Select from 'react-select'
import ReactPaginate from 'react-paginate'
import { ChevronDown } from 'react-feather'
import DataTable from 'react-data-table-component'
import { selectThemeColors } from '#utils'
import { Card, CardHeader, CardTitle, CardBody, Input, Row, Col, Label, CustomInput, Button } from 'reactstrap'
// ** Styles
import '#styles/react/libs/react-select/_react-select.scss'
import '#styles/react/libs/tables/react-dataTable-component.scss'
const UsersList = () => {
// ** Store Vars
const dispatch = useDispatch()
const store = useSelector(state => state.users)
// ** Get data on mount
useEffect(() => {
dispatch(getAllData())
dispatch(
getData()
)
}, [dispatch, store.data.length])
// ** User filter options
const roleOptions = useSelector(state => state.users.roleOptions)
const openModal= e => {
//need to get the value here
console.log(e)
}
...
return (
<Fragment>
<Card>
<DataTable
responsive
paginationServer
columns={columns(openModal)}
sortIcon={<ChevronDown />}
className='react-dataTable'
paginationComponent={CustomPagination}
data={dataToRender()}
}
/>
</Card>
<Sidebar open={sidebarOpen} toggleSidebar={toggleSidebar} />
</Fragment>
)
}
export default UsersList