hi,
I had some delay. I thought it was NEXT.JS problem so I rewrote it into React ... but problem hasn't disappeared. So here's info you wanted:
package.json:
{
"name": "frontend",
"version": "0.1.0",
"private": true,
"dependencies": {
"@syncfusion/ej2": "^20.2.40",
"@syncfusion/ej2-react-charts": "^20.2.40",
"@syncfusion/ej2-react-grids": "^20.2.40",
"@syncfusion/ej2-react-popups": "^20.2.40",
"@tanstack/react-query": "^4.0.10",
"@tanstack/react-query-devtools": "^4.0.10",
"@testing-library/jest-dom": "^5.16.4",
"@testing-library/react": "^13.3.0",
"@testing-library/user-event": "^13.5.0",
"@types/jest": "^27.5.2",
"@types/node": "^16.11.45",
"@types/react": "^18.0.15",
"@types/react-dom": "^18.0.6",
"@types/react-transition-group": "^4.4.5",
"@types/uuid": "^8.3.4",
"@types/yup": "^0.29.14",
"axios": "^0.27.2",
"buffer": "^6.0.3",
"formik": "^2.2.9",
"i18next": "^21.8.14",
"i18next-browser-languagedetector": "^6.1.4",
"i18next-http-backend": "^1.4.1",
"jsonwebtoken": "^8.5.1",
"jwt-decode": "^3.1.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-i18next": "^11.18.1",
"react-icons": "^4.4.0",
"react-router-dom": "^6.3.0",
"react-scripts": "5.0.1",
"react-spinners": "^0.13.3",
"react-transition-group": "^4.4.2",
"typescript": "^4.7.4",
"uuid": "^8.3.2",
"web-vitals": "^2.1.4",
"yup": "^0.32.11"
},
"scripts": {
"start": "react-scripts start",
"dev": "i18nexus pull -k asP18t3Jst04ZrBvzmAHtA && react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"autoprefixer": "^10.4.7",
"postcss": "^8.4.14",
"tailwindcss": "^3.1.6"
}
}
newly created component in React:
import React, { Fragment, useEffect, useState } from "react";
import { v4 as uuidv4 } from "uuid";
import { useTranslation } from "react-i18next";
import { useThemeProvider } from "../contexts/theme-context";
import {
GridComponent,
ColumnsDirective,
ColumnDirective,
Resize,
Page,
Edit,
Inject,
Toolbar,
ToolbarItems,
Group,
EditSettingsModel,
Sort,
} from "@syncfusion/ej2-react-grids";
import {
useDeletePlantVarieties,
useGetPlantVarieties,
} from "../hooks/usePlantVarietiesCRUDData";
import { usePostPlantVarieties } from "../hooks/usePlantVarietiesCRUDData";
import { usePutPlantVarieties } from "../hooks/usePlantVarietiesCRUDData";
import Header from "../components/Header";
import { PlantVariety } from "../utils/types/app.types";
const PlantVarieties = () => {
////vars
const { t } = useTranslation();
const { currentColor } = useThemeProvider();
const [plantVarieties, setPlantVarieties] = useState<
{ result: PlantVariety[]; count: number } | undefined
>(undefined);
////CRUD
//get
const { data, isFetching, isError, error } = useGetPlantVarieties();
useEffect(() => {
if (data) setPlantVarieties({ ...data.data });
}, [data]);
//post/put
const { mutate: postMutate } = usePostPlantVarieties();
const { mutate: putMutate } = usePutPlantVarieties();
const { mutate: deleteMutate } = useDeletePlantVarieties();
////grid options
const editOptions: EditSettingsModel = {
allowAdding: true,
allowEditing: true,
allowDeleting: true,
mode: "Dialog",
};
const toolbarOptions: ToolbarItems[] = ["Add", "Edit", "Delete"];
////
async function dataSourceChanged(state: any) {
if (state.action === "add") {
console.log("add");
postMutate(createPlantObject(state.data.varietyCode, state.data.name));
state.endEdit();
}
if (state.action === "edit") {
console.log("edit");
putMutate(state.data);
state.endEdit();
}
if (state.requestType === "delete") {
console.log("delete");
deleteMutate(state.data[0].plantId);
state.endEdit();
}
}
////utils
function createPlantObject(varietyCode: string, name: string) {
const newPlantId = uuidv4();
const plant: PlantVariety = {
plantId: newPlantId,
varietyCode: varietyCode,
name: name,
};
return plant;
}
////jsx
let content = (
<div className="m-2 md:m-10 p-2 md:p-10 bg-white rounded-3xl">
<Header category={t("common:monitoring")} title={t("common:varietes")} />
<div className="font-loading animate-pulse">some dummy text div>
<div className="font-loading animate-pulse">
somevery verydummydummytemporarytext text{" "}
div>
<div className="font-loading animate-pulse">some dummy text div>
div>
);
if (plantVarieties) {
content = (
<Fragment>
<div className="m-2 md:m-10 p-2 md:p-10 bg-white rounded-3xl">
<Header
category={t("common:monitoring")}
title={t("common:varietes")}
/>
<GridComponent
dataSource={plantVarieties}
allowSorting={true}
allowGrouping
allowPaging
pageSettings={{ pageSize: 10 }}
toolbar={toolbarOptions}
editSettings={editOptions}
dataSourceChanged={dataSourceChanged}
>
<ColumnsDirective>
<ColumnDirective
field="name"
headerText="Nazwa"
textAlign="Center"
width="100%"
/>
<ColumnDirective
field="varietyCode"
headerText="Kod odmiany"
textAlign="Center"
width="200"
/>
ColumnsDirective>
<Inject services={[Resize, Edit, Toolbar, Page, Group, Sort]} />
GridComponent>
div>
Fragment>
);
}
return content;
};
export default PlantVarieties;
CRUD operations hook:
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import axios from "axios";
import { getDataFromLocalStorage } from "../utils/localStorageUtils";
import { PlantVariety } from "../utils/types/app.types";
const dataFromLocalStorage = getDataFromLocalStorage();
const token = dataFromLocalStorage ? dataFromLocalStorage.token : "";
interface PlantVarietiesFetched {
result: PlantVariety[];
count: number;
}
////GET
const getPlantVarieties = () =>
axios.get<PlantVarietiesFetched>(
`${process.env.REACT_APP_BACKEND_URL}/api/plant-varieties/`,
{
headers: {
Authorization: token,
Accept: "application/json",
},
}
);
export const useGetPlantVarieties = () => {
return useQuery(["plantVarieties"], () => getPlantVarieties());
};
////POST
const postPlantVarieties = (plantData: PlantVariety) =>
axios.post(
`${process.env.REACT_APP_BACKEND_URL}/api/plant-varieties/`,
plantData,
{
headers: {
Authorization: token,
Accept: "application/json",
},
}
);
export const usePostPlantVarieties = () => {
const queryClient = useQueryClient();
return useMutation(postPlantVarieties, {
onSuccess: () => {
queryClient.invalidateQueries(["plantVarieties"]);
},
});
};
////PUT
const putPlantVarieties = (plantData: PlantVariety) =>
axios.put(
`${process.env.REACT_APP_BACKEND_URL}/api/plant-varieties/`,
plantData,
{
headers: {
Authorization: token,
Accept: "application/json",
},
}
);
export const usePutPlantVarieties = () => {
const queryClient = useQueryClient();
return useMutation(putPlantVarieties, {
onSuccess: () => {
queryClient.invalidateQueries(["plantVarieties"]);
},
});
};
////DELETE
const deletePlantVarieties = (plantId: string) =>
axios.delete(
`${process.env.REACT_APP_BACKEND_URL}/api/plant-varieties/${plantId}`,
{
headers: {
Authorization: token,
Accept: "application/json",
},
}
);
export const useDeletePlantVarieties = () => {
const queryClient = useQueryClient();
return useMutation(deletePlantVarieties, {
onSuccess: () => {
queryClient.invalidateQueries(["plantVarieties"]);
},
});
};
...
video:
https://res.cloudinary.com/dn8l30dkf/video/upload/v1659453004/2022-08-02_17h06_34_xj0xav.mp4
all CRUD actions work without problem (as seen on video),
but any click in Paging, sorting by clicking on Column Header, or dragging column header to group it - end with endless spinner, and action never finishes.
regards
Piotr