Compare commits

..

2 Commits

Author SHA1 Message Date
Adrian Rumpold
f3f490d960 Use React Query for data loading 2025-07-10 09:09:15 +02:00
Adrian Rumpold
509b765213 Fix invalid whitespace 2025-07-10 09:08:03 +02:00
7 changed files with 113 additions and 19 deletions

View File

@@ -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
View File

@@ -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",

View File

@@ -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",

View File

@@ -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;

View File

@@ -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);
});
} }

View File

@@ -18,7 +18,7 @@ Python-Programmierung,Grundlegende Programmier-kenntnisse zur Umsetzung und Anpa
Software Design,"Gestaltung robuster, skalierbarer und wartbarer Softwarelösungen mit KI-Komponenten",code Software Design,"Gestaltung robuster, skalierbarer und wartbarer Softwarelösungen mit KI-Komponenten",code
Maschinelles Lernen,Kenntnisse in maschinellem Lernen zur Entwicklung datengetriebener Modelle,model_training Maschinelles Lernen,Kenntnisse in maschinellem Lernen zur Entwicklung datengetriebener Modelle,model_training
MLOps / Infrastruktur,Fähigkeiten zum produktiven Einsatz und Betrieb von KI-Systemen in Unternehmen,all_inclusive MLOps / Infrastruktur,Fähigkeiten zum produktiven Einsatz und Betrieb von KI-Systemen in Unternehmen,all_inclusive
GenAI-Kenntnisse,Verständnis generativer KI-Modelle (z.B. Large Language Models) und ihrer praktischen Nutzung,auto_awesome`; GenAI-Kenntnisse,Verständnis generativer KI-Modelle (z. B. Large Language Models) und ihrer praktischen Nutzung,auto_awesome`;
export function fetchCategoryMetadata(): Promise<CategoryMetadata[]> { export function fetchCategoryMetadata(): Promise<CategoryMetadata[]> {
const parseCsv = (csv: string): CategoryMetadata[] => { const parseCsv = (csv: string): CategoryMetadata[] => {

View File

@@ -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>
<App /> <QueryClientProvider client={queryClient}>
<ReactQueryDevtools />
<App />
</QueryClientProvider>
</StrictMode> </StrictMode>
); );