Use React Query for data loading
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import js from "@eslint/js";
|
import js from "@eslint/js";
|
||||||
|
import pluginQuery from "@tanstack/eslint-plugin-query";
|
||||||
import reactHooks from "eslint-plugin-react-hooks";
|
import reactHooks from "eslint-plugin-react-hooks";
|
||||||
import reactRefresh from "eslint-plugin-react-refresh";
|
import reactRefresh from "eslint-plugin-react-refresh";
|
||||||
import globals from "globals";
|
import globals from "globals";
|
||||||
@@ -7,18 +8,21 @@ import tseslint from "typescript-eslint";
|
|||||||
export default tseslint.config(
|
export default tseslint.config(
|
||||||
{ ignores: ["dist"] },
|
{ ignores: ["dist"] },
|
||||||
{
|
{
|
||||||
extends: [js.configs.recommended, ...tseslint.configs.recommended],
|
extends: [
|
||||||
|
js.configs.recommended,
|
||||||
|
reactHooks.configs["recommended-latest"],
|
||||||
|
...tseslint.configs.recommended,
|
||||||
|
...pluginQuery.configs["flat/recommended"],
|
||||||
|
],
|
||||||
files: ["**/*.{ts,tsx}"],
|
files: ["**/*.{ts,tsx}"],
|
||||||
languageOptions: {
|
languageOptions: {
|
||||||
ecmaVersion: 2020,
|
ecmaVersion: 2020,
|
||||||
globals: globals.browser,
|
globals: globals.browser,
|
||||||
},
|
},
|
||||||
plugins: {
|
plugins: {
|
||||||
"react-hooks": reactHooks,
|
|
||||||
"react-refresh": reactRefresh,
|
"react-refresh": reactRefresh,
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
...reactHooks.configs.recommended.rules,
|
|
||||||
"react-refresh/only-export-components": [
|
"react-refresh/only-export-components": [
|
||||||
"warn",
|
"warn",
|
||||||
{ allowConstantExport: true },
|
{ allowConstantExport: true },
|
||||||
|
|||||||
73
package-lock.json
generated
73
package-lock.json
generated
@@ -10,6 +10,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/styled": "^11.14.1",
|
"@emotion/styled": "^11.14.1",
|
||||||
"@mui/icons-material": "^7.2.0",
|
"@mui/icons-material": "^7.2.0",
|
||||||
|
"@tanstack/react-query": "^5.82.0",
|
||||||
|
"@tanstack/react-query-devtools": "^5.82.0",
|
||||||
"d3": "^7.9.0",
|
"d3": "^7.9.0",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
@@ -17,6 +19,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.30.1",
|
"@eslint/js": "^9.30.1",
|
||||||
|
"@tanstack/eslint-plugin-query": "^5.81.2",
|
||||||
"@types/d3": "^7.4.3",
|
"@types/d3": "^7.4.3",
|
||||||
"@types/node": "^24.0.12",
|
"@types/node": "^24.0.12",
|
||||||
"@types/react": "^19.1.8",
|
"@types/react": "^19.1.8",
|
||||||
@@ -2089,6 +2092,76 @@
|
|||||||
"win32"
|
"win32"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
"node_modules/@tanstack/eslint-plugin-query": {
|
||||||
|
"version": "5.81.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/eslint-plugin-query/-/eslint-plugin-query-5.81.2.tgz",
|
||||||
|
"integrity": "sha512-h4k6P6fm5VhKP5NkK+0TTVpGGyKQdx6tk7NYYG7J7PkSu7ClpLgBihw7yzK8N3n5zPaF3IMyErxfoNiXWH/3/A==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@typescript-eslint/utils": "^8.18.1"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"eslint": "^8.57.0 || ^9.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tanstack/query-core": {
|
||||||
|
"version": "5.82.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.82.0.tgz",
|
||||||
|
"integrity": "sha512-JrjoVuaajBQtnoWSg8iaPHaT4mW73lK2t+exxHNOSMqy0+13eKLqJgTKXKImLejQIfdAHQ6Un0njEhOvUtOd5w==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tanstack/query-devtools": {
|
||||||
|
"version": "5.81.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.81.2.tgz",
|
||||||
|
"integrity": "sha512-jCeJcDCwKfoyyBXjXe9+Lo8aTkavygHHsUHAlxQKKaDeyT0qyQNLKl7+UyqYH2dDF6UN/14873IPBHchcsU+Zg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tanstack/react-query": {
|
||||||
|
"version": "5.82.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.82.0.tgz",
|
||||||
|
"integrity": "sha512-mnk8/ofKEthFeMdhV1dV8YXRf+9HqvXAcciXkoo755d/ocfWq7N/Y9jGOzS3h7ZW9dDGwSIhs3/HANWUBsyqYg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@tanstack/query-core": "5.82.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^18 || ^19"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@tanstack/react-query-devtools": {
|
||||||
|
"version": "5.82.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.82.0.tgz",
|
||||||
|
"integrity": "sha512-MC05Zq3zr/59jhgF7dL6JSGPg1krbasDSizmRxjNcvxgh/sUTwRFD9CGN10YYX7LB6jq0ZpFtCjSVGdLiFrKAA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@tanstack/query-devtools": "5.81.2"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@tanstack/react-query": "^5.82.0",
|
||||||
|
"react": "^18 || ^19"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tsconfig/node10": {
|
"node_modules/@tsconfig/node10": {
|
||||||
"version": "1.0.11",
|
"version": "1.0.11",
|
||||||
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
|
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@emotion/styled": "^11.14.1",
|
"@emotion/styled": "^11.14.1",
|
||||||
"@mui/icons-material": "^7.2.0",
|
"@mui/icons-material": "^7.2.0",
|
||||||
|
"@tanstack/react-query": "^5.82.0",
|
||||||
|
"@tanstack/react-query-devtools": "^5.82.0",
|
||||||
"d3": "^7.9.0",
|
"d3": "^7.9.0",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
@@ -19,6 +21,7 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.30.1",
|
"@eslint/js": "^9.30.1",
|
||||||
|
"@tanstack/eslint-plugin-query": "^5.81.2",
|
||||||
"@types/d3": "^7.4.3",
|
"@types/d3": "^7.4.3",
|
||||||
"@types/node": "^24.0.12",
|
"@types/node": "^24.0.12",
|
||||||
"@types/react": "^19.1.8",
|
"@types/react": "^19.1.8",
|
||||||
|
|||||||
26
src/App.tsx
26
src/App.tsx
@@ -1,24 +1,26 @@
|
|||||||
|
import { useQuery } from "@tanstack/react-query";
|
||||||
import * as d3 from "d3";
|
import * as d3 from "d3";
|
||||||
import { useEffect, useState } from "react";
|
import { useEffect, useState } from "react";
|
||||||
import Legend from "./components/Legend";
|
import Legend from "./components/Legend";
|
||||||
import QRCode from "./components/QRCode";
|
import QRCode from "./components/QRCode";
|
||||||
import { QuestionGroupChart } from "./components/QuestionGroupChart";
|
import { QuestionGroupChart } from "./components/QuestionGroupChart";
|
||||||
import { config } from "./config";
|
import { config } from "./config";
|
||||||
import { CategoryMetadata, fetchCategoryMetadata } from "./lib/metadata";
|
import { getSampleData } from "./lib/data";
|
||||||
import { fetchGoogleSheet, ResponseData } from "./lib/parser";
|
import { fetchCategoryMetadata } from "./lib/metadata";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [data, setData] = useState<ResponseData[]>([]);
|
const { data: categoryMetadata } = useQuery({
|
||||||
const [categoryMetadata, setCategoryMetadata] = useState<CategoryMetadata[]>(
|
queryKey: ["categoryMetadata"],
|
||||||
[]
|
queryFn: fetchCategoryMetadata,
|
||||||
);
|
});
|
||||||
|
const { data, isPending, isError } = useQuery({
|
||||||
|
queryKey: ["responses"],
|
||||||
|
queryFn: getSampleData,
|
||||||
|
refetchInterval: 2 * 1000, // Refresh every 5 seconds
|
||||||
|
});
|
||||||
|
|
||||||
useEffect(() => {
|
if (isPending) return <div>Loading...</div>;
|
||||||
fetchGoogleSheet().then(setData);
|
if (isError) return <div>Error loading data</div>;
|
||||||
// setData(getSampleData());
|
|
||||||
|
|
||||||
fetchCategoryMetadata().then(setCategoryMetadata);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
if (!data.length) return null;
|
if (!data.length) return null;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { ResponseData } from "./parser";
|
import { ResponseData } from "./parser";
|
||||||
|
|
||||||
export function getSampleData(): ResponseData[] {
|
export function getSampleData(): Promise<ResponseData[]> {
|
||||||
const questions = [
|
const questions = [
|
||||||
"Service Quality",
|
"Service Quality",
|
||||||
"Value for Money",
|
"Value for Money",
|
||||||
@@ -24,5 +24,8 @@ export function getSampleData(): ResponseData[] {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return sampleData;
|
// Simulate a delay to mimic fetching actual data
|
||||||
|
return new Promise<ResponseData[]>((resolve) => {
|
||||||
|
setTimeout(() => resolve(sampleData), 500);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,19 @@
|
|||||||
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
||||||
|
import { ReactQueryDevtools } from "@tanstack/react-query-devtools";
|
||||||
import { StrictMode } from "react";
|
import { StrictMode } from "react";
|
||||||
import { createRoot } from "react-dom/client";
|
import { createRoot } from "react-dom/client";
|
||||||
|
|
||||||
import App from "./App";
|
import App from "./App";
|
||||||
|
|
||||||
import "./styles/index.scss";
|
import "./styles/index.scss";
|
||||||
|
|
||||||
|
const queryClient = new QueryClient();
|
||||||
|
|
||||||
createRoot(document.getElementById("root")!).render(
|
createRoot(document.getElementById("root")!).render(
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
|
<QueryClientProvider client={queryClient}>
|
||||||
|
<ReactQueryDevtools />
|
||||||
<App />
|
<App />
|
||||||
|
</QueryClientProvider>
|
||||||
</StrictMode>
|
</StrictMode>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user