chart js + typescript leading to Can't resolve 'react-server-dom-webpack' - reactjs

Here is my page.tsx file
import Image from 'next/image'
import styles from './page.module.css'
import React, { forwardRef } from 'react';
import { useRouter } from 'next/router'
import {Line} from 'react-chartjs-2';
import { ChartData } from 'chart.js';
export default function Home() {
const data: ChartData<'line', number[], string> = {
labels: ['0.5', '1', '1.5', '2', '2.5', '3', '3.5'],
datasets: [
{
label: 'My First dataset',
fill: false,
backgroundColor: 'rgba(75,192,192,0.4)',
borderColor: 'rgba(75,192,192,1)',
borderCapStyle: 'butt',
borderDash: [],
borderDashOffset: 0.0,
borderJoinStyle: 'miter',
pointBorderColor: 'rgba(75,192,192,1)',
pointBackgroundColor: '#fff',
pointBorderWidth: 1,
pointHoverRadius: 5,
pointHoverBackgroundColor: 'rgba(75,192,192,1)',
pointHoverBorderColor: 'rgba(220,220,220,1)',
pointHoverBorderWidth: 2,
pointRadius: 1,
pointHitRadius: 10,
data: [65, 59, 80, 81, 56, 55, 40]
}
]
};
function handleFirebase(): number {
return 1
}
return (
<main className={styles.main}>
<nav className="bg-white px-2 sm:px-4 py-2.5 dark:bg-gray-900 fixed w-full z-20 top-0 left-0 border-b border-gray-200 dark:border-gray-600">
<div className="container flex flex-wrap items-center justify-between mx-auto">
<a href="https://flowbite.com/" className="flex items-center">
<span className="self-center text-xl font-semibold whitespace-nowrap dark:text-white">Water</span>
</a>
<div className="items-center justify-between hidden w-full md:flex md:w-auto md:order-1" id="navbar-sticky">
<ul className="flex flex-col p-4 mt-4 border border-gray-100 rounded-lg bg-gray-50 md:flex-row md:space-x-8 md:mt-0 md:text-sm md:font-medium md:border-0 md:bg-white dark:bg-gray-800 md:dark:bg-gray-900 dark:border-gray-700">
<li>
</li>
<li>
About
</li>
<li>
</li>
</ul>
</div>
</div>
</nav>
<div className="flex md:order-2 left-10">
<div className="relative w-full lg:max-w-sm left-10">
<select className="w-full p-6 text-gray-500 bg-white border rounded-md shadow-sm outline-none appearance-none focus:border-indigo-600 left-10">
<option>Home</option>
<option>Work</option>
<option>School</option>
<option>Balls</option>
</select>
</div>
</div>
<div>
<h2>Line Example</h2>
<Line
data={data}
width={400}
height={400}
/>
</div>
</main>
)
}
Here is my ./node_modules/react-chartjs-2/dist/index.js
import { Chart as Chart$1, LineController, BarController, RadarController, DoughnutController, PolarAreaController, BubbleController, PieController, ScatterController } from 'chart.js';
// Import `useClient` from `react-server-dom-webpack`
const defaultDatasetIdKey = "label";
function reforwardRef(ref, value) {
if (typeof ref === "function") {
ref(value);
} else if (ref) {
ref.current = value;
}
}
function setOptions(chart, nextOptions) {
const options = chart.options;
if (options && nextOptions) {
Object.assign(options, nextOptions);
}
}
function setLabels(currentData, nextLabels) {
currentData.labels = nextLabels;
}
function setDatasets(currentData, nextDatasets, datasetIdKey = defaultDatasetIdKey) {
const addedDatasets = [];
currentData.datasets = nextDatasets.map((nextDataset) => {
// given the new set, find it's current match
const currentDataset = currentData.datasets.find((dataset) => dataset[datasetIdKey] === nextDataset[datasetIdKey]);
// There is no original to update, so simply add new one
if (!currentDataset || !nextDataset.data || addedDatasets.includes(currentDataset)) {
return {
...nextDataset
};
}
addedDatasets.push(currentDataset);
Object.assign(currentDataset, nextDataset);
return currentDataset;
});
}
function cloneData(data, datasetIdKey = defaultDatasetIdKey) {
const nextData = {
labels: [],
datasets: []
};
setLabels(nextData, data.labels);
setDatasets(nextData, data.datasets, datasetIdKey);
return nextData;
}
/**
* Get dataset from mouse click event
* #param chart - Chart.js instance
* #param event - Mouse click event
* #returns Dataset
*/
function getDatasetAtEvent(chart, event) {
return chart.getElementsAtEventForMode(event.nativeEvent, "dataset", {
intersect: true
}, false);
}
/**
* Get single dataset element from mouse click event
* #param chart - Chart.js instance
* #param event - Mouse click event
* #returns Dataset
*/ function getElementAtEvent(chart, event) {
return chart.getElementsAtEventForMode(event.nativeEvent, "nearest", {
intersect: true
}, false);
}
/**
* Get all dataset elements from mouse click event
* #param chart - Chart.js instance
* #param event - Mouse click event
* #returns Dataset
*/ function getElementsAtEvent(chart, event) {
return chart.getElementsAtEventForMode(event.nativeEvent, "index", {
intersect: true
}, false);
}
function ChartComponent(props, ref) {
const { height =150 , width =300 , redraw =false , datasetIdKey , type , data , options , plugins =[] , fallbackContent , updateMode , ...canvasProps } = props;
const canvasRef = useRef(null);
const chartRef = useRef();
const renderChart = ()=>{
if (!canvasRef.current) return;
chartRef.current = new Chart$1(canvasRef.current, {
type,
data: cloneData(data, datasetIdKey),
options: options && {
...options
},
plugins
});
reforwardRef(ref, chartRef.current);
};
const destroyChart = ()=>{
reforwardRef(ref, null);
if (chartRef.current) {
chartRef.current.destroy();
chartRef.current = null;
}
};
useEffect(()=>{
if (!redraw && chartRef.current && options) {
setOptions(chartRef.current, options);
}
}, [
redraw,
options
]);
useEffect(()=>{
if (!redraw && chartRef.current) {
setLabels(chartRef.current.config.data, data.labels);
}
}, [
redraw,
data.labels
]);
useEffect(()=>{
if (!redraw && chartRef.current && data.datasets) {
setDatasets(chartRef.current.config.data, data.datasets, datasetIdKey);
}
}, [
redraw,
data.datasets
]);
useEffect(()=>{
if (!chartRef.current) return;
if (redraw) {
destroyChart();
setTimeout(renderChart);
} else {
chartRef.current.update(updateMode);
}
}, [
redraw,
options,
data.labels,
data.datasets,
updateMode
]);
useEffect(()=>{
if (!chartRef.current) return;
destroyChart();
setTimeout(renderChart);
}, [
type
]);
useEffect(()=>{
renderChart();
return ()=>destroyChart();
}, []);
return /*#__PURE__*/ React.createElement("canvas", Object.assign({
ref: canvasRef,
role: "img",
height: height,
width: width
}, canvasProps), fallbackContent);
}
const Chart = /*#__PURE__*/ forwardRef(ChartComponent);
function createTypedChart(type, registerables) {
Chart$1.register(registerables);
return /*#__PURE__*/ forwardRef((props, ref)=>/*#__PURE__*/ React.createElement(Chart, Object.assign({}, props, {
ref: ref,
type: type
})));
}
const Line = /* #__PURE__ */ createTypedChart("line", LineController);
const Bar = /* #__PURE__ */ createTypedChart("bar", BarController);
const Radar = /* #__PURE__ */ createTypedChart("radar", RadarController);
const Doughnut = /* #__PURE__ */ createTypedChart("doughnut", DoughnutController);
const PolarArea = /* #__PURE__ */ createTypedChart("polarArea", PolarAreaController);
const Bubble = /* #__PURE__ */ createTypedChart("bubble", BubbleController);
const Pie = /* #__PURE__ */ createTypedChart("pie", PieController);
const Scatter = /* #__PURE__ */ createTypedChart("scatter", ScatterController);
export { Bar, Bubble, Chart, Doughnut, Line, Pie, PolarArea, Radar, Scatter, getDatasetAtEvent, getElementAtEvent, getElementsAtEvent };
//# sourceMappingURL=index.js.map
After running npm run dev I get this error
` Failed to compile
./node_modules/react-chartjs-2/dist/index.js:4:0
Module not found: Can't resolve 'react-server-dom-webpack'
Import trace for requested module:
./src/app/page.tsx
https://nextjs.org/docs/messages/module-not-found`
Im attempting to make a chart render on my page.tsx file and im not really sure what index.js does so right now im assuming its auto generated by chart.js. Im currently attempting to make a line chart render with the respective data points in the const data

Below are the possibilities,
Try with downgrade chartjs version to 3.x.x
Install types also like #types/react-server-dom-webpack
Do npm i properly if any of module pending

Related

(fullcalendar) Unknown option 'schedulerLicenseKey' , Unknown option 'resources'

I'm developing a project for which I'm using #fullcalendar/react the problem that I'm facing is that I want to use 'resourceTimeGridDay' but the when I run the my project it says in the console that Unknown option 'schedulerLicenseKey' , Unknown option 'resources', the project is an update of old version where the other company were using the schedulerLicenseKey which I do have, the above warning even appears on schedulerLicenseKey: 'GPL-My-Project-Is-Open-Source', open source...
the versions that i'm using for the updated version of the project are
"#fullcalendar/core": "^6.1.1",
"#fullcalendar/daygrid": "^5.11.0",
"#fullcalendar/interaction": "^5.11.0",
"#fullcalendar/list": "^5.11.0",
"#fullcalendar/react": "^5.11.1",
"#fullcalendar/resource": "^6.1.1",
"#fullcalendar/resource-daygrid": "^6.1.1",
"#fullcalendar/resource-timegrid": "^6.1.1",
"#fullcalendar/resource-timeline": "^6.1.1",
"#fullcalendar/timegrid": "^5.11.0",
"#fullcalendar/timeline": "^5.11.0",
and old version where I'm getting the from are:
"#fullcalendar/core": "^4.3.1",
"#fullcalendar/daygrid": "^4.3.0",
"#fullcalendar/interaction": "^4.3.0",
"#fullcalendar/resource-timegrid": "^4.3.0",
"#fullcalendar/timegrid": "^4.3.0",
Below is my code for the calendar.
/* eslint-disable no-unused-vars */
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { getDurations } from '#utils'
// ** Reactstrap
import { Card, CardBody, Input, FormGroup, Label } from 'reactstrap'
// ** Calendar Plugins
import Flatpickr from 'react-flatpickr'
import FullCalendar from '#fullcalendar/react'
import listPlugin from '#fullcalendar/list'
import dayGridPlugin from '#fullcalendar/daygrid'
import timeGridPlugin from '#fullcalendar/timegrid'
import interactionPlugin from '#fullcalendar/interaction'
import resourceTimeGridPlugin from '#fullcalendar/resource-timegrid'
// import resourceTimelinePlugin from '#fullcalendar/resource-timeline'
// import resourceDayGridPlugin from '#fullcalendar/resource-daygrid'
// import '#fullcalendar/core/main.css'
import '#fullcalendar/daygrid/main.css'
import '#fullcalendar/timegrid/main.css'
// ** Third Party Components
import moment from 'moment'
import { Menu } from 'react-feather'
import * as Icon from 'react-feather'
import useMediaQuery from '#src/utility/hooks/useMediaQuery'
// ** Custom Components
import SelectField from '#select'
import CustomSpinner from '#spinner'
import Avatar from '#components/avatar'
import AddEventSideBar from './AddEventSideBar'
import defaultAvatar from '#src/assets/default.png'
// ** Styles
import '#styles/react/apps/app-calendar.scss'
// ** Store & Actions
import { useDispatch, useSelector } from 'react-redux'
import { resetBookings } from '#store/booking/bookingSlice'
import { getAllRoomsAction } from '#store/rooms/roomsAction'
import { getAllLocationsAction } from '#store/locations/locationsAction'
import {
getAllBookingsAction,
getBookingByIdAction
} from '#store/booking/bookingsAction'
const calendarsColor = {
'Ethera Isaac': 'admin',
'Ethera OC': 'admin',
'Ethera Irvine': 'admin'
}
function Calendar() {
const dispatch = useDispatch()
const calendarRef = useRef(null)
const isMobile = useMediaQuery('(max-width: 600px)')
const smallScreen = useMediaQuery('(min-width: 900px)')
const largeScreen = useMediaQuery('(min-width: 1350px)')
// ** Selectors
const {
success,
loading,
getBooking,
getAllBookings,
bookingPending,
updatePending
} = useSelector((state) => state.booking)
const getAllRooms = useSelector((state) => state.rooms.getAllRooms?.roomsList)
const roomsPending = useSelector((state) => state.rooms.loading)
const getAllLocations = useSelector(
(state) => state.locations.getAllLocations?.locationsList
)
const locationsPending = useSelector(
(state) => state.locations.getAllLocations?.loading
)
const rows = getAllBookings?.bookingsList
// ** States
const [room, setRoom] = useState()
const [endDate, setEndDate] = useState('')
const [location, setLocation] = useState()
const [startDate, setStartDate] = useState('')
const [roomsList, setRoomsList] = useState([])
const [allRooms, setAllRooms] = useState(false)
const [eventsList, setEventsList] = useState([])
const [calendarApi, setCalendarApi] = useState(null)
const [locationsList, setLocationsList] = useState([])
const [addSidebarOpen, setAddSidebarOpen] = useState(false)
const [allRoomsDayGrid, setAllRoomsDayGrid] = useState(true)
// ** Rooms Resources
const resources = useMemo(() => {
return roomsList
.map((room) => {
return { id: room.value, title: room.text }
})
.filter((_, index) => index !== 0)
}, [roomsList])
// ** Function to handle sidebar visibility
const handleAddAppointmentSidebar = (id) => {
setAddSidebarOpen(!addSidebarOpen)
if (id && addSidebarOpen === false) {
dispatch(getBookingByIdAction(id))
}
}
useEffect(() => {
if (calendarApi === null) {
setCalendarApi(calendarRef.current.getApi())
}
}, [calendarApi])
// ** Getting Bookings
useEffect(() => {
if (location?.value) {
dispatch(
getAllBookingsAction({
offset: 0,
limit: 100,
startDate,
endDate,
location: location?.value,
room: room?.value,
callback: () => setEventsList([])
})
)
}
}, [endDate, location, room, success])
// ** Getting Locations
useEffect(() => {
dispatch(getAllLocationsAction())
}, [])
// ** Getting Rooms
useEffect(() => {
if (location?.value) {
dispatch(getAllRoomsAction({ id: location?.value }))
}
}, [location?.value])
// ** Creating Locations and Rooms lists
useEffect(() => {
if (getAllLocations) {
const arrLocations = []
getAllLocations.forEach((item) => {
arrLocations.push({
text: item?.name,
value: item.id
})
})
setLocation(arrLocations[0])
setLocationsList(arrLocations)
}
}, [getAllLocations])
useEffect(() => {
if (getAllRooms) {
const arrRooms = [{ text: 'All Rooms', value: '' }]
getAllRooms.forEach((item) => {
arrRooms.push({
text: item?.name,
value: item.id
})
})
// setRoom(arrRooms[0])
setRoomsList(arrRooms)
}
}, [getAllRooms])
// ** Date Picker
const onDateChangeHandler = (dates) => {
if (dates.length === 1) {
setStartDate(dates[0])
calendarRef.current.getApi().gotoDate(new Date(dates[0]))
}
if (dates.length === 2) {
setStartDate(dates[0])
setEndDate(dates[1])
calendarRef.current.getApi().gotoDate(new Date(dates[1]))
}
}
// ** Function to handle filters
const onChangeHandler = (name, value) => {
if (name === 'location') setLocation(value)
if (name === 'room') setRoom(value)
}
const events = () => {
let events = []
const durations = getDurations(rows)
console.log('durations : ', durations)
if (rows.length > 0 && room?.value) {
events = rows.map((row) => {
return {
allDay: false,
url: '',
start: `${row?.start_date__date}T${row?.start_time}`,
end: `${row?.start_date__date}T${row?.end_time}`,
title: `${row?.provider__first_name} ${row?.provider__last_name}`,
extendedProps: {
id: row?.id,
date: row?.start_date__date,
calendar: 'Ethera OC',
img: row?.provider__avatar,
end_time: row?.appointments__end_time || '--',
start_time: row?.appointments__start_time || '--',
duration: `${row?.duration / 3600} hours`
}
}
})
}
if (rows.length > 0 && durations.length > 0 && !room?.value) {
durations.map((durationArr, index) => {
let sum = 0
durationArr.forEach((item) => {
sum += parseFloat(item)
})
events.push({
allDay: false,
url: '',
id: `${index}`,
start: `${rows[index]?.start_date__date}T${rows[index]?.start_time}`,
end: `${rows[index]?.start_date__date}T${rows[index]?.end_time}`,
title: `${sum / 3600}`,
extendsProps: {
start: `${rows[index]?.start_date__date}T${rows[index]?.start_time}`,
end: `${rows[index]?.start_date__date}T${rows[index]?.end_time}`,
calendar: 'Ethera OC'
}
})
})
}
return events
}
useEffect(() => {
setEventsList(events())
}, [rows])
// ** Duration Component
const DurationComponent = ({ calendarEvent }) => {
return (
<div className="fc-event-title">
<div className="fc-event-time">
{smallScreen ? (
<span className="fc-event-time-text f-700 fs-s-med">
<Icon.Clock color="black" size={20} className="me-1" />
{calendarEvent?._def?.title} Hours
</span>
) : (
<span className="fc-event-time-text f-700 fs-s-med">
{calendarEvent?._def?.title} H
</span>
)}
</div>
</div>
)
}
// ** View component
const ViewComponent = ({ calendarEvent, id }) => {
const nameImage = `https://ui-avatars.com/api/? name=${calendarEvent?.title}&background=0D8ABC&color=fff&size=128`
return (
<div
className="fc-event d-flex align-items-center justify-content-between"
// onClick={() => handleAddAppointmentSidebar(id)}
onClick={() => handleAddAppointmentSidebar(id)}
>
<div className="fc-event-title">
<div className="fc-event-time">
<span className="fc-event-time-text">
{(calendarEvent?.extendedProps?.start_time !== '--' &&
moment(
calendarEvent?.extendedProps?.start_time,
'HH:mm:ss'
).format('hh:mm A')) ||
'--'}
{' - '}
{(calendarEvent?.extendedProps?.end_time !== '--' &&
moment(
calendarEvent?.extendedProps?.end_time,
'HH:mm:ss'
).format('hh:mm A')) ||
'--'}
</span>
</div>
<div className="fc-event-title-text">
<span className="fc-event-title-text-text f-700 fs-s-med">
{calendarEvent?.title}
</span>
</div>
</div>
<Avatar
className="provider-avatar-calendar"
// img={calendarEvent?.extendedProps?.img || defaultAvatar}
img={calendarEvent?.extendedProps?.img || nameImage}
imgHeight={smallScreen ? '35' : '30'}
imgWidth={smallScreen ? '35' : '30'}
/>
</div>
)
}
// ** Calendar Options
const calendarOptions = {
schedulerLicenseKey: 'GPL-My-Project-Is-Open-Source',
// resources,
resources: [
{ id: 'a', title: 'Resource A' },
{ id: 'b', title: 'Resource B' },
{ id: 'c', title: 'Resource C' }
],
eventSources: [
{
events: eventsList,
textColor: 'black'
}
],
// events: appointments,
plugins: [
interactionPlugin,
resourceTimeGridPlugin,
dayGridPlugin,
timeGridPlugin,
listPlugin
],
// initialView: 'timeGridWeek',
initialView: 'timeGridDay',
headerToolbar: {
start: (() => {
if (isMobile) {
return 'title, prev, next'
} else return 'title, prev, next, timeGridDay,timeGridWeek,dayGridMonth'
})(),
center: (() => {
if (isMobile) {
return 'dayGridMonth,timeGridWeek,timeGridDay'
} else return ''
})(),
end: 'venueSelect'
},
eventOverlap: false,
ref: calendarRef,
editable: false,
dayMaxEvents: 2,
eventResizableFromStart: true,
dragScroll: true,
navLinks: true,
selectable: true,
views: {
timeGridDay: {
type: 'timeGrid',
duration: { days: 1 },
slotDuration: '00:30:00',
slotLabelInterval: '00:30:00',
slotLabelFormat: {
hour: 'numeric',
minute: '2-digit',
omitZeroMinute: false,
meridiem: 'short'
},
slotMinTime: '00:00:00',
slotMaxTime: '24:00:00',
allDaySlot: true,
dayHeaderContent: (arg) => {
// console.log('get all rooms', arg)
return (
<div className="fc-daygrid-day-top">
<div className="fc-daygrid-day-number">
{moment(arg.date).format('MMMM D, YYYY')}
</div>
</div>
)
},
eventContent: (arg) => {
return <ViewComponent calendarEvent={arg.event} id={arg.event.id} />
},
eventDidMount: (arg) => {
// console.log('eventDidMount', arg)
setAllRoomsDayGrid(false)
},
eventWillUnmount: (arg) => {
// console.log('eventWillUnmount', arg)
},
eventTimeFormat: {
hour: 'numeric',
minute: '2-digit',
omitZeroMinute: false,
meridiem: 'short'
}
}
},
customButtons: {
sidebarToggle: {
text: <Menu className="d-xl-none d-block" />,
click() {
toggleSidebar(true)
}
},
venueSelect: {
hint: 'Select',
text: (
<div className="calendar-selectors">
<SelectField
header
wd="100%"
search={false}
value={location}
data={locationsList}
controlMaxWidth="270px"
onChange={(e) => {
onChangeHandler('location', e)
onChangeHandler('room', null)
}}
controlMinWidth={largeScreen ? '230px' : '100%'}
placeholder={locationsPending ? 'Loading...' : 'Locations'}
/>
{allRoomsDayGrid && (
<SelectField
header
wd="100%"
value={room}
search={false}
data={roomsList}
controlMaxWidth="270px"
disabled={roomsPending}
isLoading={roomsPending}
formikError={!!room?.value === ''}
onChange={(e) => onChangeHandler('room', e)}
controlMinWidth={largeScreen ? '230px' : '100%'}
placeholder={
location?.value ? 'Select Room' : 'Select Location First'
}
/>
)}
</div>
)
}
},
eventClassNames({ event: calendarEvent }) {
const colorName =
calendarsColor[calendarEvent?.extendedProps?.calendar] || 'admin'
return [`bg-light-${colorName}`]
},
// eventClick({ event: clickedAppointment }) {
// const id = clickedAppointment?.extendedProps?.id
// handleAddAppointmentSidebar(id)
// },
eventContent({ event: calendarEvent }) {
const day = calendarEvent?._context?.viewApi?.type === 'timeGridDay'
const month = calendarEvent?._context?.viewApi?.type === 'dayGridMonth'
const week = calendarEvent?._context?.viewApi?.type === 'timeGridWeek'
const nameImage = `https://ui-avatars.com/api/?name=${calendarEvent?.title}&background=0D8ABC&color=fff&size=128`
if ((month || week) && !room?.value) {
return <DurationComponent calendarEvent={calendarEvent} />
}
if ((week || month) && room?.value) {
return (
<div className="event-small">
{isMobile ? (
<span className="f-calendar-small">{calendarEvent?.title}</span>
) : !smallScreen ? (
<div className="fc-event d-flex align-items-center justify-content-between">
<div className="fc-event-title">
<span className="f-calendar-small">
{calendarEvent?.title}
</span>
</div>
<Avatar
className="provider-avatar-calendar"
img={calendarEvent?.extendedProps?.img || nameImage}
imgHeight="25"
imgWidth="25"
/>
</div>
) : (
<ViewComponent
calendarEvent={calendarEvent}
id={calendarEvent?._def?.extendedProps?.id}
/>
)}
</div>
)
}
if (day) {
return (
<ViewComponent
calendarEvent={calendarEvent}
id={calendarEvent?._def?.extendedProps?.id}
/>
)
}
}
}
// ** Reset Bookings
useEffect(() => {
return () => {
dispatch(resetBookings())
}
}, [])
return (
<>
<AddEventSideBar
open={addSidebarOpen}
pending={bookingPending}
updatePending={updatePending}
selectedBooking={getBooking}
locationsList={locationsList}
handleOpen={handleAddAppointmentSidebar}
/>
<Card className="shadow-none border-0 mb-0 bg-yellow rounded-0">
<CardBody className="p-0 relative">
<Label htmlFor="datePicker">
<Icon.Calendar
color="white"
size={30}
className="absolute datePicker-icon pointer"
/>
</Label>
<FullCalendar {...calendarOptions} />{' '}
<Flatpickr
id="datePicker"
name="datePicker"
className="form-control datePicker-non-visible"
onChange={onDateChangeHandler}
options={{
mode: 'range',
enableTime: false,
dateFormat: 'F j, Y'
}}
/>
</CardBody>
</Card>
</>
)
}
export default Calendar
so in the calendar what I'm doing is fetching locations and bookings on that location from an API, once the api's get fetched, on the Month, and Week calendar I will have to show total hours of the bookings on that day, if the room is selected then it will only fetch the bookings of that room on different dates, for which the month and week calendar events also gets changed, but on the day calendar I will have to show all the rooms in the header as resources so that it can show all the bookings on that day in different rooms...
also when changing "timeGridDay" to "resourceTimeGridDay" it gives me the error Uncaught Error: viewType "resourceTimeGridDay" is not available. Please make sure you've loaded all neccessary plugins
initialView: 'timeGridDay',
headerToolbar: {
start: (() => {
if (isMobile) {
return 'title, prev, next'
} else return 'title, prev, next, timeGridDay,timeGridWeek,dayGridMonth'
})(),
center: (() => {
if (isMobile) {
return 'dayGridMonth,timeGridWeek,timeGridDay'
} else return ''
})(),
end: 'venueSelect'
},
if any one can help me with this issue of "Unknow option schedulerLicenseKey" and "Unknow option resources".
Thank you in advance
Check this issue : https://github.com/fullcalendar/fullcalendar/issues/5462
import { BASE_OPTION_REFINERS, BASE_OPTION_DEFAULTS } from '#fullcalendar/core'
BASE_OPTION_REFINERS.schedulerLicenseKey = String
BASE_OPTION_DEFAULTS.schedulerLicenseKey = 'GPL-My-Project-Is-Open-Source'

ApexCharts Pie/donut charts are not appearing correctly

I'm having a problem with Pie/donut charts in Apex Charts in my React App,
Basically I'm fetching data from google analytics and trying to display it on a pie/donut chart but the chart doesn't render completly like this:
instead it appears like this :
as you can see I get those little "Lines" instead of the full graph and also it works fine if I get one value from the api,
this is the component code :
import axios from "axios"
import { useQuery } from "react-query"
import ReactApexChart from "react-apexcharts";
import { ApexOptions } from "apexcharts";
import Spinner from "../../utils/Spinner/Spinner";
const VisitedPages = () => {
const { data, isLoading } = useQuery("visitedPages", () => {
return axios.post('http://localhost:8000/ga/getRealTimeReport', {
metrics: 'rt:activeUsers',
dimensions: 'rt:pagePath',
})
});
const labels= data?.data.data.dimensions.map((e: string[]) => e[0]);
const options = {
labels,
theme: {
monochrome: {
enabled: false
}
},
responsive: [
{
breakpoint: 480,
options: {
chart: {
width: "100%"
},
legend: {
show: false
}
}
}
],
};
const series = data?.data.data.dimensions.map((e: string[]) => e[1]);
return (
<div className="col-span-2 bg-white rounded-lg shadow-xl flex flex-col justify-center items-center">
{isLoading ? <Spinner /> : <><h1 className="text-3xl font-bold">Visited Pages</h1>
<ReactApexChart type="pie" options={options} series={series} /></>}
</div>
)
}
export default VisitedPages
Ps: I tried it with constant values and it works just fine Idk what's the problem...
the problem was that the api returns the values as strings so all you have to do is to convert them into numbers
all you have to do is to change this line :
const series = data?.data.data.dimensions.map((e: string[]) => e[1]);
into :
const series = data?.data.data.dimensions.map((e: string[]) => +e[1]);
it's weird cause other charts works fine with string results

WYS is not WYG in React Quill

I started to integrate a WYSIWYG into my blog project by using React Quill and I have no experience with it before and tried to do the most from the help of internet. Actually everything is working fine from loading images(using Image Handler) to saving it to database(PostgreSQL in Rails).I am saving the contents in HTML and not in Delta format but whenever i try to view it by loading it from database, all the formatting, alignment, and indentation are all gone but (header, italic, underline, bold, text-color) are present ,and everything is left aligned
Any help would be appreciated.
I read the Quill documentation and tried to understand how to deal with this but I don't know how to make this work.
I'm using React + Rails
this is my code (I'll show only relevant code):
CreateBlog.jsx file
import axios from 'axios'
import React, { useState } from "react";
import PageLoader from '../PageLoader'
import CreateForm from './CreateForm'
export default function CreateBlog({history}) {
const [title, setTitle] = useState("")
const [body, setBody] = useState("")
const [loading, setLoading] = useState(false)
const handleChange = (value)=>{
setBody(value)
console.log(value)
}
const handleSubmit = async (event) => {
event.preventDefault()
const variables = {
title: title,
body: body,
}
try{
const response = await axios.post("/blogs",variables)
setLoading(false)
history.push("/blogs")
} catch(error){
console.log(error)
setLoading(false)
}
}
return (
<CreateForm
setTitle={setTitle}
setBody={setBody}
body={body}
loading={loading}
handleSubmit={handleSubmit}
handleChange={handleChange}
/>
)
}
CreateForm.jsx file
import React,{useMemo,useRef} from 'react'
import Input from '../Input'
import Button from '../Button'
import 'react-quill/dist/quill.snow.css'
import ReactQuill,{Quill} from "react-quill";
import ImageResize from 'quill-image-resize-module-react';
import Editor from "./Editor";
Quill.register('modules/imageResize', ImageResize);
export default function CreateForm(
{
type="create",
setTitle,setBody,loading,handleSubmit,
handleChange,body
}) {
const editorRef = useRef(null);
const modules = useMemo(()=>({
imageResize: {
parchment: Quill.import('parchment'),
modules: ['Resize', 'DisplaySize', 'Toolbar']
},
toolbar:{
container: [
[{ 'header': [1, 2, 3, 4, 5, 6, false] }],
['bold', 'italic', 'underline'],
[
{ 'list': 'ordered' },
{ 'list': 'bullet' },
{ 'indent': "-1" },
{ 'indent': "+1" }
],
[{ 'align': [] }],
['link', 'image', 'video'],
['clean'],
[{ 'color': [] }]
],
handlers: {
image: imageHandler,
},
clipboard: {
matchVisual: false,
}
}
}));
const imageHandler = (a) => {
const input = document.createElement("input");
input.setAttribute("type", "file");
input.setAttribute("accept", "image/*");
input.click();
input.onchange = () => {
const file = input.files[0];
// file type is only image.
if (/^image\//.test(file.type)) {
console.log("image file type",file)
saveToServer(file);
} else {
console.warn("You could only upload images.");
}
};
};
function saveToServer(file) {
const fd = new FormData();
fd.append("upload", file);
const xhr = new XMLHttpRequest();
xhr.open("POST", "/blogs", true);
xhr.upload.onprogress = function(event){
const progress =event.loaded / event.total * 100;
}
xhr.onload = () => {
if (xhr.status === 201) {
const data = JSON.parse(xhr.responseText);
const url = data.url
console.log("Image url",url)
setImage(url)
insertToEditor(url);
}
};
xhr.send(fd);
console.log("formdata",fd)
}
function insertToEditor(url) {
editorRef.current.getEditor().insertEmbed(null, "image", url);
}
return (
<form className="max-w-full" onSubmit={handleSubmit}>
<Input
label="Title"
placeholder="Blog Title (Max 50 Characters Allowed)"
onChange={e => setTitle(e.target.value)}
/>
<ReactQuill
theme="snow"
placeholder="Write your story"
modules={modules}
forwardedRef={editorRef}
onChange={handleChange}
value={body}
/>
<Button
type="submit"
buttonText={type === "create" ? "Create Blog" : "Update Blog"}
loading={loading}
/>
</form>
)
}
Everything is working perfectly when i am editing the contents
like the one in this image
While editing
But after saving the post and again viewing it ,
its something like this (but bold, italics, underline) are showing as desired but ordered lists nand unordered lists, alignment, quotes... etc are not showing as desired.
View after saving
For viewing the contents code is
ShowBlog.jsx
import React,{useState,useEffect} from 'react'
import { useParams } from 'react-router-dom'
import blogsApi from '../apis/blogs'
import axios from 'axios'
import parse from 'html-react-parser';
export default function ShowBlog() {
const componentMounted = true
const {id} = useParams()
const [blogDetails, setBlogDetails] = useState([])
const [loading, setLoading] = useState(true)
const [blogCreator, setBlogCreator] = useState('')
const source = axios.CancelToken.source()
const fetchBlogDetails = async()=>{
try{
const response = await axios.get(`/blogs/${id}`, {cancelToken:source.token})
setBlogDetails(response.data.blog)
setBlogCreator(response.data.blog_creator)
setLoading(false)
console.log("Show Blog details",response)
} catch(error){
if(axios.isCancel(error)){
console.log('cancelled')
}else{
throw error
}
console.log(error)
} finally {
setLoading(false)
}
}
useEffect(()=>{
fetchBlogDetails()
return () => {
source.cancel()
}
}, [])
if(loading){
return <PageLoader />
}
return (
<div className="bg-white">
<div className="max-w-6xl mx-auto mt-10">
<div className="relative max-w-4xl mx-auto items-center justify-between">
<div className="flex flex-col ">
<div className="w-full ">
<h2 className="text-gray-800 ">
{blogDetails?.title}
</h2>
<div className="flex ">
<span>by {blogCreator?.username}</span>
</div>
<div>
{parse(blogDetails.body)}
</div>
</div>
</div>
</div>
</div>
</div>
)
}
Inspect

How to refactor this particular Reactjs code so it's complies with Eslint

I'm a Reactjs Beginner and read lots of code and stumble on this.
I want to change this code so it comply with Estlint, that is:
"Arrow function should not return assignment"
I read the docs and it's no big deal but they dont mention this particular case.
I have tried to create the react-slick Sliderbeforehand somehow to try to get a ref to it but dont know how to do it. Like creating a class variable Sliter and then make the this.slider = slider but it gives lots of error
This is the file
/* eslint-disable react/jsx-props-no-spreading */
import Slider from 'react-slick';
import 'slick-carousel/slick/slick.css';
import 'slick-carousel/slick/slick-theme.css';
import React from 'react';
import Resume from '../../resume.json';
import albums from '../../albumData.json';
const la = require('lodash');
class SliderWrapper extends React.Component {
shouldComponentUpdate(nextProps) {
// certain condition here, perhaps comparison between this.props and nextProps
// and if you want to update slider on setState in parent of this, return true, otherwise return false
const { updateCount } = nextProps;
const { updateCounter } = this.props;
if (updateCounter !== updateCount) {
return false;
}
return true;
}
sliders() {
return Resume.weeks.map(week => {
let photo = la.find(albums, { weekNumber: week.weekNumber });
photo = encodeURIComponent(`${process.env.PUBLIC_URL}/images/weeks/${week.weekNumber}/${photo.coverImage}`);
const { onImageClick } = this.props;
return (
// Timeline items
<section className="timeline-carousel" key={week.weekNumber}>
<h1>week {week.weekNumber}</h1>
<div className="timeline-carousel__item-wrapper" data-js="timeline-carousel">
<div className="timeline-carousel__item">
<div className="timeline-carousel__image">
<img onClick={() => onImageClick(week.weekNumber)} alt="CoverImage" src={photo} />
<h2>UNDER CONSTRUCTION IN PROGRES..</h2>
</div>
<div className="timeline-carousel__item-inner">
<div className="pointer" />
<span className="year">{week.year}</span>
<span className="month">{week.albumDate}</span>
<p>{week.summary}</p>
<a href="#/" className="read-more">
Read more, Dev should go to read more
</a>
</div>
</div>
</div>
</section>
);
});
}
render() {
const { afterChanged } = this.props;
const { beforeChanged } = this.props;
const settings = {
dots: false,
arrows: false,
autoplay: false,
infinite: true,
lazyLoad: false,
swipeToSlide: true,
centerMode: false,
focusOnSelect: false,
className: 'center',
slidesToShow: 4,
afterChange: afterChanged,
beforeChange: beforeChanged,
responsive: [
{
breakpoint: 1024,
settings: {
slidesToShow: 3,
slidesToScroll: 3,
infinite: false,
},
},
{
breakpoint: 600,
settings: {
slidesToShow: 2,
slidesToScroll: 2,
initialSlide: 2,
},
},
{
breakpoint: 480,
settings: {
slidesToShow: 1,
slidesToScroll: 1,
},
},
],
};
return (
<div>
<Slider ref={slider => (this.slider = slider)} {...settings}>
{this.sliders()}
</Slider>
</div>
);
}
}
export default SliderWrapper;
By just using parens there, the code creates a function that returns a value. So essentially, you're actually writing a function like this:
// example of what's generated with parens; don't do this!
function assignRef(slider) {
return this.slider = slider;
}
// and later...
<Slider ref={assignRef} {...settings}>
{this.sliders()}
</Slider>
Which is not what should be used here. Use Curly Braces instead
<Slider ref={slider => {this.slider = slider}} {...settings}>
{this.sliders()}
</Slider>
// example of what's generated with curly braces, do not actually use.
// function assignRef(slider) {
// this.slider = slider;
// }
which is what you're looking for.

React JS Functional component renders twice on onChange event and gets always current value of array and then new value

I have a React functional component that renders a JSX that contains a paragraph, a dropdown from Select React JS library and a Line chart from Nivo library.
When I render the component for the first time I have a useEffect hook that helps me to retrieve data, a list, from the backend. The data is returned from the backend based on a mode value.
This mode can be:
week
month
year
and I have a useState for it const [mode, setMode] = useState("week").
The Select dropdown has the onChange event listener that helps me set a new mode
setMode(e.value) - can be week, month or year
When I set a new mode, it goes back to the backend and retrieves a new list with data.
My problem is the following one:
I select a new value from the dropdown
My component re-renders and gets the current value of my array
Then it changes the mode with the new value
Then the useEffect gets the new data based on the new mode and re-renders with the new list.
For example:
My current value on the mode is week. Data comes from the backend and renders correctly in the chart. I select a new mode, month and call setMode("month").
First things that happen:
The component re-renders
Gets current data for the chart which is week
useEffect makes the GET request for the new mode month data and sets the new data on the chart
If the current mode is month and I want to show a chart with year. Again on dropdown onChange I set the mode to year, but first component re-renders get current array value which is month and then returns data for year.
I do not want to get the current value of the array first every time I select a new value from the dropdown. I only want to setMode with the new value and retrieve data from the server with the new list.
Here is my code:
React Component:
import { useFeedbackDistribution } from "../../api/analytics.firebase";
import { DISTRIBUTION_MODE } from "../../utils/query_filters";
// UI
import Loading from "../App/loadingIndicator";
import { ErrorSolid } from "../Errors/error.solid";
import { ResponsiveLine } from "#nivo/line";
import Select from "react-select";
import {
dayTimeScaleProperties,
monthTimeScaleProperties,
yearTimeScaleProperties
} from "../../utils/charts/utils";
const options = [
{ value: DISTRIBUTION_MODE.WEEK, label: DISTRIBUTION_MODE.WEEK },
{ value: DISTRIBUTION_MODE.MONTH, label: DISTRIBUTION_MODE.MONTH },
{ value: DISTRIBUTION_MODE.YEAR, label: DISTRIBUTION_MODE.YEAR }
];
const FeedbackDistributionCard = user => {
const [mode, setMode] = useState({
value: DISTRIBUTION_MODE.WEEK,
label: DISTRIBUTION_MODE.WEEK
});
const [{ isLoading, isError, data }] = useFeedbackDistribution(
mode.value,
[]
);
function load(data) {
switch (mode.value) {
case DISTRIBUTION_MODE.WEEK:
return dayTimeScaleProperties(data);
case DISTRIBUTION_MODE.MONTH:
return monthTimeScaleProperties(data);
default:
return yearTimeScaleProperties(data);
}
}
return (
<div className="w-full h-64 sm:w-full md:w-full lg:w-3/4 xl:w-3/4 mb-4 bg-white rounded-lg shadow">
<div className="w-full h-full ">
{isError && <ErrorSolid />}
{isLoading ? (
<Loading />
) : (
<div className="h-full w-full flex-col shadow p-6">
<div>
<p className="font-bold float-left inline-block">
Feedback by {mode.value}
</p>
<Select
className="w-40 z-50 float-right"
options={options}
onChange={e => {
setMode({ label: e.label, value: e.value });
}}
value={mode}
/>
</div>
<div className="h-full w-full">
<FeedbackDistributionLineChart
properties={load(data)}
/>
</div>
</div>
)}
</div>
</div>
);
};
export default FeedbackDistributionCard;
const FeedbackDistributionLineChart = ({ properties }) => (
<ResponsiveLine
{...properties}
enablePoints={false}
enableGridX={false}
enableGridY={false}
colors={{ scheme: "category10" }}
margin={{ top: 20, right: 30, bottom: 40, left: 40 }}
animate={true}
enableSlices={"x"}
yScale={{
type: "linear",
stacked: false
}}
axisLeft={{
legend: "total",
legendPosition: "middle",
legendOffset: -30,
tickValues: 5
}}
curve={"basis"}
enablePointLabel={true}
useMesh={true}
enableSlices={false}
/>
);
useEffect custom hook
const feedbackDistributionReducer = (state, action) => {
switch (action.type) {
case "FETCH_INIT":
return { ...state, isLoading: true, isError: false };
case "FETCH_SUCCESS":
return {
...state,
isLoading: false,
isError: false,
data: action.payload
};
case "FETCH_ERROR":
return {
...state,
isLoading: false,
isError: true,
data: action.payload
};
default:
throw new Error("Could not fetch feedback distribution");
}
};
const useFeedbackDistribution = (mode, initialData) => {
const [state, dispatch] = useReducer(feedbackDistributionReducer, {
isLoading: false,
isError: false,
data: initialData
});
useEffect(() => {
let didCancel = false;
async function load(mode) {
console.log(mode);
dispatch({ type: "FETCH_INIT", payload: null });
try {
var feedbackDistribution = firebase
.functions()
.httpsCallable("feedbackDistribution");
let result = await feedbackDistribution({ mode: mode });
var mappedResult = result.data.map(function(item) {
var info = { y: item.totalCount, x: item.time };
return info;
});
const distribution = [
{
id: "id",
data: mappedResult
}
];
if (!didCancel) {
dispatch({ type: "FETCH_SUCCESS", payload: distribution });
}
} catch (err) {
if (!didCancel) {
dispatch({ type: "FETCH_ERROR", payload: error });
}
}
}
load(mode);
return () => {
didCancel = true;
};
}, [mode]);
return [state];
};
Thanks!
the problem is you're changing a useState value directly from the onChange which causes a re-render and triggers the hook, you need to dispatch the fetch call directly in the onChange. Good luck! :)

Resources