diff --git a/webapp/README.md b/webapp/README.md
index 254a5f0..6cbd57d 100644
--- a/webapp/README.md
+++ b/webapp/README.md
@@ -8,11 +8,13 @@ Plus d'infos ici : [https://feature-sliced.github.io/documentation/docs/get-star
- Avoir Node.js installé sur votre machine [voir comment faire](https://docs.npmjs.com/downloading-and-installing-node-js-and-npm#using-a-node-version-manager-to-install-nodejs-and-npm)
## Installer les packages
+
```
npm ci
```
## Démarrer le serveur
+
```
npm run dev
```
@@ -22,4 +24,4 @@ npm run dev
- `npm run build` : package l'application pour la mise en production (dossier [dist](./dist))
- `npm run preview` : Démarre le serveur à partir du build pour la production (dans le dist)
- `npm run check:arch` : Vérifier si les imports du projet respectent le principe de l'architecture FSD.
-- `npm run arch:tree` : Génère un fichier text contenant l'arborescence du projet.
\ No newline at end of file
+- `npm run arch:tree` : Génère un fichier text contenant l'arborescence du projet.
diff --git a/webapp/components.json b/webapp/components.json
index 711c837..793a405 100644
--- a/webapp/components.json
+++ b/webapp/components.json
@@ -22,4 +22,4 @@
"hooks": "@/hooks"
},
"registries": {}
-}
\ No newline at end of file
+}
diff --git a/webapp/eslint.config.ts b/webapp/eslint.config.ts
index 93b060a..5479510 100644
--- a/webapp/eslint.config.ts
+++ b/webapp/eslint.config.ts
@@ -1,13 +1,19 @@
-import js from "@eslint/js";
+import pluginReact from "eslint-plugin-react";
import globals from "globals";
import tseslint from "typescript-eslint";
-import pluginReact from "eslint-plugin-react";
+
+import js from "@eslint/js";
import json from "@eslint/json";
-import { defineConfig } from "eslint/config";
import pluginPrettier from "eslint-config-prettier/flat";
+import { defineConfig } from "eslint/config";
export default defineConfig([
- { files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"], plugins: { js }, extends: ["js/recommended"], languageOptions: { globals: globals.browser } },
+ {
+ files: ["**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"],
+ plugins: { js },
+ extends: ["js/recommended"],
+ languageOptions: { globals: globals.browser },
+ },
tseslint.configs.recommended,
{
...pluginReact.configs.flat.recommended,
@@ -16,17 +22,27 @@ export default defineConfig([
* Disable react/display-name since it's currently broken
* TypeError: Error while loading rule 'react/display-name': sourceCode.getAllComments is not a function
*/
- "react/display-name": ["off"]
+ "react/display-name": ["off"],
},
settings: {
react: {
- version: "detect"
- }
+ version: "detect",
+ },
},
},
- /** @ts-expect-error json plugin not typed well*/
- { files: ["**/*.json"], plugins: { json }, language: "json/json", extends: ["json/recommended"] },
- /** @ts-expect-error json plugin not typed well*/
- { files: ["**/*.jsonc"], plugins: { json }, language: "json/jsonc", extends: ["json/recommended"] },
+ {
+ files: ["**/*.json"],
+ /** @ts-expect-error json plugin not typed well*/
+ plugins: { json },
+ language: "json/json",
+ extends: ["json/recommended"],
+ },
+ {
+ files: ["**/*.jsonc"],
+ /** @ts-expect-error json plugin not typed well*/
+ plugins: { json },
+ language: "json/jsonc",
+ extends: ["json/recommended"],
+ },
pluginPrettier,
]);
diff --git a/webapp/index.html b/webapp/index.html
index 072a57e..9174257 100644
--- a/webapp/index.html
+++ b/webapp/index.html
@@ -2,12 +2,22 @@
-
-
+
+
frontend
-
+
diff --git a/webapp/scripts/check-architecture.cjs b/webapp/scripts/check-architecture.cjs
index 935ac05..c337398 100644
--- a/webapp/scripts/check-architecture.cjs
+++ b/webapp/scripts/check-architecture.cjs
@@ -3,21 +3,21 @@
* Vérifie que les imports respectent les règles de l'architecture
*/
-const fs = require('fs');
-const path = require('path');
+const fs = require("fs");
+const path = require("path");
-const LAYERS = ['app', 'pages', 'widgets', 'features', 'entities', 'shared'];
+const LAYERS = ["app", "pages", "widgets", "features", "entities", "shared"];
const LAYER_HIERARCHY = {
- 'shared': [],
- 'entities': ['shared'],
- 'features': ['entities', 'shared'],
- 'widgets': ['features', 'entities', 'shared'],
- 'pages': ['widgets', 'features', 'entities', 'shared'],
- 'app': ['pages', 'widgets', 'features', 'entities', 'shared']
+ shared: [],
+ entities: ["shared"],
+ features: ["entities", "shared"],
+ widgets: ["features", "entities", "shared"],
+ pages: ["widgets", "features", "entities", "shared"],
+ app: ["pages", "widgets", "features", "entities", "shared"],
};
function getLayerFromPath(filePath) {
- const relativePath = path.relative(path.join(__dirname, 'src'), filePath);
+ const relativePath = path.relative(path.join(__dirname, "src"), filePath);
const firstDir = relativePath.split(path.sep)[0];
return LAYERS.includes(firstDir) ? firstDir : null;
}
@@ -33,12 +33,15 @@ function checkImports(filePath, fileContent) {
while ((match = importRegex.exec(fileContent)) !== null) {
const importedLayer = match[1];
- if (LAYERS.includes(importedLayer) && !LAYER_HIERARCHY[layer].includes(importedLayer)) {
+ if (
+ LAYERS.includes(importedLayer) &&
+ !LAYER_HIERARCHY[layer].includes(importedLayer)
+ ) {
violations.push({
file: filePath,
layer,
importedLayer,
- line: fileContent.substring(0, match.index).split('\n').length
+ line: fileContent.substring(0, match.index).split("\n").length,
});
}
}
@@ -54,10 +57,17 @@ function scanDirectory(dir) {
const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);
- if (stat.isDirectory() && !file.startsWith('.') && file !== 'node_modules') {
+ if (
+ stat.isDirectory() &&
+ !file.startsWith(".") &&
+ file !== "node_modules"
+ ) {
violations.push(...scanDirectory(filePath));
- } else if (stat.isFile() && (file.endsWith('.ts') || file.endsWith('.tsx'))) {
- const content = fs.readFileSync(filePath, 'utf8');
+ } else if (
+ stat.isFile() &&
+ (file.endsWith(".ts") || file.endsWith(".tsx"))
+ ) {
+ const content = fs.readFileSync(filePath, "utf8");
violations.push(...checkImports(filePath, content));
}
}
@@ -66,21 +76,27 @@ function scanDirectory(dir) {
}
// Exécution
-console.log('🔍 Vérification de l\'architecture FSD...\n');
+console.log("🔍 Vérification de l'architecture FSD...\n");
-const srcDir = path.join(__dirname, '../src');
+const srcDir = path.join(__dirname, "../src");
const violations = scanDirectory(srcDir);
if (violations.length === 0) {
- console.log('✅ Aucune violation détectée ! L\'architecture FSD est respectée.');
+ console.log(
+ "✅ Aucune violation détectée ! L'architecture FSD est respectée.",
+ );
} else {
console.log(`❌ ${violations.length} violation(s) détectée(s):\n`);
violations.forEach(({ file, layer, importedLayer, line }) => {
const relativeFile = path.relative(__dirname, file);
console.log(` ${relativeFile}:${line}`);
- console.log(` ↳ La couche "${layer}" ne peut pas importer depuis "${importedLayer}"`);
- console.log(` ↳ Imports autorisés: ${LAYER_HIERARCHY[layer].join(', ') || 'aucun'}\n`);
+ console.log(
+ ` ↳ La couche "${layer}" ne peut pas importer depuis "${importedLayer}"`,
+ );
+ console.log(
+ ` ↳ Imports autorisés: ${LAYER_HIERARCHY[layer].join(", ") || "aucun"}\n`,
+ );
});
process.exit(1);
diff --git a/webapp/scripts/generate-tree.cjs b/webapp/scripts/generate-tree.cjs
index f99f96c..ba63b29 100644
--- a/webapp/scripts/generate-tree.cjs
+++ b/webapp/scripts/generate-tree.cjs
@@ -6,16 +6,10 @@
* @example node scripts/generate-tree.cjs ./frontend/src docs/frontend-archi.md
*/
-const fs = require('fs');
-const path = require('path');
-
-const IGNORE_LIST = [
- 'node_modules',
- '.git',
- 'dist',
- 'coverage',
- '.vscode',
-];
+const fs = require("fs");
+const path = require("path");
+
+const IGNORE_LIST = ["node_modules", ".git", "dist", "coverage", ".vscode"];
// Caractères Unicode (maintenant commentés)
// const PREFIX_BRANCH = '├── ';
@@ -24,11 +18,10 @@ const IGNORE_LIST = [
// const PREFIX_EMPTY = ' ';
// Alternative avec des caractères ASCII-safe pour une compatibilité maximale
-const PREFIX_BRANCH = '|-- ';
-const PREFIX_LAST_BRANCH = '`-- '; // Utilise un accent grave pour simuler la branche finale
-const PREFIX_CHILD = '| ';
-const PREFIX_EMPTY = ' ';
-
+const PREFIX_BRANCH = "|-- ";
+const PREFIX_LAST_BRANCH = "`-- "; // Utilise un accent grave pour simuler la branche finale
+const PREFIX_CHILD = "| ";
+const PREFIX_EMPTY = " ";
/**
* Fonction récursive qui génère l'arborescence d'un dossier.
@@ -36,24 +29,25 @@ const PREFIX_EMPTY = ' ';
* @param {string} prefix - Le préfixe de ligne pour l'indentation.
* @returns {string[]} Un tableau de chaînes, chaque chaîne étant une ligne de l'arbre.
*/
-function generateTree(directory, prefix = '') {
- const lines = [];
- const files = fs.readdirSync(directory)
- .filter(file => !IGNORE_LIST.includes(file));
-
- files.forEach((file, index) => {
- const filePath = path.join(directory, file);
- const isLast = index === files.length - 1;
- const isDirectory = fs.statSync(filePath).isDirectory();
-
- lines.push(prefix + (isLast ? PREFIX_LAST_BRANCH : PREFIX_BRANCH) + file);
-
- if (isDirectory) {
- const childPrefix = prefix + (isLast ? PREFIX_EMPTY : PREFIX_CHILD);
- lines.push(...generateTree(filePath, childPrefix));
- }
- });
- return lines;
+function generateTree(directory, prefix = "") {
+ const lines = [];
+ const files = fs
+ .readdirSync(directory)
+ .filter((file) => !IGNORE_LIST.includes(file));
+
+ files.forEach((file, index) => {
+ const filePath = path.join(directory, file);
+ const isLast = index === files.length - 1;
+ const isDirectory = fs.statSync(filePath).isDirectory();
+
+ lines.push(prefix + (isLast ? PREFIX_LAST_BRANCH : PREFIX_BRANCH) + file);
+
+ if (isDirectory) {
+ const childPrefix = prefix + (isLast ? PREFIX_EMPTY : PREFIX_CHILD);
+ lines.push(...generateTree(filePath, childPrefix));
+ }
+ });
+ return lines;
}
// --- Point d'entrée du script ---
@@ -62,35 +56,45 @@ const targetDir = process.argv[2];
const outputFile = process.argv[3];
if (!targetDir) {
- console.error('❌ Erreur : Veuillez spécifier le chemin du dossier à analyser.');
- console.error('Usage: node scripts/generate-tree.cjs [fichier_sortie]');
- process.exit(1);
+ console.error(
+ "❌ Erreur : Veuillez spécifier le chemin du dossier à analyser.",
+ );
+ console.error(
+ "Usage: node scripts/generate-tree.cjs [fichier_sortie]",
+ );
+ process.exit(1);
}
if (!fs.existsSync(targetDir) || !fs.statSync(targetDir).isDirectory()) {
- console.error(`❌ Erreur : Le dossier "${targetDir}" n'est pas un dossier valide.`);
- process.exit(1);
+ console.error(
+ `❌ Erreur : Le dossier "${targetDir}" n'est pas un dossier valide.`,
+ );
+ process.exit(1);
}
const treeLines = [
- `\`\`\`text`,
- path.basename(targetDir),
- ...generateTree(targetDir),
- `\`\`\``
+ `\`\`\`text`,
+ path.basename(targetDir),
+ ...generateTree(targetDir),
+ `\`\`\``,
];
-const outputString = treeLines.join('\n');
+const outputString = treeLines.join("\n");
-console.log('🌳 Arborescence générée :\n');
+console.log("🌳 Arborescence générée :\n");
console.log(outputString);
if (outputFile) {
- try {
- // Le BOM n'est plus nécessaire avec des caractères ASCII purs.
- fs.writeFileSync(outputFile, outputString, 'utf8');
- console.log(`\n✅ Arborescence sauvegardée avec succès dans : ${outputFile}`);
- } catch (error) {
- console.error(`\n❌ Erreur lors de l'écriture du fichier : ${error.message}`);
- process.exit(1);
- }
-}
\ No newline at end of file
+ try {
+ // Le BOM n'est plus nécessaire avec des caractères ASCII purs.
+ fs.writeFileSync(outputFile, outputString, "utf8");
+ console.log(
+ `\n✅ Arborescence sauvegardée avec succès dans : ${outputFile}`,
+ );
+ } catch (error) {
+ console.error(
+ `\n❌ Erreur lors de l'écriture du fichier : ${error.message}`,
+ );
+ process.exit(1);
+ }
+}
diff --git a/webapp/src/app/App.tsx b/webapp/src/app/App.tsx
index ad90399..1c0541e 100644
--- a/webapp/src/app/App.tsx
+++ b/webapp/src/app/App.tsx
@@ -1,12 +1,15 @@
-import { ThemeProvider, ApiProvider, AuthProvider } from "@providers";
-import { AppRouter } from "./routes/AppRouter";
+import { ApiProvider, AuthProvider, ThemeProvider } from "@providers";
+import { AppRouter } from "./routes/AppRouter";
import "./styles/all4trees.css";
import "./styles/globals.css";
function App() {
return (
-
+
@@ -16,4 +19,4 @@ function App() {
);
}
-export default App;
\ No newline at end of file
+export default App;
diff --git a/webapp/src/app/api/client.ts b/webapp/src/app/api/client.ts
index 1b94b27..b735bee 100644
--- a/webapp/src/app/api/client.ts
+++ b/webapp/src/app/api/client.ts
@@ -1,4 +1,4 @@
-const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:8000/graphql';
+const API_URL = import.meta.env.VITE_API_URL || "http://localhost:8000/graphql";
export const fetchJsonFixture = async (name: string) => {
const response = await fetch(`/src/fixtures/${name}.json`);
@@ -7,8 +7,8 @@ export const fetchJsonFixture = async (name: string) => {
export const fetchGraphQLData = async () => {
const res = await fetch(API_URL, {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
body: JSON.stringify({
query: `
query {
@@ -22,20 +22,20 @@ export const fetchGraphQLData = async () => {
month
}
}
-}`
+}`,
}),
});
const data = await res.json();
return data;
-}
+};
export const fetchWithAuth = async (
endpoint: string,
options: RequestInit = {},
- authToken: string | null
+ authToken: string | null,
) => {
const headers = new Headers(options.headers);
- headers.set('Authorization', authToken ? `Bearer ${authToken}` : '');
+ headers.set("Authorization", authToken ? `Bearer ${authToken}` : "");
const res = await fetch(`${API_URL}${endpoint}`, {
...options,
@@ -45,10 +45,10 @@ export const fetchWithAuth = async (
if (!res.ok) {
console.error(`Erreur API: ${res.status} ${res.statusText}`);
const errorData = await res.json().catch(() => ({
- error: 'Erreur de communication',
+ error: "Erreur de communication",
details: [res.statusText],
}));
- console.error('Détails de l\'erreur:', JSON.stringify(errorData, null, 2));
+ console.error("Détails de l'erreur:", JSON.stringify(errorData, null, 2));
const error = new Error(`Erreur API: ${res.status}`);
@@ -64,13 +64,13 @@ export const fetchWithAuth = async (
export const fetchJSONWithAuth = async (
endpoint: string,
options: RequestInit = {},
- authToken: string | null
+ authToken: string | null,
) => (await fetchWithAuth(endpoint, options, authToken)).json();
export const createApiClient = () => ({
getData() {
- return fetchJsonFixture('exampleData');
- }
+ return fetchJsonFixture("exampleData");
+ },
});
export type ApiClient = ReturnType;
diff --git a/webapp/src/app/providers/ApiProvider.tsx b/webapp/src/app/providers/ApiProvider.tsx
index 422de7a..c0b7ed6 100644
--- a/webapp/src/app/providers/ApiProvider.tsx
+++ b/webapp/src/app/providers/ApiProvider.tsx
@@ -1,26 +1,25 @@
-import { createContext, type ReactNode, useContext, useMemo } from 'react';
-import { createApiClient } from '../api/client';
+import { type ReactNode, createContext, useContext, useMemo } from "react";
+
+import { createApiClient } from "../api/client";
interface ApiProviderProps {
- children: ReactNode;
+ children: ReactNode;
}
-export const ApiContext = createContext | undefined>(undefined);
+export const ApiContext = createContext<
+ ReturnType | undefined
+>(undefined);
export function useApi() {
- const context = useContext(ApiContext);
- if (context === undefined) {
- throw new Error('useApi must be used within an ApiProvider');
- }
- return context;
+ const context = useContext(ApiContext);
+ if (context === undefined) {
+ throw new Error("useApi must be used within an ApiProvider");
+ }
+ return context;
}
export function ApiProvider({ children }: ApiProviderProps) {
- const api = useMemo(() => createApiClient(), []);
+ const api = useMemo(() => createApiClient(), []);
- return (
-
- {children}
-
- );
-}
\ No newline at end of file
+ return {children};
+}
diff --git a/webapp/src/app/providers/AuthProvider.tsx b/webapp/src/app/providers/AuthProvider.tsx
index e01d29f..2c97a91 100644
--- a/webapp/src/app/providers/AuthProvider.tsx
+++ b/webapp/src/app/providers/AuthProvider.tsx
@@ -1,76 +1,84 @@
-import { useState, useEffect, createContext, type ReactNode, useContext } from 'react';
+import {
+ type ReactNode,
+ createContext,
+ useContext,
+ useEffect,
+ useState,
+} from "react";
-const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000/api';
+const API_URL = import.meta.env.VITE_API_URL || "http://localhost:3000/api";
export interface AuthContextType {
- isAuthenticated: boolean;
- token: string | null;
- login: (token: string) => void;
- logout: () => void;
+ isAuthenticated: boolean;
+ token: string | null;
+ login: (token: string) => void;
+ logout: () => void;
}
-export const AuthContext = createContext(undefined);
+export const AuthContext = createContext(
+ undefined,
+);
export const useAuth = () => {
- const context = useContext(AuthContext);
- if (!context) {
- throw new Error('useAuth must be used within AuthProvider');
- }
- return context;
+ const context = useContext(AuthContext);
+ if (!context) {
+ throw new Error("useAuth must be used within AuthProvider");
+ }
+ return context;
};
interface AuthProviderProps {
- children: ReactNode;
+ children: ReactNode;
}
export function AuthProvider({ children }: AuthProviderProps) {
- const [isAuthenticated, setIsAuthenticated] = useState(false);
- const [token, setToken] = useState(null);
+ const [isAuthenticated, setIsAuthenticated] = useState(false);
+ const [token, setToken] = useState(null);
- useEffect(() => {
- const storedToken = localStorage.getItem('token');
+ useEffect(() => {
+ const storedToken = localStorage.getItem("token");
- if (storedToken) {
- // Vérifier si le token est toujours valide
- fetch(`${API_URL}/auth/verify`, {
- headers: {
- 'Authorization': `Bearer ${storedToken}`
- }
- })
- .then(res => res.json())
- .then(data => {
- if (data.valid) {
- setToken(storedToken);
- setIsAuthenticated(true);
- } else {
- // Token invalide, nettoyer le localStorage
- localStorage.removeItem('token');
- localStorage.removeItem('user');
- }
- })
- .catch(() => {
- localStorage.removeItem('token');
- localStorage.removeItem('user');
- });
- }
- }, []);
+ if (storedToken) {
+ // Vérifier si le token est toujours valide
+ fetch(`${API_URL}/auth/verify`, {
+ headers: {
+ Authorization: `Bearer ${storedToken}`,
+ },
+ })
+ .then((res) => res.json())
+ .then((data) => {
+ if (data.valid) {
+ setToken(storedToken);
+ setIsAuthenticated(true);
+ } else {
+ // Token invalide, nettoyer le localStorage
+ localStorage.removeItem("token");
+ localStorage.removeItem("user");
+ }
+ })
+ .catch(() => {
+ localStorage.removeItem("token");
+ localStorage.removeItem("user");
+ });
+ }
+ }, []);
- const login = (newToken: string) => {
- setToken(newToken);
- setIsAuthenticated(true);
- localStorage.setItem('token', newToken);
- };
+ const login = (newToken: string) => {
+ setToken(newToken);
+ setIsAuthenticated(true);
+ localStorage.setItem("token", newToken);
+ };
- const logout = () => {
- localStorage.removeItem('token');
- localStorage.removeItem('user');
- setToken(null);
- setIsAuthenticated(false);
- };
+ const logout = () => {
+ localStorage.removeItem("token");
+ localStorage.removeItem("user");
+ setToken(null);
+ setIsAuthenticated(false);
+ };
- return (
-
- {children}
-
- );
+ return (
+
+ {children}
+
+ );
}
diff --git a/webapp/src/app/providers/ThemeProvider.tsx b/webapp/src/app/providers/ThemeProvider.tsx
index 473f79e..db9f716 100644
--- a/webapp/src/app/providers/ThemeProvider.tsx
+++ b/webapp/src/app/providers/ThemeProvider.tsx
@@ -1,73 +1,76 @@
-import { createContext, useContext, useEffect, useState } from "react"
+import { createContext, useContext, useEffect, useState } from "react";
-type Theme = "dark" | "light" | "system"
+type Theme = "dark" | "light" | "system";
type ThemeProviderProps = {
- children: React.ReactNode
- defaultTheme?: Theme
- storageKey?: string
-}
+ children: React.ReactNode;
+ defaultTheme?: Theme;
+ storageKey?: string;
+};
type ThemeProviderState = {
- theme: Theme
- setTheme: (theme: Theme) => void
-}
+ theme: Theme;
+ setTheme: (theme: Theme) => void;
+};
const initialState: ThemeProviderState = {
- theme: "system",
- setTheme: () => null,
-}
+ theme: "system",
+ setTheme: () => null,
+};
-const ThemeProviderContext = createContext(initialState)
+const ThemeProviderContext = createContext(initialState);
export function ThemeProvider({
- children,
- defaultTheme = "system",
- storageKey = "vite-ui-theme",
- ...props
+ children,
+ defaultTheme = "system",
+ storageKey = "vite-ui-theme",
+ ...props
}: ThemeProviderProps) {
- const [theme, setTheme] = useState(
- () => (localStorage.getItem(storageKey) as Theme) || defaultTheme
- )
-
- useEffect(() => {
- const root = window.document.documentElement
-
- root.classList.remove("light", "dark")
-
- if (theme === "system") {
- const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
- .matches
- ? "dark"
- : "light"
-
- root.classList.add(systemTheme)
- return
- }
-
- root.classList.add(theme)
- }, [theme])
-
- const value = {
- theme,
- setTheme: (theme: Theme) => {
- localStorage.setItem(storageKey, theme)
- setTheme(theme)
- },
+ const [theme, setTheme] = useState(
+ () => (localStorage.getItem(storageKey) as Theme) || defaultTheme,
+ );
+
+ useEffect(() => {
+ const root = window.document.documentElement;
+
+ root.classList.remove("light", "dark");
+
+ if (theme === "system") {
+ const systemTheme = window.matchMedia("(prefers-color-scheme: dark)")
+ .matches
+ ? "dark"
+ : "light";
+
+ root.classList.add(systemTheme);
+ return;
}
- return (
-
- {children}
-
- )
+ root.classList.add(theme);
+ }, [theme]);
+
+ const value = {
+ theme,
+ setTheme: (theme: Theme) => {
+ localStorage.setItem(storageKey, theme);
+ setTheme(theme);
+ },
+ };
+
+ return (
+
+ {children}
+
+ );
}
export const useTheme = () => {
- const context = useContext(ThemeProviderContext)
+ const context = useContext(ThemeProviderContext);
- if (context === undefined)
- throw new Error("useTheme must be used within a ThemeProvider")
+ if (context === undefined)
+ throw new Error("useTheme must be used within a ThemeProvider");
- return context
-}
\ No newline at end of file
+ return context;
+};
diff --git a/webapp/src/app/providers/index.ts b/webapp/src/app/providers/index.ts
index ba3560e..38beedb 100644
--- a/webapp/src/app/providers/index.ts
+++ b/webapp/src/app/providers/index.ts
@@ -1,3 +1,3 @@
export { ThemeProvider } from "./ThemeProvider";
export { ApiProvider, useApi } from "./ApiProvider";
-export { AuthProvider, useAuth } from "./AuthProvider";
\ No newline at end of file
+export { AuthProvider, useAuth } from "./AuthProvider";
diff --git a/webapp/src/app/routes/AppRouter.tsx b/webapp/src/app/routes/AppRouter.tsx
index 535a905..4567fbb 100644
--- a/webapp/src/app/routes/AppRouter.tsx
+++ b/webapp/src/app/routes/AppRouter.tsx
@@ -1,5 +1,5 @@
-import { MainPage } from '@pages';
+import { MainPage } from "@pages";
export function AppRouter() {
- return ;
+ return ;
}
diff --git a/webapp/src/app/styles/all4trees.css b/webapp/src/app/styles/all4trees.css
index c59a44f..ec6ddf5 100644
--- a/webapp/src/app/styles/all4trees.css
+++ b/webapp/src/app/styles/all4trees.css
@@ -6,27 +6,31 @@
========================================================================== */
:root {
- /* ========================================================================
+ /* ========================================================================
COULEURS PRINCIPALES - CHARTE ALL4TREES
======================================================================== */
- --color-nuit: #0f0f0f;
- --color-onyx: #424242;
- --color-brunswick-green: #224d41;
- --color-vert-kelly: #54b025;
- --color-jaune-vert: #99cf16;
- --color-citrouille: #f98038;
- --color-alabaster: #f5f4eb;
- --color-bleu: #2d6db4;
- --color-vert-de-gris: #3fafb6;
+ --color-nuit: #0f0f0f;
+ --color-onyx: #424242;
+ --color-brunswick-green: #224d41;
+ --color-vert-kelly: #54b025;
+ --color-jaune-vert: #99cf16;
+ --color-citrouille: #f98038;
+ --color-alabaster: #f5f4eb;
+ --color-bleu: #2d6db4;
+ --color-vert-de-gris: #3fafb6;
- /* ========================================================================
+ /* ========================================================================
TYPOGRAPHIE - CHARTE ALL4TREES
======================================================================== */
- --font-title-primary: "Phosphate", "Phosphate Solid", Impact, "Arial Black", system-ui, sans-serif;
- --font-body-primary: Arial, system-ui, -apple-system, "Segoe UI", sans-serif;
+ --font-title-primary:
+ "Phosphate", "Phosphate Solid", Impact, "Arial Black", system-ui, sans-serif;
+ --font-body-primary: Arial, system-ui, -apple-system, "Segoe UI", sans-serif;
- --font-title-secondary: "Century Gothic", "Century Gothic Black", "Arial Black", system-ui, sans-serif;
- --font-body-secondary: "Open Sans", Arial, system-ui, -apple-system, "Segoe UI", sans-serif;
-}
\ No newline at end of file
+ --font-title-secondary:
+ "Century Gothic", "Century Gothic Black", "Arial Black", system-ui,
+ sans-serif;
+ --font-body-secondary:
+ "Open Sans", Arial, system-ui, -apple-system, "Segoe UI", sans-serif;
+}
diff --git a/webapp/src/app/styles/globals.css b/webapp/src/app/styles/globals.css
index e70dda4..c74a228 100644
--- a/webapp/src/app/styles/globals.css
+++ b/webapp/src/app/styles/globals.css
@@ -12,30 +12,29 @@
RESET CSS
======================================================================== */
-
@import "@app/styles/all4trees.css";
@import "@/index.css";
* {
- margin: 0;
- padding: 0;
- box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
}
html {
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ text-rendering: optimizeLegibility;
}
body {
- font-size: 1rem;
- line-height: 1.5;
- font-weight: 400;
- color-scheme: light dark;
+ font-size: 1rem;
+ line-height: 1.5;
+ font-weight: 400;
+ color-scheme: light dark;
}
h1 {
- font-size: 3.2em;
- line-height: 1.1;
-}
\ No newline at end of file
+ font-size: 3.2em;
+ line-height: 1.1;
+}
diff --git a/webapp/src/components/Charts/ExampleGraph.tsx b/webapp/src/components/Charts/ExampleGraph.tsx
index 0ed7958..2f45d7a 100644
--- a/webapp/src/components/Charts/ExampleGraph.tsx
+++ b/webapp/src/components/Charts/ExampleGraph.tsx
@@ -1,114 +1,116 @@
-import { GitCommitVertical } from "lucide-react"
-import { CartesianGrid, Line, LineChart, XAxis } from "recharts"
+import { GitCommitVertical } from "lucide-react";
+import { CartesianGrid, Line, LineChart, XAxis } from "recharts";
import {
- Card,
- CardContent,
- CardDescription,
- CardHeader,
- CardTitle,
-} from "@ui/card"
+ Card,
+ CardContent,
+ CardDescription,
+ CardHeader,
+ CardTitle,
+} from "@ui/card";
import {
- ChartContainer,
- ChartTooltip,
- ChartTooltipContent,
- type ChartConfig,
-} from "@ui/chart"
+ type ChartConfig,
+ ChartContainer,
+ ChartTooltip,
+ ChartTooltipContent,
+} from "@ui/chart";
-export const description = "A line chart with custom dots"
+export const description = "A line chart with custom dots";
interface DataPoint {
- year: number
- month: number
- kwhConsumed: number
+ year: number;
+ month: number;
+ kwhConsumed: number;
}
export interface GraphConsoElecProps {
- name: string
- chartData: DataPoint[]
+ name: string;
+ chartData: DataPoint[];
}
const chartConfig = {
- year: {
- label: "Année",
- color: "var(--chart-1)",
- },
- month: {
- label: "Mois",
- color: "var(--chart-2)",
- },
- kwhConsumed: {
- label: "kWh Consommés",
- color: "var(--chart-3)",
- },
-} satisfies ChartConfig
+ year: {
+ label: "Année",
+ color: "var(--chart-1)",
+ },
+ month: {
+ label: "Mois",
+ color: "var(--chart-2)",
+ },
+ kwhConsumed: {
+ label: "kWh Consommés",
+ color: "var(--chart-3)",
+ },
+} satisfies ChartConfig;
export function ExampleGraph({ name, chartData }: GraphConsoElecProps) {
- chartData.sort((a, b) => {
- if (a.year === b.year) {
- return a.month - b.month
- }
- return a.year - b.year
- });
- return (
-
-
- Consommation Electrique de {name}
- 2015-2023
-
-
-
-
-
-
-
- }
- />
- {
- const r = payload.kwhConsumed / 20
- return (
-
- )
- }}
- />
-
-
-
-
- )
-}
\ No newline at end of file
+ chartData.sort((a, b) => {
+ if (a.year === b.year) {
+ return a.month - b.month;
+ }
+ return a.year - b.year;
+ });
+ return (
+
+
+
+ Consommation Electrique de {name}
+
+ 2015-2023
+
+
+
+
+
+
+
+ }
+ />
+ {
+ const r = payload.kwhConsumed / 20;
+ return (
+
+ );
+ }}
+ />
+
+
+
+
+ );
+}
diff --git a/webapp/src/components/Header.tsx b/webapp/src/components/Header.tsx
index 21cb396..b187111 100644
--- a/webapp/src/components/Header.tsx
+++ b/webapp/src/components/Header.tsx
@@ -1,46 +1,49 @@
// frontend/src/shared/ui/Header/Header.tsx
import "@app/styles/all4trees.css";
-import logo from '@assets/logo_all4trees.png';
-import { Button } from "@ui/button"
+
+import logo from "@assets/logo_all4trees.png";
+
+import { Button } from "@ui/button";
+
import { ModeToggle } from "./ModeToggle";
interface HeaderProps {
- onLogout: () => void;
- onLogin: () => void;
- isLogin: boolean;
+ onLogout: () => void;
+ onLogin: () => void;
+ isLogin: boolean;
}
-export function Header({
- onLogout,
- onLogin,
- isLogin,
-}: HeaderProps) {
- return (
-
-
-
-

+export function Header({ onLogout, onLogin, isLogin }: HeaderProps) {
+ return (
+
+
+
+

-
- {isLogin ? (
-
- ) : (
-
- )}
-
-
-
-
-
- );
-}
\ No newline at end of file
+
+ {isLogin ? (
+
+ ) : (
+
+ )}
+
+
+
+
+
+ );
+}
diff --git a/webapp/src/components/ModeToggle.tsx b/webapp/src/components/ModeToggle.tsx
index 46850c5..9c9e214 100644
--- a/webapp/src/components/ModeToggle.tsx
+++ b/webapp/src/components/ModeToggle.tsx
@@ -1,36 +1,41 @@
-import { Moon, Sun } from "lucide-react"
+import { Moon, Sun } from "lucide-react";
-import { Button } from "@/components/ui/button"
+import { useTheme } from "@/app/providers/ThemeProvider";
+import { Button } from "@/components/ui/button";
import {
- DropdownMenu,
- DropdownMenuContent,
- DropdownMenuItem,
- DropdownMenuTrigger,
-} from "@/components/ui/dropdown-menu"
-import { useTheme } from "@/app/providers/ThemeProvider"
+ DropdownMenu,
+ DropdownMenuContent,
+ DropdownMenuItem,
+ DropdownMenuTrigger,
+} from "@/components/ui/dropdown-menu";
export function ModeToggle() {
- const { setTheme } = useTheme()
+ const { setTheme } = useTheme();
- return (
-
-
-
-
-
- setTheme("light")}>
- Light
-
- setTheme("dark")}>
- Dark
-
-
-
- )
-
-}
\ No newline at end of file
+ return (
+
+
+
+
+
+ setTheme("light")}>
+ Light
+
+ setTheme("dark")}>
+ Dark
+
+
+
+ );
+}
diff --git a/webapp/src/components/index.ts b/webapp/src/components/index.ts
index 8e2fc40..1d8ab55 100644
--- a/webapp/src/components/index.ts
+++ b/webapp/src/components/index.ts
@@ -1,3 +1,3 @@
export { Header } from "./Header";
export { ModeToggle } from "./ModeToggle";
-export { ExampleGraph, type GraphConsoElecProps } from "./Charts/ExampleGraph";
\ No newline at end of file
+export { ExampleGraph, type GraphConsoElecProps } from "./Charts/ExampleGraph";
diff --git a/webapp/src/components/ui/button.tsx b/webapp/src/components/ui/button.tsx
index 65d4fcd..c478f6d 100644
--- a/webapp/src/components/ui/button.tsx
+++ b/webapp/src/components/ui/button.tsx
@@ -1,8 +1,9 @@
-import * as React from "react"
-import { Slot } from "@radix-ui/react-slot"
-import { cva, type VariantProps } from "class-variance-authority"
+import { type VariantProps, cva } from "class-variance-authority";
+import * as React from "react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
+
+import { Slot } from "@radix-ui/react-slot";
const buttonVariants = cva(
"inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0",
@@ -31,27 +32,28 @@ const buttonVariants = cva(
variant: "default",
size: "default",
},
- }
-)
+ },
+);
export interface ButtonProps
- extends React.ButtonHTMLAttributes,
+ extends
+ React.ButtonHTMLAttributes,
VariantProps {
- asChild?: boolean
+ asChild?: boolean;
}
const Button = React.forwardRef(
({ className, variant, size, asChild = false, ...props }, ref) => {
- const Comp = asChild ? Slot : "button"
+ const Comp = asChild ? Slot : "button";
return (
- )
- }
-)
-Button.displayName = "Button"
+ );
+ },
+);
+Button.displayName = "Button";
-export { Button, buttonVariants }
+export { Button, buttonVariants };
diff --git a/webapp/src/components/ui/card.tsx b/webapp/src/components/ui/card.tsx
index cabfbfc..13b4726 100644
--- a/webapp/src/components/ui/card.tsx
+++ b/webapp/src/components/ui/card.tsx
@@ -1,6 +1,6 @@
-import * as React from "react"
+import * as React from "react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
const Card = React.forwardRef<
HTMLDivElement,
@@ -10,12 +10,12 @@ const Card = React.forwardRef<
ref={ref}
className={cn(
"rounded-xl border bg-card text-card-foreground shadow",
- className
+ className,
)}
{...props}
/>
-))
-Card.displayName = "Card"
+));
+Card.displayName = "Card";
const CardHeader = React.forwardRef<
HTMLDivElement,
@@ -26,8 +26,8 @@ const CardHeader = React.forwardRef<
className={cn("flex flex-col space-y-1.5 p-6", className)}
{...props}
/>
-))
-CardHeader.displayName = "CardHeader"
+));
+CardHeader.displayName = "CardHeader";
const CardTitle = React.forwardRef<
HTMLDivElement,
@@ -38,8 +38,8 @@ const CardTitle = React.forwardRef<
className={cn("font-semibold leading-none tracking-tight", className)}
{...props}
/>
-))
-CardTitle.displayName = "CardTitle"
+));
+CardTitle.displayName = "CardTitle";
const CardDescription = React.forwardRef<
HTMLDivElement,
@@ -50,16 +50,20 @@ const CardDescription = React.forwardRef<
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
-))
-CardDescription.displayName = "CardDescription"
+));
+CardDescription.displayName = "CardDescription";
const CardContent = React.forwardRef<
HTMLDivElement,
React.HTMLAttributes
>(({ className, ...props }, ref) => (
-
-))
-CardContent.displayName = "CardContent"
+
+));
+CardContent.displayName = "CardContent";
const CardFooter = React.forwardRef<
HTMLDivElement,
@@ -70,7 +74,14 @@ const CardFooter = React.forwardRef<
className={cn("flex items-center p-6 pt-0", className)}
{...props}
/>
-))
-CardFooter.displayName = "CardFooter"
+));
+CardFooter.displayName = "CardFooter";
-export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent }
+export {
+ Card,
+ CardHeader,
+ CardFooter,
+ CardTitle,
+ CardDescription,
+ CardContent,
+};
diff --git a/webapp/src/components/ui/chart.tsx b/webapp/src/components/ui/chart.tsx
index 23dc1c1..556804c 100644
--- a/webapp/src/components/ui/chart.tsx
+++ b/webapp/src/components/ui/chart.tsx
@@ -1,48 +1,48 @@
-import * as React from "react"
-import * as RechartsPrimitive from "recharts"
+import * as React from "react";
+import * as RechartsPrimitive from "recharts";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
// Format: { THEME_NAME: CSS_SELECTOR }
-const THEMES = { light: "", dark: ".dark" } as const
+const THEMES = { light: "", dark: ".dark" } as const;
export type ChartConfig = {
[k in string]: {
- label?: React.ReactNode
- icon?: React.ComponentType
+ label?: React.ReactNode;
+ icon?: React.ComponentType;
} & (
| { color?: string; theme?: never }
| { color?: never; theme: Record }
- )
-}
+ );
+};
type ChartContextProps = {
- config: ChartConfig
-}
+ config: ChartConfig;
+};
-const ChartContext = React.createContext(null)
+const ChartContext = React.createContext(null);
function useChart() {
- const context = React.useContext(ChartContext)
+ const context = React.useContext(ChartContext);
if (!context) {
- throw new Error("useChart must be used within a ")
+ throw new Error("useChart must be used within a ");
}
- return context
+ return context;
}
const ChartContainer = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> & {
- config: ChartConfig
+ config: ChartConfig;
children: React.ComponentProps<
typeof RechartsPrimitive.ResponsiveContainer
- >["children"]
+ >["children"];
}
>(({ id, className, children, config, ...props }, ref) => {
- const uniqueId = React.useId()
- const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`
+ const uniqueId = React.useId();
+ const chartId = `chart-${id || uniqueId.replace(/:/g, "")}`;
return (
@@ -51,27 +51,30 @@ const ChartContainer = React.forwardRef<
ref={ref}
className={cn(
"flex aspect-video justify-center text-xs [&_.recharts-cartesian-axis-tick_text]:fill-muted-foreground [&_.recharts-cartesian-grid_line[stroke='#ccc']]:stroke-border/50 [&_.recharts-curve.recharts-tooltip-cursor]:stroke-border [&_.recharts-dot[stroke='#fff']]:stroke-transparent [&_.recharts-layer]:outline-none [&_.recharts-polar-grid_[stroke='#ccc']]:stroke-border [&_.recharts-radial-bar-background-sector]:fill-muted [&_.recharts-rectangle.recharts-tooltip-cursor]:fill-muted [&_.recharts-reference-line_[stroke='#ccc']]:stroke-border [&_.recharts-sector[stroke='#fff']]:stroke-transparent [&_.recharts-sector]:outline-none [&_.recharts-surface]:outline-none",
- className
+ className,
)}
{...props}
>
-
+
{children}
- )
-})
-ChartContainer.displayName = "Chart"
+ );
+});
+ChartContainer.displayName = "Chart";
const ChartStyle = ({ id, config }: { id: string; config: ChartConfig }) => {
const colorConfig = Object.entries(config).filter(
- ([, config]) => config.theme || config.color
- )
+ ([, config]) => config.theme || config.color,
+ );
if (!colorConfig.length) {
- return null
+ return null;
}
return (
@@ -85,30 +88,30 @@ ${colorConfig
.map(([key, itemConfig]) => {
const color =
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] ||
- itemConfig.color
- return color ? ` --color-${key}: ${color};` : null
+ itemConfig.color;
+ return color ? ` --color-${key}: ${color};` : null;
})
.join("\n")}
}
-`
+`,
)
.join("\n"),
}}
/>
- )
-}
+ );
+};
-const ChartTooltip = RechartsPrimitive.Tooltip
+const ChartTooltip = RechartsPrimitive.Tooltip;
const ChartTooltipContent = React.forwardRef<
HTMLDivElement,
React.ComponentProps &
React.ComponentProps<"div"> & {
- hideLabel?: boolean
- hideIndicator?: boolean
- indicator?: "line" | "dot" | "dashed"
- nameKey?: string
- labelKey?: string
+ hideLabel?: boolean;
+ hideIndicator?: boolean;
+ indicator?: "line" | "dot" | "dashed";
+ nameKey?: string;
+ labelKey?: string;
}
>(
(
@@ -127,36 +130,36 @@ const ChartTooltipContent = React.forwardRef<
nameKey,
labelKey,
},
- ref
+ ref,
) => {
- const { config } = useChart()
+ const { config } = useChart();
const tooltipLabel = React.useMemo(() => {
if (hideLabel || !payload?.length) {
- return null
+ return null;
}
- const [item] = payload
- const key = `${labelKey || item?.dataKey || item?.name || "value"}`
- const itemConfig = getPayloadConfigFromPayload(config, item, key)
+ const [item] = payload;
+ const key = `${labelKey || item?.dataKey || item?.name || "value"}`;
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
const value =
!labelKey && typeof label === "string"
? config[label as keyof typeof config]?.label || label
- : itemConfig?.label
+ : itemConfig?.label;
if (labelFormatter) {
return (
{labelFormatter(value, payload)}
- )
+ );
}
if (!value) {
- return null
+ return null;
}
- return {value}
+ return {value}
;
}, [
label,
labelFormatter,
@@ -165,20 +168,20 @@ const ChartTooltipContent = React.forwardRef<
labelClassName,
config,
labelKey,
- ])
+ ]);
if (!active || !payload?.length) {
- return null
+ return null;
}
- const nestLabel = payload.length === 1 && indicator !== "dot"
+ const nestLabel = payload.length === 1 && indicator !== "dot";
return (
{!nestLabel ? tooltipLabel : null}
@@ -186,16 +189,16 @@ const ChartTooltipContent = React.forwardRef<
{payload
.filter((item) => item.type !== "none")
.map((item, index) => {
- const key = `${nameKey || item.name || item.dataKey || "value"}`
- const itemConfig = getPayloadConfigFromPayload(config, item, key)
- const indicatorColor = color || item.payload.fill || item.color
+ const key = `${nameKey || item.name || item.dataKey || "value"}`;
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
+ const indicatorColor = color || item.payload.fill || item.color;
return (
svg]:h-2.5 [&>svg]:w-2.5 [&>svg]:text-muted-foreground",
- indicator === "dot" && "items-center"
+ indicator === "dot" && "items-center",
)}
>
{formatter && item?.value !== undefined && item.name ? (
@@ -215,7 +218,7 @@ const ChartTooltipContent = React.forwardRef<
"w-0 border-[1.5px] border-dashed bg-transparent":
indicator === "dashed",
"my-0.5": nestLabel && indicator === "dashed",
- }
+ },
)}
style={
{
@@ -229,7 +232,7 @@ const ChartTooltipContent = React.forwardRef<
@@ -247,33 +250,33 @@ const ChartTooltipContent = React.forwardRef<
>
)}
- )
+ );
})}
- )
- }
-)
-ChartTooltipContent.displayName = "ChartTooltip"
+ );
+ },
+);
+ChartTooltipContent.displayName = "ChartTooltip";
-const ChartLegend = RechartsPrimitive.Legend
+const ChartLegend = RechartsPrimitive.Legend;
const ChartLegendContent = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> &
Pick
& {
- hideIcon?: boolean
- nameKey?: string
+ hideIcon?: boolean;
+ nameKey?: string;
}
>(
(
{ className, hideIcon = false, payload, verticalAlign = "bottom", nameKey },
- ref
+ ref,
) => {
- const { config } = useChart()
+ const { config } = useChart();
if (!payload?.length) {
- return null
+ return null;
}
return (
@@ -282,20 +285,20 @@ const ChartLegendContent = React.forwardRef<
className={cn(
"flex items-center justify-center gap-4",
verticalAlign === "top" ? "pb-3" : "pt-3",
- className
+ className,
)}
>
{payload
.filter((item) => item.type !== "none")
.map((item) => {
- const key = `${nameKey || item.dataKey || "value"}`
- const itemConfig = getPayloadConfigFromPayload(config, item, key)
+ const key = `${nameKey || item.dataKey || "value"}`;
+ const itemConfig = getPayloadConfigFromPayload(config, item, key);
return (
svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground"
+ "flex items-center gap-1.5 [&>svg]:h-3 [&>svg]:w-3 [&>svg]:text-muted-foreground",
)}
>
{itemConfig?.icon && !hideIcon ? (
@@ -310,22 +313,22 @@ const ChartLegendContent = React.forwardRef<
)}
{itemConfig?.label}
- )
+ );
})}
- )
- }
-)
-ChartLegendContent.displayName = "ChartLegend"
+ );
+ },
+);
+ChartLegendContent.displayName = "ChartLegend";
// Helper to extract item config from a payload.
function getPayloadConfigFromPayload(
config: ChartConfig,
payload: unknown,
- key: string
+ key: string,
) {
if (typeof payload !== "object" || payload === null) {
- return undefined
+ return undefined;
}
const payloadPayload =
@@ -333,15 +336,15 @@ function getPayloadConfigFromPayload(
typeof payload.payload === "object" &&
payload.payload !== null
? payload.payload
- : undefined
+ : undefined;
- let configLabelKey: string = key
+ let configLabelKey: string = key;
if (
key in payload &&
typeof payload[key as keyof typeof payload] === "string"
) {
- configLabelKey = payload[key as keyof typeof payload] as string
+ configLabelKey = payload[key as keyof typeof payload] as string;
} else if (
payloadPayload &&
key in payloadPayload &&
@@ -349,12 +352,12 @@ function getPayloadConfigFromPayload(
) {
configLabelKey = payloadPayload[
key as keyof typeof payloadPayload
- ] as string
+ ] as string;
}
return configLabelKey in config
? config[configLabelKey]
- : config[key as keyof typeof config]
+ : config[key as keyof typeof config];
}
export {
@@ -364,4 +367,4 @@ export {
ChartLegend,
ChartLegendContent,
ChartStyle,
-}
+};
diff --git a/webapp/src/components/ui/dropdown-menu.tsx b/webapp/src/components/ui/dropdown-menu.tsx
index e804bca..5b67ee7 100644
--- a/webapp/src/components/ui/dropdown-menu.tsx
+++ b/webapp/src/components/ui/dropdown-menu.tsx
@@ -1,25 +1,26 @@
-import * as React from "react"
-import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"
-import { Check, ChevronRight, Circle } from "lucide-react"
+import { Check, ChevronRight, Circle } from "lucide-react";
+import * as React from "react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
-const DropdownMenu = DropdownMenuPrimitive.Root
+import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
-const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger
+const DropdownMenu = DropdownMenuPrimitive.Root;
-const DropdownMenuGroup = DropdownMenuPrimitive.Group
+const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
-const DropdownMenuPortal = DropdownMenuPrimitive.Portal
+const DropdownMenuGroup = DropdownMenuPrimitive.Group;
-const DropdownMenuSub = DropdownMenuPrimitive.Sub
+const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
-const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup
+const DropdownMenuSub = DropdownMenuPrimitive.Sub;
+
+const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
const DropdownMenuSubTrigger = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef & {
- inset?: boolean
+ inset?: boolean;
}
>(({ className, inset, children, ...props }, ref) => (
{children}
-))
+));
DropdownMenuSubTrigger.displayName =
- DropdownMenuPrimitive.SubTrigger.displayName
+ DropdownMenuPrimitive.SubTrigger.displayName;
const DropdownMenuSubContent = React.forwardRef<
React.ElementRef,
@@ -46,13 +47,13 @@ const DropdownMenuSubContent = React.forwardRef<
ref={ref}
className={cn(
"z-50 min-w-[8rem] overflow-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-lg data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",
- className
+ className,
)}
{...props}
/>
-))
+));
DropdownMenuSubContent.displayName =
- DropdownMenuPrimitive.SubContent.displayName
+ DropdownMenuPrimitive.SubContent.displayName;
const DropdownMenuContent = React.forwardRef<
React.ElementRef,
@@ -65,18 +66,18 @@ const DropdownMenuContent = React.forwardRef<
className={cn(
"z-50 max-h-[var(--radix-dropdown-menu-content-available-height)] min-w-[8rem] overflow-y-auto overflow-x-hidden rounded-md border bg-popover p-1 text-popover-foreground shadow-md",
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-dropdown-menu-content-transform-origin]",
- className
+ className,
)}
{...props}
/>
-))
-DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName
+));
+DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName;
const DropdownMenuItem = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef & {
- inset?: boolean
+ inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
svg]:size-4 [&>svg]:shrink-0",
inset && "pl-8",
- className
+ className,
)}
{...props}
/>
-))
-DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName
+));
+DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName;
const DropdownMenuCheckboxItem = React.forwardRef<
React.ElementRef,
@@ -99,7 +100,7 @@ const DropdownMenuCheckboxItem = React.forwardRef<
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
- className
+ className,
)}
checked={checked}
{...props}
@@ -111,9 +112,9 @@ const DropdownMenuCheckboxItem = React.forwardRef<
{children}
-))
+));
DropdownMenuCheckboxItem.displayName =
- DropdownMenuPrimitive.CheckboxItem.displayName
+ DropdownMenuPrimitive.CheckboxItem.displayName;
const DropdownMenuRadioItem = React.forwardRef<
React.ElementRef,
@@ -123,7 +124,7 @@ const DropdownMenuRadioItem = React.forwardRef<
ref={ref}
className={cn(
"relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
- className
+ className,
)}
{...props}
>
@@ -134,13 +135,13 @@ const DropdownMenuRadioItem = React.forwardRef<
{children}
-))
-DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName
+));
+DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName;
const DropdownMenuLabel = React.forwardRef<
React.ElementRef,
React.ComponentPropsWithoutRef & {
- inset?: boolean
+ inset?: boolean;
}
>(({ className, inset, ...props }, ref) => (
-))
-DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName
+));
+DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName;
const DropdownMenuSeparator = React.forwardRef<
React.ElementRef,
@@ -164,8 +165,8 @@ const DropdownMenuSeparator = React.forwardRef<
className={cn("-mx-1 my-1 h-px bg-muted", className)}
{...props}
/>
-))
-DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName
+));
+DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName;
const DropdownMenuShortcut = ({
className,
@@ -176,9 +177,9 @@ const DropdownMenuShortcut = ({
className={cn("ml-auto text-xs tracking-widest opacity-60", className)}
{...props}
/>
- )
-}
-DropdownMenuShortcut.displayName = "DropdownMenuShortcut"
+ );
+};
+DropdownMenuShortcut.displayName = "DropdownMenuShortcut";
export {
DropdownMenu,
@@ -196,4 +197,4 @@ export {
DropdownMenuSubContent,
DropdownMenuSubTrigger,
DropdownMenuRadioGroup,
-}
+};
diff --git a/webapp/src/components/ui/input.tsx b/webapp/src/components/ui/input.tsx
index 69b64fb..7db5241 100644
--- a/webapp/src/components/ui/input.tsx
+++ b/webapp/src/components/ui/input.tsx
@@ -1,6 +1,6 @@
-import * as React from "react"
+import * as React from "react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
const Input = React.forwardRef>(
({ className, type, ...props }, ref) => {
@@ -9,14 +9,14 @@ const Input = React.forwardRef>(
type={type}
className={cn(
"flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-base shadow-sm transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium file:text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
- className
+ className,
)}
ref={ref}
{...props}
/>
- )
- }
-)
-Input.displayName = "Input"
+ );
+ },
+);
+Input.displayName = "Input";
-export { Input }
+export { Input };
diff --git a/webapp/src/components/ui/label.tsx b/webapp/src/components/ui/label.tsx
index 683faa7..36ab4e7 100644
--- a/webapp/src/components/ui/label.tsx
+++ b/webapp/src/components/ui/label.tsx
@@ -1,12 +1,13 @@
-import * as React from "react"
-import * as LabelPrimitive from "@radix-ui/react-label"
-import { cva, type VariantProps } from "class-variance-authority"
+import { type VariantProps, cva } from "class-variance-authority";
+import * as React from "react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
+
+import * as LabelPrimitive from "@radix-ui/react-label";
const labelVariants = cva(
- "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"
-)
+ "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70",
+);
const Label = React.forwardRef<
React.ElementRef,
@@ -18,7 +19,7 @@ const Label = React.forwardRef<
className={cn(labelVariants(), className)}
{...props}
/>
-))
-Label.displayName = LabelPrimitive.Root.displayName
+));
+Label.displayName = LabelPrimitive.Root.displayName;
-export { Label }
+export { Label };
diff --git a/webapp/src/components/ui/popover.tsx b/webapp/src/components/ui/popover.tsx
index fdcb511..f9f8d87 100644
--- a/webapp/src/components/ui/popover.tsx
+++ b/webapp/src/components/ui/popover.tsx
@@ -1,13 +1,14 @@
-import * as React from "react"
-import * as PopoverPrimitive from "@radix-ui/react-popover"
+import * as React from "react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
-const Popover = PopoverPrimitive.Root
+import * as PopoverPrimitive from "@radix-ui/react-popover";
-const PopoverTrigger = PopoverPrimitive.Trigger
+const Popover = PopoverPrimitive.Root;
-const PopoverAnchor = PopoverPrimitive.Anchor
+const PopoverTrigger = PopoverPrimitive.Trigger;
+
+const PopoverAnchor = PopoverPrimitive.Anchor;
const PopoverContent = React.forwardRef<
React.ElementRef,
@@ -20,12 +21,12 @@ const PopoverContent = React.forwardRef<
sideOffset={sideOffset}
className={cn(
"z-50 w-72 rounded-md border bg-popover p-4 text-popover-foreground shadow-md outline-none data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-popover-content-transform-origin]",
- className
+ className,
)}
{...props}
/>
-))
-PopoverContent.displayName = PopoverPrimitive.Content.displayName
+));
+PopoverContent.displayName = PopoverPrimitive.Content.displayName;
-export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }
+export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
diff --git a/webapp/src/components/ui/radio-group.tsx b/webapp/src/components/ui/radio-group.tsx
index 9d3a26e..b05ebe3 100644
--- a/webapp/src/components/ui/radio-group.tsx
+++ b/webapp/src/components/ui/radio-group.tsx
@@ -1,8 +1,9 @@
-import * as React from "react"
-import * as RadioGroupPrimitive from "@radix-ui/react-radio-group"
-import { Circle } from "lucide-react"
+import { Circle } from "lucide-react";
+import * as React from "react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
+
+import * as RadioGroupPrimitive from "@radix-ui/react-radio-group";
const RadioGroup = React.forwardRef<
React.ElementRef,
@@ -14,9 +15,9 @@ const RadioGroup = React.forwardRef<
{...props}
ref={ref}
/>
- )
-})
-RadioGroup.displayName = RadioGroupPrimitive.Root.displayName
+ );
+});
+RadioGroup.displayName = RadioGroupPrimitive.Root.displayName;
const RadioGroupItem = React.forwardRef<
React.ElementRef,
@@ -27,7 +28,7 @@ const RadioGroupItem = React.forwardRef<
ref={ref}
className={cn(
"aspect-square h-4 w-4 rounded-full border border-primary text-primary shadow focus:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
- className
+ className,
)}
{...props}
>
@@ -35,8 +36,8 @@ const RadioGroupItem = React.forwardRef<
- )
-})
-RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName
+ );
+});
+RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName;
-export { RadioGroup, RadioGroupItem }
+export { RadioGroup, RadioGroupItem };
diff --git a/webapp/src/components/ui/resizable.tsx b/webapp/src/components/ui/resizable.tsx
index cd3cb0e..4460345 100644
--- a/webapp/src/components/ui/resizable.tsx
+++ b/webapp/src/components/ui/resizable.tsx
@@ -1,7 +1,7 @@
-import { GripVertical } from "lucide-react"
-import * as ResizablePrimitive from "react-resizable-panels"
+import { GripVertical } from "lucide-react";
+import * as ResizablePrimitive from "react-resizable-panels";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
const ResizablePanelGroup = ({
className,
@@ -10,25 +10,25 @@ const ResizablePanelGroup = ({
-)
+);
-const ResizablePanel = ResizablePrimitive.Panel
+const ResizablePanel = ResizablePrimitive.Panel;
const ResizableHandle = ({
withHandle,
className,
...props
}: React.ComponentProps & {
- withHandle?: boolean
+ withHandle?: boolean;
}) => (
div]:rotate-90",
- className
+ className,
)}
{...props}
>
@@ -38,6 +38,6 @@ const ResizableHandle = ({
)}
-)
+);
-export { ResizablePanelGroup, ResizablePanel, ResizableHandle }
+export { ResizablePanelGroup, ResizablePanel, ResizableHandle };
diff --git a/webapp/src/components/ui/separator.tsx b/webapp/src/components/ui/separator.tsx
index 6d7f122..a7bacae 100644
--- a/webapp/src/components/ui/separator.tsx
+++ b/webapp/src/components/ui/separator.tsx
@@ -1,7 +1,8 @@
-import * as React from "react"
-import * as SeparatorPrimitive from "@radix-ui/react-separator"
+import * as React from "react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
+
+import * as SeparatorPrimitive from "@radix-ui/react-separator";
const Separator = React.forwardRef<
React.ElementRef,
@@ -9,7 +10,7 @@ const Separator = React.forwardRef<
>(
(
{ className, orientation = "horizontal", decorative = true, ...props },
- ref
+ ref,
) => (
- )
-)
-Separator.displayName = SeparatorPrimitive.Root.displayName
+ ),
+);
+Separator.displayName = SeparatorPrimitive.Root.displayName;
-export { Separator }
+export { Separator };
diff --git a/webapp/src/components/ui/sheet.tsx b/webapp/src/components/ui/sheet.tsx
index 272cb72..19a2a68 100644
--- a/webapp/src/components/ui/sheet.tsx
+++ b/webapp/src/components/ui/sheet.tsx
@@ -1,19 +1,20 @@
-"use client"
+"use client";
-import * as React from "react"
-import * as SheetPrimitive from "@radix-ui/react-dialog"
-import { cva, type VariantProps } from "class-variance-authority"
-import { X } from "lucide-react"
+import { type VariantProps, cva } from "class-variance-authority";
+import { X } from "lucide-react";
+import * as React from "react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
-const Sheet = SheetPrimitive.Root
+import * as SheetPrimitive from "@radix-ui/react-dialog";
-const SheetTrigger = SheetPrimitive.Trigger
+const Sheet = SheetPrimitive.Root;
-const SheetClose = SheetPrimitive.Close
+const SheetTrigger = SheetPrimitive.Trigger;
-const SheetPortal = SheetPrimitive.Portal
+const SheetClose = SheetPrimitive.Close;
+
+const SheetPortal = SheetPrimitive.Portal;
const SheetOverlay = React.forwardRef<
React.ElementRef,
@@ -22,13 +23,13 @@ const SheetOverlay = React.forwardRef<
-))
-SheetOverlay.displayName = SheetPrimitive.Overlay.displayName
+));
+SheetOverlay.displayName = SheetPrimitive.Overlay.displayName;
const sheetVariants = cva(
"fixed z-50 gap-4 bg-background p-6 shadow-lg transition ease-in-out data-[state=closed]:duration-300 data-[state=open]:duration-500 data-[state=open]:animate-in data-[state=closed]:animate-out",
@@ -46,11 +47,12 @@ const sheetVariants = cva(
defaultVariants: {
side: "right",
},
- }
-)
+ },
+);
interface SheetContentProps
- extends React.ComponentPropsWithoutRef,
+ extends
+ React.ComponentPropsWithoutRef,
VariantProps {}
const SheetContent = React.forwardRef<
@@ -71,8 +73,8 @@ const SheetContent = React.forwardRef<
{children}
-))
-SheetContent.displayName = SheetPrimitive.Content.displayName
+));
+SheetContent.displayName = SheetPrimitive.Content.displayName;
const SheetHeader = ({
className,
@@ -81,12 +83,12 @@ const SheetHeader = ({
-)
-SheetHeader.displayName = "SheetHeader"
+);
+SheetHeader.displayName = "SheetHeader";
const SheetFooter = ({
className,
@@ -95,12 +97,12 @@ const SheetFooter = ({
-)
-SheetFooter.displayName = "SheetFooter"
+);
+SheetFooter.displayName = "SheetFooter";
const SheetTitle = React.forwardRef<
React.ElementRef,
@@ -111,8 +113,8 @@ const SheetTitle = React.forwardRef<
className={cn("text-lg font-semibold text-foreground", className)}
{...props}
/>
-))
-SheetTitle.displayName = SheetPrimitive.Title.displayName
+));
+SheetTitle.displayName = SheetPrimitive.Title.displayName;
const SheetDescription = React.forwardRef<
React.ElementRef,
@@ -123,8 +125,8 @@ const SheetDescription = React.forwardRef<
className={cn("text-sm text-muted-foreground", className)}
{...props}
/>
-))
-SheetDescription.displayName = SheetPrimitive.Description.displayName
+));
+SheetDescription.displayName = SheetPrimitive.Description.displayName;
export {
Sheet,
@@ -137,4 +139,4 @@ export {
SheetFooter,
SheetTitle,
SheetDescription,
-}
+};
diff --git a/webapp/src/components/ui/sidebar.tsx b/webapp/src/components/ui/sidebar.tsx
index c7ca99c..bb7f7c5 100644
--- a/webapp/src/components/ui/sidebar.tsx
+++ b/webapp/src/components/ui/sidebar.tsx
@@ -1,62 +1,63 @@
-import * as React from "react"
-import { Slot } from "@radix-ui/react-slot"
-import { cva, type VariantProps } from "class-variance-authority"
-import { PanelLeft } from "lucide-react"
-
-import { useIsMobile } from "@/hooks/use-mobile"
-import { cn } from "@/lib/utils"
-import { Button } from "@/components/ui/button"
-import { Input } from "@/components/ui/input"
-import { Separator } from "@/components/ui/separator"
+import { type VariantProps, cva } from "class-variance-authority";
+import { PanelLeft } from "lucide-react";
+import * as React from "react";
+
+import { Button } from "@/components/ui/button";
+import { Input } from "@/components/ui/input";
+import { Separator } from "@/components/ui/separator";
import {
Sheet,
SheetContent,
SheetDescription,
SheetHeader,
SheetTitle,
-} from "@/components/ui/sheet"
-import { Skeleton } from "@/components/ui/skeleton"
+} from "@/components/ui/sheet";
+import { Skeleton } from "@/components/ui/skeleton";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
-} from "@/components/ui/tooltip"
+} from "@/components/ui/tooltip";
+import { useIsMobile } from "@/hooks/use-mobile";
+import { cn } from "@/lib/utils";
+
+import { Slot } from "@radix-ui/react-slot";
-const SIDEBAR_COOKIE_NAME = "sidebar_state"
-const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7
-const SIDEBAR_WIDTH = "16rem"
-const SIDEBAR_WIDTH_MOBILE = "18rem"
-const SIDEBAR_WIDTH_ICON = "3rem"
-const SIDEBAR_KEYBOARD_SHORTCUT = "b"
+const SIDEBAR_COOKIE_NAME = "sidebar_state";
+const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7;
+const SIDEBAR_WIDTH = "16rem";
+const SIDEBAR_WIDTH_MOBILE = "18rem";
+const SIDEBAR_WIDTH_ICON = "3rem";
+const SIDEBAR_KEYBOARD_SHORTCUT = "b";
type SidebarContextProps = {
- state: "expanded" | "collapsed"
- open: boolean
- setOpen: (open: boolean) => void
- openMobile: boolean
- setOpenMobile: (open: boolean) => void
- isMobile: boolean
- toggleSidebar: () => void
-}
+ state: "expanded" | "collapsed";
+ open: boolean;
+ setOpen: (open: boolean) => void;
+ openMobile: boolean;
+ setOpenMobile: (open: boolean) => void;
+ isMobile: boolean;
+ toggleSidebar: () => void;
+};
-const SidebarContext = React.createContext(null)
+const SidebarContext = React.createContext(null);
function useSidebar() {
- const context = React.useContext(SidebarContext)
+ const context = React.useContext(SidebarContext);
if (!context) {
- throw new Error("useSidebar must be used within a SidebarProvider.")
+ throw new Error("useSidebar must be used within a SidebarProvider.");
}
- return context
+ return context;
}
const SidebarProvider = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> & {
- defaultOpen?: boolean
- open?: boolean
- onOpenChange?: (open: boolean) => void
+ defaultOpen?: boolean;
+ open?: boolean;
+ onOpenChange?: (open: boolean) => void;
}
>(
(
@@ -69,36 +70,36 @@ const SidebarProvider = React.forwardRef<
children,
...props
},
- ref
+ ref,
) => {
- const isMobile = useIsMobile()
- const [openMobile, setOpenMobile] = React.useState(false)
+ const isMobile = useIsMobile();
+ const [openMobile, setOpenMobile] = React.useState(false);
// This is the internal state of the sidebar.
// We use openProp and setOpenProp for control from outside the component.
- const [_open, _setOpen] = React.useState(defaultOpen)
- const open = openProp ?? _open
+ const [_open, _setOpen] = React.useState(defaultOpen);
+ const open = openProp ?? _open;
const setOpen = React.useCallback(
(value: boolean | ((value: boolean) => boolean)) => {
- const openState = typeof value === "function" ? value(open) : value
+ const openState = typeof value === "function" ? value(open) : value;
if (setOpenProp) {
- setOpenProp(openState)
+ setOpenProp(openState);
} else {
- _setOpen(openState)
+ _setOpen(openState);
}
// This sets the cookie to keep the sidebar state.
- document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`
+ document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`;
},
- [setOpenProp, open]
- )
+ [setOpenProp, open],
+ );
// Helper to toggle the sidebar.
const toggleSidebar = React.useCallback(() => {
return isMobile
? setOpenMobile((open) => !open)
- : setOpen((open) => !open)
- }, [isMobile, setOpen, setOpenMobile])
+ : setOpen((open) => !open);
+ }, [isMobile, setOpen, setOpenMobile]);
// Adds a keyboard shortcut to toggle the sidebar.
React.useEffect(() => {
@@ -107,18 +108,18 @@ const SidebarProvider = React.forwardRef<
event.key === SIDEBAR_KEYBOARD_SHORTCUT &&
(event.metaKey || event.ctrlKey)
) {
- event.preventDefault()
- toggleSidebar()
+ event.preventDefault();
+ toggleSidebar();
}
- }
+ };
- window.addEventListener("keydown", handleKeyDown)
- return () => window.removeEventListener("keydown", handleKeyDown)
- }, [toggleSidebar])
+ window.addEventListener("keydown", handleKeyDown);
+ return () => window.removeEventListener("keydown", handleKeyDown);
+ }, [toggleSidebar]);
// We add a state so that we can do data-state="expanded" or "collapsed".
// This makes it easier to style the sidebar with Tailwind classes.
- const state = open ? "expanded" : "collapsed"
+ const state = open ? "expanded" : "collapsed";
const contextValue = React.useMemo(
() => ({
@@ -130,8 +131,16 @@ const SidebarProvider = React.forwardRef<
setOpenMobile,
toggleSidebar,
}),
- [state, open, setOpen, isMobile, openMobile, setOpenMobile, toggleSidebar]
- )
+ [
+ state,
+ open,
+ setOpen,
+ isMobile,
+ openMobile,
+ setOpenMobile,
+ toggleSidebar,
+ ],
+ );
return (
@@ -146,7 +155,7 @@ const SidebarProvider = React.forwardRef<
}
className={cn(
"group/sidebar-wrapper flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar",
- className
+ className,
)}
ref={ref}
{...props}
@@ -155,17 +164,17 @@ const SidebarProvider = React.forwardRef<
- )
- }
-)
-SidebarProvider.displayName = "SidebarProvider"
+ );
+ },
+);
+SidebarProvider.displayName = "SidebarProvider";
const Sidebar = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> & {
- side?: "left" | "right"
- variant?: "sidebar" | "floating" | "inset"
- collapsible?: "offcanvas" | "icon" | "none"
+ side?: "left" | "right";
+ variant?: "sidebar" | "floating" | "inset";
+ collapsible?: "offcanvas" | "icon" | "none";
}
>(
(
@@ -177,28 +186,32 @@ const Sidebar = React.forwardRef<
children,
...props
},
- ref
+ ref,
) => {
- const { isMobile, state, openMobile, setOpenMobile } = useSidebar()
+ const { isMobile, state, openMobile, setOpenMobile } = useSidebar();
if (collapsible === "none") {
return (
{children}
- )
+ );
}
if (isMobile) {
return (
-
+
{children}
- )
+ );
}
return (
@@ -237,7 +250,7 @@ const Sidebar = React.forwardRef<
"group-data-[side=right]:rotate-180",
variant === "floating" || variant === "inset"
? "group-data-[collapsible=icon]:w-[calc(var(--sidebar-width-icon)_+_theme(spacing.4))]"
- : "group-data-[collapsible=icon]:w-[--sidebar-width-icon]"
+ : "group-data-[collapsible=icon]:w-[--sidebar-width-icon]",
)}
/>
@@ -262,16 +275,16 @@ const Sidebar = React.forwardRef<
- )
- }
-)
-Sidebar.displayName = "Sidebar"
+ );
+ },
+);
+Sidebar.displayName = "Sidebar";
const SidebarTrigger = React.forwardRef<
React.ElementRef,
React.ComponentProps
>(({ className, onClick, ...props }, ref) => {
- const { toggleSidebar } = useSidebar()
+ const { toggleSidebar } = useSidebar();
return (
- )
-})
-SidebarTrigger.displayName = "SidebarTrigger"
+ );
+});
+SidebarTrigger.displayName = "SidebarTrigger";
const SidebarRail = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<"button">
>(({ className, ...props }, ref) => {
- const { toggleSidebar } = useSidebar()
+ const { toggleSidebar } = useSidebar();
return (
- )
-})
-SidebarRail.displayName = "SidebarRail"
+ );
+});
+SidebarRail.displayName = "SidebarRail";
const SidebarInset = React.forwardRef<
HTMLDivElement,
@@ -332,13 +345,13 @@ const SidebarInset = React.forwardRef<
className={cn(
"relative flex w-full flex-1 flex-col bg-background",
"md:peer-data-[variant=inset]:m-2 md:peer-data-[state=collapsed]:peer-data-[variant=inset]:ml-2 md:peer-data-[variant=inset]:ml-0 md:peer-data-[variant=inset]:rounded-xl md:peer-data-[variant=inset]:shadow",
- className
+ className,
)}
{...props}
/>
- )
-})
-SidebarInset.displayName = "SidebarInset"
+ );
+});
+SidebarInset.displayName = "SidebarInset";
const SidebarInput = React.forwardRef<
React.ElementRef,
@@ -350,13 +363,13 @@ const SidebarInput = React.forwardRef<
data-sidebar="input"
className={cn(
"h-8 w-full bg-background shadow-none focus-visible:ring-2 focus-visible:ring-sidebar-ring",
- className
+ className,
)}
{...props}
/>
- )
-})
-SidebarInput.displayName = "SidebarInput"
+ );
+});
+SidebarInput.displayName = "SidebarInput";
const SidebarHeader = React.forwardRef<
HTMLDivElement,
@@ -369,9 +382,9 @@ const SidebarHeader = React.forwardRef<
className={cn("flex flex-col gap-2 p-2", className)}
{...props}
/>
- )
-})
-SidebarHeader.displayName = "SidebarHeader"
+ );
+});
+SidebarHeader.displayName = "SidebarHeader";
const SidebarFooter = React.forwardRef<
HTMLDivElement,
@@ -384,9 +397,9 @@ const SidebarFooter = React.forwardRef<
className={cn("flex flex-col gap-2 p-2", className)}
{...props}
/>
- )
-})
-SidebarFooter.displayName = "SidebarFooter"
+ );
+});
+SidebarFooter.displayName = "SidebarFooter";
const SidebarSeparator = React.forwardRef<
React.ElementRef,
@@ -399,9 +412,9 @@ const SidebarSeparator = React.forwardRef<
className={cn("mx-2 w-auto bg-sidebar-border", className)}
{...props}
/>
- )
-})
-SidebarSeparator.displayName = "SidebarSeparator"
+ );
+});
+SidebarSeparator.displayName = "SidebarSeparator";
const SidebarContent = React.forwardRef<
HTMLDivElement,
@@ -413,13 +426,13 @@ const SidebarContent = React.forwardRef<
data-sidebar="content"
className={cn(
"flex min-h-0 flex-1 flex-col gap-2 overflow-auto group-data-[collapsible=icon]:overflow-hidden",
- className
+ className,
)}
{...props}
/>
- )
-})
-SidebarContent.displayName = "SidebarContent"
+ );
+});
+SidebarContent.displayName = "SidebarContent";
const SidebarGroup = React.forwardRef<
HTMLDivElement,
@@ -432,15 +445,15 @@ const SidebarGroup = React.forwardRef<
className={cn("relative flex w-full min-w-0 flex-col p-2", className)}
{...props}
/>
- )
-})
-SidebarGroup.displayName = "SidebarGroup"
+ );
+});
+SidebarGroup.displayName = "SidebarGroup";
const SidebarGroupLabel = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> & { asChild?: boolean }
>(({ className, asChild = false, ...props }, ref) => {
- const Comp = asChild ? Slot : "div"
+ const Comp = asChild ? Slot : "div";
return (
svg]:size-4 [&>svg]:shrink-0",
"group-data-[collapsible=icon]:-mt-8 group-data-[collapsible=icon]:opacity-0",
- className
+ className,
)}
{...props}
/>
- )
-})
-SidebarGroupLabel.displayName = "SidebarGroupLabel"
+ );
+});
+SidebarGroupLabel.displayName = "SidebarGroupLabel";
const SidebarGroupAction = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<"button"> & { asChild?: boolean }
>(({ className, asChild = false, ...props }, ref) => {
- const Comp = asChild ? Slot : "button"
+ const Comp = asChild ? Slot : "button";
return (
- )
-})
-SidebarGroupAction.displayName = "SidebarGroupAction"
+ );
+});
+SidebarGroupAction.displayName = "SidebarGroupAction";
const SidebarGroupContent = React.forwardRef<
HTMLDivElement,
@@ -490,8 +503,8 @@ const SidebarGroupContent = React.forwardRef<
className={cn("w-full text-sm", className)}
{...props}
/>
-))
-SidebarGroupContent.displayName = "SidebarGroupContent"
+));
+SidebarGroupContent.displayName = "SidebarGroupContent";
const SidebarMenu = React.forwardRef<
HTMLUListElement,
@@ -503,8 +516,8 @@ const SidebarMenu = React.forwardRef<
className={cn("flex w-full min-w-0 flex-col gap-1", className)}
{...props}
/>
-))
-SidebarMenu.displayName = "SidebarMenu"
+));
+SidebarMenu.displayName = "SidebarMenu";
const SidebarMenuItem = React.forwardRef<
HTMLLIElement,
@@ -516,8 +529,8 @@ const SidebarMenuItem = React.forwardRef<
className={cn("group/menu-item relative", className)}
{...props}
/>
-))
-SidebarMenuItem.displayName = "SidebarMenuItem"
+));
+SidebarMenuItem.displayName = "SidebarMenuItem";
const sidebarMenuButtonVariants = cva(
"peer/menu-button flex w-full items-center gap-2 overflow-hidden rounded-md p-2 text-left text-sm outline-none ring-sidebar-ring transition-[width,height,padding] hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:ring-2 active:bg-sidebar-accent active:text-sidebar-accent-foreground disabled:pointer-events-none disabled:opacity-50 group-has-[[data-sidebar=menu-action]]/menu-item:pr-8 aria-disabled:pointer-events-none aria-disabled:opacity-50 data-[active=true]:bg-sidebar-accent data-[active=true]:font-medium data-[active=true]:text-sidebar-accent-foreground data-[state=open]:hover:bg-sidebar-accent data-[state=open]:hover:text-sidebar-accent-foreground group-data-[collapsible=icon]:!size-8 group-data-[collapsible=icon]:!p-2 [&>span:last-child]:truncate [&>svg]:size-4 [&>svg]:shrink-0",
@@ -538,15 +551,15 @@ const sidebarMenuButtonVariants = cva(
variant: "default",
size: "default",
},
- }
-)
+ },
+);
const SidebarMenuButton = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<"button"> & {
- asChild?: boolean
- isActive?: boolean
- tooltip?: string | React.ComponentProps
+ asChild?: boolean;
+ isActive?: boolean;
+ tooltip?: string | React.ComponentProps;
} & VariantProps
>(
(
@@ -559,10 +572,10 @@ const SidebarMenuButton = React.forwardRef<
className,
...props
},
- ref
+ ref,
) => {
- const Comp = asChild ? Slot : "button"
- const { isMobile, state } = useSidebar()
+ const Comp = asChild ? Slot : "button";
+ const { isMobile, state } = useSidebar();
const button = (
- )
+ );
if (!tooltip) {
- return button
+ return button;
}
if (typeof tooltip === "string") {
tooltip = {
children: tooltip,
- }
+ };
}
return (
@@ -595,19 +608,19 @@ const SidebarMenuButton = React.forwardRef<
{...tooltip}
/>
- )
- }
-)
-SidebarMenuButton.displayName = "SidebarMenuButton"
+ );
+ },
+);
+SidebarMenuButton.displayName = "SidebarMenuButton";
const SidebarMenuAction = React.forwardRef<
HTMLButtonElement,
React.ComponentProps<"button"> & {
- asChild?: boolean
- showOnHover?: boolean
+ asChild?: boolean;
+ showOnHover?: boolean;
}
>(({ className, asChild = false, showOnHover = false, ...props }, ref) => {
- const Comp = asChild ? Slot : "button"
+ const Comp = asChild ? Slot : "button";
return (
- )
-})
-SidebarMenuAction.displayName = "SidebarMenuAction"
+ );
+});
+SidebarMenuAction.displayName = "SidebarMenuAction";
const SidebarMenuBadge = React.forwardRef<
HTMLDivElement,
@@ -645,23 +658,23 @@ const SidebarMenuBadge = React.forwardRef<
"peer-data-[size=default]/menu-button:top-1.5",
"peer-data-[size=lg]/menu-button:top-2.5",
"group-data-[collapsible=icon]:hidden",
- className
+ className,
)}
{...props}
/>
-))
-SidebarMenuBadge.displayName = "SidebarMenuBadge"
+));
+SidebarMenuBadge.displayName = "SidebarMenuBadge";
const SidebarMenuSkeleton = React.forwardRef<
HTMLDivElement,
React.ComponentProps<"div"> & {
- showIcon?: boolean
+ showIcon?: boolean;
}
>(({ className, showIcon = false, ...props }, ref) => {
// Random width between 50 to 90%.
const width = React.useMemo(() => {
- return `${Math.floor(Math.random() * 40) + 50}%`
- }, [])
+ return `${Math.floor(Math.random() * 40) + 50}%`;
+ }, []);
return (
- )
-})
-SidebarMenuSkeleton.displayName = "SidebarMenuSkeleton"
+ );
+});
+SidebarMenuSkeleton.displayName = "SidebarMenuSkeleton";
const SidebarMenuSub = React.forwardRef<
HTMLUListElement,
@@ -700,28 +713,33 @@ const SidebarMenuSub = React.forwardRef<
className={cn(
"mx-3.5 flex min-w-0 translate-x-px flex-col gap-1 border-l border-sidebar-border px-2.5 py-0.5",
"group-data-[collapsible=icon]:hidden",
- className
+ className,
)}
{...props}
/>
-))
-SidebarMenuSub.displayName = "SidebarMenuSub"
+));
+SidebarMenuSub.displayName = "SidebarMenuSub";
const SidebarMenuSubItem = React.forwardRef<
HTMLLIElement,
React.ComponentProps<"li">
->(({ ...props }, ref) => )
-SidebarMenuSubItem.displayName = "SidebarMenuSubItem"
+>(({ ...props }, ref) => (
+
+));
+SidebarMenuSubItem.displayName = "SidebarMenuSubItem";
const SidebarMenuSubButton = React.forwardRef<
HTMLAnchorElement,
React.ComponentProps<"a"> & {
- asChild?: boolean
- size?: "sm" | "md"
- isActive?: boolean
+ asChild?: boolean;
+ size?: "sm" | "md";
+ isActive?: boolean;
}
>(({ asChild = false, size = "md", isActive, className, ...props }, ref) => {
- const Comp = asChild ? Slot : "a"
+ const Comp = asChild ? Slot : "a";
return (
- )
-})
-SidebarMenuSubButton.displayName = "SidebarMenuSubButton"
+ );
+});
+SidebarMenuSubButton.displayName = "SidebarMenuSubButton";
export {
Sidebar,
@@ -768,4 +786,4 @@ export {
SidebarSeparator,
SidebarTrigger,
useSidebar,
-}
+};
diff --git a/webapp/src/components/ui/skeleton.tsx b/webapp/src/components/ui/skeleton.tsx
index d7e45f7..c26c4ea 100644
--- a/webapp/src/components/ui/skeleton.tsx
+++ b/webapp/src/components/ui/skeleton.tsx
@@ -1,4 +1,4 @@
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
function Skeleton({
className,
@@ -9,7 +9,7 @@ function Skeleton({
className={cn("animate-pulse rounded-md bg-primary/10", className)}
{...props}
/>
- )
+ );
}
-export { Skeleton }
+export { Skeleton };
diff --git a/webapp/src/components/ui/slider.tsx b/webapp/src/components/ui/slider.tsx
index 9398b33..911445c 100644
--- a/webapp/src/components/ui/slider.tsx
+++ b/webapp/src/components/ui/slider.tsx
@@ -1,7 +1,8 @@
-import * as React from "react"
-import * as SliderPrimitive from "@radix-ui/react-slider"
+import * as React from "react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
+
+import * as SliderPrimitive from "@radix-ui/react-slider";
const Slider = React.forwardRef<
React.ElementRef,
@@ -11,7 +12,7 @@ const Slider = React.forwardRef<
ref={ref}
className={cn(
"relative flex w-full touch-none select-none items-center",
- className
+ className,
)}
{...props}
>
@@ -20,7 +21,7 @@ const Slider = React.forwardRef<
-))
-Slider.displayName = SliderPrimitive.Root.displayName
+));
+Slider.displayName = SliderPrimitive.Root.displayName;
-export { Slider }
+export { Slider };
diff --git a/webapp/src/components/ui/tooltip.tsx b/webapp/src/components/ui/tooltip.tsx
index 99ad630..93c21f9 100644
--- a/webapp/src/components/ui/tooltip.tsx
+++ b/webapp/src/components/ui/tooltip.tsx
@@ -1,13 +1,14 @@
-import * as React from "react"
-import * as TooltipPrimitive from "@radix-ui/react-tooltip"
+import * as React from "react";
-import { cn } from "@/lib/utils"
+import { cn } from "@/lib/utils";
-const TooltipProvider = TooltipPrimitive.Provider
+import * as TooltipPrimitive from "@radix-ui/react-tooltip";
-const Tooltip = TooltipPrimitive.Root
+const TooltipProvider = TooltipPrimitive.Provider;
-const TooltipTrigger = TooltipPrimitive.Trigger
+const Tooltip = TooltipPrimitive.Root;
+
+const TooltipTrigger = TooltipPrimitive.Trigger;
const TooltipContent = React.forwardRef<
React.ElementRef,
@@ -19,12 +20,12 @@ const TooltipContent = React.forwardRef<
sideOffset={sideOffset}
className={cn(
"z-50 overflow-hidden rounded-md bg-primary px-3 py-1.5 text-xs text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 origin-[--radix-tooltip-content-transform-origin]",
- className
+ className,
)}
{...props}
/>
-))
-TooltipContent.displayName = TooltipPrimitive.Content.displayName
+));
+TooltipContent.displayName = TooltipPrimitive.Content.displayName;
-export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider }
+export { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider };
diff --git a/webapp/src/fixtures/exampleData.json b/webapp/src/fixtures/exampleData.json
index 3a91076..b8752ac 100644
--- a/webapp/src/fixtures/exampleData.json
+++ b/webapp/src/fixtures/exampleData.json
@@ -1,622 +1,622 @@
{
- "data": {
- "clientByName": {
- "id": "1",
- "fullName": "Sharon Kelly",
- "consumptionSet": [
- {
- "id": "30395",
- "kwhConsumed": 164.4148351699662,
- "year": 2023,
- "month": 8
- },
- {
- "id": "308198",
- "kwhConsumed": 189.61895461983553,
- "year": 2023,
- "month": 7
- },
- {
- "id": "482293",
- "kwhConsumed": 216.34553198096057,
- "year": 2023,
- "month": 6
- },
- {
- "id": "117320",
- "kwhConsumed": 133.1116051379582,
- "year": 2023,
- "month": 5
- },
- {
- "id": "78305",
- "kwhConsumed": 394.26072022740703,
- "year": 2023,
- "month": 4
- },
- {
- "id": "276566",
- "kwhConsumed": 538.9759228423014,
- "year": 2023,
- "month": 3
- },
- {
- "id": "427431",
- "kwhConsumed": 805.3670664537833,
- "year": 2023,
- "month": 2
- },
- {
- "id": "220138",
- "kwhConsumed": 939.5755634433095,
- "year": 2023,
- "month": 1
- },
- {
- "id": "226265",
- "kwhConsumed": 448.4633802114093,
- "year": 2022,
- "month": 12
- },
- {
- "id": "484422",
- "kwhConsumed": 310.32085167717605,
- "year": 2022,
- "month": 11
- },
- {
- "id": "347263",
- "kwhConsumed": 343.2684507743658,
- "year": 2022,
- "month": 10
- },
- {
- "id": "220782",
- "kwhConsumed": 137.45770851754543,
- "year": 2022,
- "month": 9
- },
- {
- "id": "325539",
- "kwhConsumed": 209.7627541128656,
- "year": 2022,
- "month": 8
- },
- {
- "id": "396380",
- "kwhConsumed": 259.4689786815701,
- "year": 2022,
- "month": 7
- },
- {
- "id": "83882",
- "kwhConsumed": 178.3242117310336,
- "year": 2022,
- "month": 6
- },
- {
- "id": "132371",
- "kwhConsumed": 173.2027803056221,
- "year": 2022,
- "month": 5
- },
- {
- "id": "368157",
- "kwhConsumed": 304.6967395930563,
- "year": 2022,
- "month": 4
- },
- {
- "id": "358821",
- "kwhConsumed": 445.1120664781448,
- "year": 2022,
- "month": 3
- },
- {
- "id": "504295",
- "kwhConsumed": 453.32448159050074,
- "year": 2022,
- "month": 2
- },
- {
- "id": "128481",
- "kwhConsumed": 717.6340239397259,
- "year": 2022,
- "month": 1
- },
- {
- "id": "91765",
- "kwhConsumed": 508.5620973662434,
- "year": 2021,
- "month": 12
- },
- {
- "id": "177014",
- "kwhConsumed": 481.2143712301713,
- "year": 2021,
- "month": 11
- },
- {
- "id": "200696",
- "kwhConsumed": 243.10460986693374,
- "year": 2021,
- "month": 10
- },
- {
- "id": "341032",
- "kwhConsumed": 253.39513263269774,
- "year": 2021,
- "month": 9
- },
- {
- "id": "85535",
- "kwhConsumed": 233.43539537508053,
- "year": 2021,
- "month": 8
- },
- {
- "id": "465032",
- "kwhConsumed": 233.39533485053437,
- "year": 2021,
- "month": 7
- },
- {
- "id": "19681",
- "kwhConsumed": 140.63148035394678,
- "year": 2021,
- "month": 6
- },
- {
- "id": "300141",
- "kwhConsumed": 238.12223318570972,
- "year": 2021,
- "month": 5
- },
- {
- "id": "201527",
- "kwhConsumed": 270.4850239941495,
- "year": 2021,
- "month": 4
- },
- {
- "id": "343817",
- "kwhConsumed": 408.1057140708247,
- "year": 2021,
- "month": 3
- },
- {
- "id": "477812",
- "kwhConsumed": 649.7378728424686,
- "year": 2021,
- "month": 2
- },
- {
- "id": "111934",
- "kwhConsumed": 721.373940772935,
- "year": 2021,
- "month": 1
- },
- {
- "id": "44344",
- "kwhConsumed": 656.797652432217,
- "year": 2020,
- "month": 12
- },
- {
- "id": "182535",
- "kwhConsumed": 472.666818825693,
- "year": 2020,
- "month": 11
- },
- {
- "id": "123764",
- "kwhConsumed": 245.87754671032516,
- "year": 2020,
- "month": 10
- },
- {
- "id": "460507",
- "kwhConsumed": 238.6555655804525,
- "year": 2020,
- "month": 9
- },
- {
- "id": "105388",
- "kwhConsumed": 177.71242955146025,
- "year": 2020,
- "month": 8
- },
- {
- "id": "265177",
- "kwhConsumed": 183.65720099552522,
- "year": 2020,
- "month": 7
- },
- {
- "id": "257037",
- "kwhConsumed": 138.81873827043685,
- "year": 2020,
- "month": 6
- },
- {
- "id": "27647",
- "kwhConsumed": 158.94399487423846,
- "year": 2020,
- "month": 5
- },
- {
- "id": "139957",
- "kwhConsumed": 395.4551584229149,
- "year": 2020,
- "month": 4
- },
- {
- "id": "434064",
- "kwhConsumed": 412.66521364321443,
- "year": 2020,
- "month": 3
- },
- {
- "id": "317455",
- "kwhConsumed": 746.0996712882987,
- "year": 2020,
- "month": 2
- },
- {
- "id": "899",
- "kwhConsumed": 837.0555968595797,
- "year": 2020,
- "month": 1
- },
- {
- "id": "51673",
- "kwhConsumed": 651.0892059147765,
- "year": 2019,
- "month": 12
- },
- {
- "id": "228508",
- "kwhConsumed": 383.5160250357795,
- "year": 2019,
- "month": 11
- },
- {
- "id": "32436",
- "kwhConsumed": 282.83021582930496,
- "year": 2019,
- "month": 10
- },
- {
- "id": "164211",
- "kwhConsumed": 163.01656279131754,
- "year": 2019,
- "month": 9
- },
- {
- "id": "1691",
- "kwhConsumed": 177.50395397654594,
- "year": 2019,
- "month": 8
- },
- {
- "id": "283063",
- "kwhConsumed": 215.672718978066,
- "year": 2019,
- "month": 7
- },
- {
- "id": "472686",
- "kwhConsumed": 129.94765771245565,
- "year": 2019,
- "month": 6
- },
- {
- "id": "23261",
- "kwhConsumed": 228.45957845917675,
- "year": 2019,
- "month": 5
- },
- {
- "id": "2433",
- "kwhConsumed": 393.43818056645256,
- "year": 2019,
- "month": 4
- },
- {
- "id": "451192",
- "kwhConsumed": 436.93474384783855,
- "year": 2019,
- "month": 3
- },
- {
- "id": "297913",
- "kwhConsumed": 764.478858255888,
- "year": 2019,
- "month": 2
- },
- {
- "id": "274142",
- "kwhConsumed": 593.4733602664692,
- "year": 2019,
- "month": 1
- },
- {
- "id": "203378",
- "kwhConsumed": 396.6835037465184,
- "year": 2018,
- "month": 12
- },
- {
- "id": "168153",
- "kwhConsumed": 379.8495844754973,
- "year": 2018,
- "month": 11
- },
- {
- "id": "183716",
- "kwhConsumed": 370.293759998266,
- "year": 2018,
- "month": 10
- },
- {
- "id": "76422",
- "kwhConsumed": 146.50330213442655,
- "year": 2018,
- "month": 9
- },
- {
- "id": "187074",
- "kwhConsumed": 229.47263925033627,
- "year": 2018,
- "month": 8
- },
- {
- "id": "335003",
- "kwhConsumed": 221.3669439448684,
- "year": 2018,
- "month": 7
- },
- {
- "id": "342670",
- "kwhConsumed": 202.07172598711654,
- "year": 2018,
- "month": 6
- },
- {
- "id": "48187",
- "kwhConsumed": 133.75174396042812,
- "year": 2018,
- "month": 5
- },
- {
- "id": "243938",
- "kwhConsumed": 398.2397790945756,
- "year": 2018,
- "month": 4
- },
- {
- "id": "378263",
- "kwhConsumed": 550.2758303286474,
- "year": 2018,
- "month": 3
- },
- {
- "id": "492398",
- "kwhConsumed": 544.8289790022931,
- "year": 2018,
- "month": 2
- },
- {
- "id": "498649",
- "kwhConsumed": 881.6480498802132,
- "year": 2018,
- "month": 1
- },
- {
- "id": "182921",
- "kwhConsumed": 454.88191065253454,
- "year": 2017,
- "month": 12
- },
- {
- "id": "424553",
- "kwhConsumed": 469.61835380445274,
- "year": 2017,
- "month": 11
- },
- {
- "id": "92157",
- "kwhConsumed": 259.8182607972273,
- "year": 2017,
- "month": 10
- },
- {
- "id": "30738",
- "kwhConsumed": 232.09415579275588,
- "year": 2017,
- "month": 9
- },
- {
- "id": "308159",
- "kwhConsumed": 190.26042860391178,
- "year": 2017,
- "month": 8
- },
- {
- "id": "454439",
- "kwhConsumed": 206.2480640869221,
- "year": 2017,
- "month": 7
- },
- {
- "id": "488731",
- "kwhConsumed": 168.01647113159484,
- "year": 2017,
- "month": 6
- },
- {
- "id": "479971",
- "kwhConsumed": 234.06059542770362,
- "year": 2017,
- "month": 5
- },
- {
- "id": "299862",
- "kwhConsumed": 371.19258696541675,
- "year": 2017,
- "month": 4
- },
- {
- "id": "233536",
- "kwhConsumed": 498.10293465987445,
- "year": 2017,
- "month": 3
- },
- {
- "id": "256482",
- "kwhConsumed": 762.8626981719045,
- "year": 2017,
- "month": 2
- },
- {
- "id": "184425",
- "kwhConsumed": 871.6006105876465,
- "year": 2017,
- "month": 1
- },
- {
- "id": "77087",
- "kwhConsumed": 682.0867100530825,
- "year": 2016,
- "month": 12
- },
- {
- "id": "236220",
- "kwhConsumed": 314.31140711807836,
- "year": 2016,
- "month": 11
- },
- {
- "id": "126648",
- "kwhConsumed": 388.3621431618891,
- "year": 2016,
- "month": 10
- },
- {
- "id": "441042",
- "kwhConsumed": 192.0762986565063,
- "year": 2016,
- "month": 9
- },
- {
- "id": "491110",
- "kwhConsumed": 210.17983789907782,
- "year": 2016,
- "month": 8
- },
- {
- "id": "378729",
- "kwhConsumed": 282.67043055478837,
- "year": 2016,
- "month": 7
- },
- {
- "id": "238785",
- "kwhConsumed": 154.9416576913818,
- "year": 2016,
- "month": 6
- },
- {
- "id": "384235",
- "kwhConsumed": 197.55329316392633,
- "year": 2016,
- "month": 5
- },
- {
- "id": "224884",
- "kwhConsumed": 413.58601176249186,
- "year": 2016,
- "month": 4
- },
- {
- "id": "213932",
- "kwhConsumed": 420.4185337083377,
- "year": 2016,
- "month": 3
- },
- {
- "id": "231520",
- "kwhConsumed": 667.7135738435337,
- "year": 2016,
- "month": 2
- },
- {
- "id": "251361",
- "kwhConsumed": 948.5574342081977,
- "year": 2016,
- "month": 1
- },
- {
- "id": "302898",
- "kwhConsumed": 416.1155705667878,
- "year": 2015,
- "month": 12
- },
- {
- "id": "249812",
- "kwhConsumed": 492.01592723491416,
- "year": 2015,
- "month": 11
- },
- {
- "id": "502823",
- "kwhConsumed": 391.6237536780693,
- "year": 2015,
- "month": 10
- },
- {
- "id": "343253",
- "kwhConsumed": 233.017284782912,
- "year": 2015,
- "month": 9
- },
- {
- "id": "176109",
- "kwhConsumed": 225.32065990362955,
- "year": 2015,
- "month": 8
- },
- {
- "id": "371581",
- "kwhConsumed": 249.26145458769824,
- "year": 2015,
- "month": 7
- },
- {
- "id": "484285",
- "kwhConsumed": 130.0484731978196,
- "year": 2015,
- "month": 6
- },
- {
- "id": "483251",
- "kwhConsumed": 206.3580797531119,
- "year": 2015,
- "month": 5
- },
- {
- "id": "492532",
- "kwhConsumed": 326.9787859487174,
- "year": 2015,
- "month": 4
- },
- {
- "id": "63238",
- "kwhConsumed": 549.686306366201,
- "year": 2015,
- "month": 3
- }
- ]
+ "data": {
+ "clientByName": {
+ "id": "1",
+ "fullName": "Sharon Kelly",
+ "consumptionSet": [
+ {
+ "id": "30395",
+ "kwhConsumed": 164.4148351699662,
+ "year": 2023,
+ "month": 8
+ },
+ {
+ "id": "308198",
+ "kwhConsumed": 189.61895461983553,
+ "year": 2023,
+ "month": 7
+ },
+ {
+ "id": "482293",
+ "kwhConsumed": 216.34553198096057,
+ "year": 2023,
+ "month": 6
+ },
+ {
+ "id": "117320",
+ "kwhConsumed": 133.1116051379582,
+ "year": 2023,
+ "month": 5
+ },
+ {
+ "id": "78305",
+ "kwhConsumed": 394.26072022740703,
+ "year": 2023,
+ "month": 4
+ },
+ {
+ "id": "276566",
+ "kwhConsumed": 538.9759228423014,
+ "year": 2023,
+ "month": 3
+ },
+ {
+ "id": "427431",
+ "kwhConsumed": 805.3670664537833,
+ "year": 2023,
+ "month": 2
+ },
+ {
+ "id": "220138",
+ "kwhConsumed": 939.5755634433095,
+ "year": 2023,
+ "month": 1
+ },
+ {
+ "id": "226265",
+ "kwhConsumed": 448.4633802114093,
+ "year": 2022,
+ "month": 12
+ },
+ {
+ "id": "484422",
+ "kwhConsumed": 310.32085167717605,
+ "year": 2022,
+ "month": 11
+ },
+ {
+ "id": "347263",
+ "kwhConsumed": 343.2684507743658,
+ "year": 2022,
+ "month": 10
+ },
+ {
+ "id": "220782",
+ "kwhConsumed": 137.45770851754543,
+ "year": 2022,
+ "month": 9
+ },
+ {
+ "id": "325539",
+ "kwhConsumed": 209.7627541128656,
+ "year": 2022,
+ "month": 8
+ },
+ {
+ "id": "396380",
+ "kwhConsumed": 259.4689786815701,
+ "year": 2022,
+ "month": 7
+ },
+ {
+ "id": "83882",
+ "kwhConsumed": 178.3242117310336,
+ "year": 2022,
+ "month": 6
+ },
+ {
+ "id": "132371",
+ "kwhConsumed": 173.2027803056221,
+ "year": 2022,
+ "month": 5
+ },
+ {
+ "id": "368157",
+ "kwhConsumed": 304.6967395930563,
+ "year": 2022,
+ "month": 4
+ },
+ {
+ "id": "358821",
+ "kwhConsumed": 445.1120664781448,
+ "year": 2022,
+ "month": 3
+ },
+ {
+ "id": "504295",
+ "kwhConsumed": 453.32448159050074,
+ "year": 2022,
+ "month": 2
+ },
+ {
+ "id": "128481",
+ "kwhConsumed": 717.6340239397259,
+ "year": 2022,
+ "month": 1
+ },
+ {
+ "id": "91765",
+ "kwhConsumed": 508.5620973662434,
+ "year": 2021,
+ "month": 12
+ },
+ {
+ "id": "177014",
+ "kwhConsumed": 481.2143712301713,
+ "year": 2021,
+ "month": 11
+ },
+ {
+ "id": "200696",
+ "kwhConsumed": 243.10460986693374,
+ "year": 2021,
+ "month": 10
+ },
+ {
+ "id": "341032",
+ "kwhConsumed": 253.39513263269774,
+ "year": 2021,
+ "month": 9
+ },
+ {
+ "id": "85535",
+ "kwhConsumed": 233.43539537508053,
+ "year": 2021,
+ "month": 8
+ },
+ {
+ "id": "465032",
+ "kwhConsumed": 233.39533485053437,
+ "year": 2021,
+ "month": 7
+ },
+ {
+ "id": "19681",
+ "kwhConsumed": 140.63148035394678,
+ "year": 2021,
+ "month": 6
+ },
+ {
+ "id": "300141",
+ "kwhConsumed": 238.12223318570972,
+ "year": 2021,
+ "month": 5
+ },
+ {
+ "id": "201527",
+ "kwhConsumed": 270.4850239941495,
+ "year": 2021,
+ "month": 4
+ },
+ {
+ "id": "343817",
+ "kwhConsumed": 408.1057140708247,
+ "year": 2021,
+ "month": 3
+ },
+ {
+ "id": "477812",
+ "kwhConsumed": 649.7378728424686,
+ "year": 2021,
+ "month": 2
+ },
+ {
+ "id": "111934",
+ "kwhConsumed": 721.373940772935,
+ "year": 2021,
+ "month": 1
+ },
+ {
+ "id": "44344",
+ "kwhConsumed": 656.797652432217,
+ "year": 2020,
+ "month": 12
+ },
+ {
+ "id": "182535",
+ "kwhConsumed": 472.666818825693,
+ "year": 2020,
+ "month": 11
+ },
+ {
+ "id": "123764",
+ "kwhConsumed": 245.87754671032516,
+ "year": 2020,
+ "month": 10
+ },
+ {
+ "id": "460507",
+ "kwhConsumed": 238.6555655804525,
+ "year": 2020,
+ "month": 9
+ },
+ {
+ "id": "105388",
+ "kwhConsumed": 177.71242955146025,
+ "year": 2020,
+ "month": 8
+ },
+ {
+ "id": "265177",
+ "kwhConsumed": 183.65720099552522,
+ "year": 2020,
+ "month": 7
+ },
+ {
+ "id": "257037",
+ "kwhConsumed": 138.81873827043685,
+ "year": 2020,
+ "month": 6
+ },
+ {
+ "id": "27647",
+ "kwhConsumed": 158.94399487423846,
+ "year": 2020,
+ "month": 5
+ },
+ {
+ "id": "139957",
+ "kwhConsumed": 395.4551584229149,
+ "year": 2020,
+ "month": 4
+ },
+ {
+ "id": "434064",
+ "kwhConsumed": 412.66521364321443,
+ "year": 2020,
+ "month": 3
+ },
+ {
+ "id": "317455",
+ "kwhConsumed": 746.0996712882987,
+ "year": 2020,
+ "month": 2
+ },
+ {
+ "id": "899",
+ "kwhConsumed": 837.0555968595797,
+ "year": 2020,
+ "month": 1
+ },
+ {
+ "id": "51673",
+ "kwhConsumed": 651.0892059147765,
+ "year": 2019,
+ "month": 12
+ },
+ {
+ "id": "228508",
+ "kwhConsumed": 383.5160250357795,
+ "year": 2019,
+ "month": 11
+ },
+ {
+ "id": "32436",
+ "kwhConsumed": 282.83021582930496,
+ "year": 2019,
+ "month": 10
+ },
+ {
+ "id": "164211",
+ "kwhConsumed": 163.01656279131754,
+ "year": 2019,
+ "month": 9
+ },
+ {
+ "id": "1691",
+ "kwhConsumed": 177.50395397654594,
+ "year": 2019,
+ "month": 8
+ },
+ {
+ "id": "283063",
+ "kwhConsumed": 215.672718978066,
+ "year": 2019,
+ "month": 7
+ },
+ {
+ "id": "472686",
+ "kwhConsumed": 129.94765771245565,
+ "year": 2019,
+ "month": 6
+ },
+ {
+ "id": "23261",
+ "kwhConsumed": 228.45957845917675,
+ "year": 2019,
+ "month": 5
+ },
+ {
+ "id": "2433",
+ "kwhConsumed": 393.43818056645256,
+ "year": 2019,
+ "month": 4
+ },
+ {
+ "id": "451192",
+ "kwhConsumed": 436.93474384783855,
+ "year": 2019,
+ "month": 3
+ },
+ {
+ "id": "297913",
+ "kwhConsumed": 764.478858255888,
+ "year": 2019,
+ "month": 2
+ },
+ {
+ "id": "274142",
+ "kwhConsumed": 593.4733602664692,
+ "year": 2019,
+ "month": 1
+ },
+ {
+ "id": "203378",
+ "kwhConsumed": 396.6835037465184,
+ "year": 2018,
+ "month": 12
+ },
+ {
+ "id": "168153",
+ "kwhConsumed": 379.8495844754973,
+ "year": 2018,
+ "month": 11
+ },
+ {
+ "id": "183716",
+ "kwhConsumed": 370.293759998266,
+ "year": 2018,
+ "month": 10
+ },
+ {
+ "id": "76422",
+ "kwhConsumed": 146.50330213442655,
+ "year": 2018,
+ "month": 9
+ },
+ {
+ "id": "187074",
+ "kwhConsumed": 229.47263925033627,
+ "year": 2018,
+ "month": 8
+ },
+ {
+ "id": "335003",
+ "kwhConsumed": 221.3669439448684,
+ "year": 2018,
+ "month": 7
+ },
+ {
+ "id": "342670",
+ "kwhConsumed": 202.07172598711654,
+ "year": 2018,
+ "month": 6
+ },
+ {
+ "id": "48187",
+ "kwhConsumed": 133.75174396042812,
+ "year": 2018,
+ "month": 5
+ },
+ {
+ "id": "243938",
+ "kwhConsumed": 398.2397790945756,
+ "year": 2018,
+ "month": 4
+ },
+ {
+ "id": "378263",
+ "kwhConsumed": 550.2758303286474,
+ "year": 2018,
+ "month": 3
+ },
+ {
+ "id": "492398",
+ "kwhConsumed": 544.8289790022931,
+ "year": 2018,
+ "month": 2
+ },
+ {
+ "id": "498649",
+ "kwhConsumed": 881.6480498802132,
+ "year": 2018,
+ "month": 1
+ },
+ {
+ "id": "182921",
+ "kwhConsumed": 454.88191065253454,
+ "year": 2017,
+ "month": 12
+ },
+ {
+ "id": "424553",
+ "kwhConsumed": 469.61835380445274,
+ "year": 2017,
+ "month": 11
+ },
+ {
+ "id": "92157",
+ "kwhConsumed": 259.8182607972273,
+ "year": 2017,
+ "month": 10
+ },
+ {
+ "id": "30738",
+ "kwhConsumed": 232.09415579275588,
+ "year": 2017,
+ "month": 9
+ },
+ {
+ "id": "308159",
+ "kwhConsumed": 190.26042860391178,
+ "year": 2017,
+ "month": 8
+ },
+ {
+ "id": "454439",
+ "kwhConsumed": 206.2480640869221,
+ "year": 2017,
+ "month": 7
+ },
+ {
+ "id": "488731",
+ "kwhConsumed": 168.01647113159484,
+ "year": 2017,
+ "month": 6
+ },
+ {
+ "id": "479971",
+ "kwhConsumed": 234.06059542770362,
+ "year": 2017,
+ "month": 5
+ },
+ {
+ "id": "299862",
+ "kwhConsumed": 371.19258696541675,
+ "year": 2017,
+ "month": 4
+ },
+ {
+ "id": "233536",
+ "kwhConsumed": 498.10293465987445,
+ "year": 2017,
+ "month": 3
+ },
+ {
+ "id": "256482",
+ "kwhConsumed": 762.8626981719045,
+ "year": 2017,
+ "month": 2
+ },
+ {
+ "id": "184425",
+ "kwhConsumed": 871.6006105876465,
+ "year": 2017,
+ "month": 1
+ },
+ {
+ "id": "77087",
+ "kwhConsumed": 682.0867100530825,
+ "year": 2016,
+ "month": 12
+ },
+ {
+ "id": "236220",
+ "kwhConsumed": 314.31140711807836,
+ "year": 2016,
+ "month": 11
+ },
+ {
+ "id": "126648",
+ "kwhConsumed": 388.3621431618891,
+ "year": 2016,
+ "month": 10
+ },
+ {
+ "id": "441042",
+ "kwhConsumed": 192.0762986565063,
+ "year": 2016,
+ "month": 9
+ },
+ {
+ "id": "491110",
+ "kwhConsumed": 210.17983789907782,
+ "year": 2016,
+ "month": 8
+ },
+ {
+ "id": "378729",
+ "kwhConsumed": 282.67043055478837,
+ "year": 2016,
+ "month": 7
+ },
+ {
+ "id": "238785",
+ "kwhConsumed": 154.9416576913818,
+ "year": 2016,
+ "month": 6
+ },
+ {
+ "id": "384235",
+ "kwhConsumed": 197.55329316392633,
+ "year": 2016,
+ "month": 5
+ },
+ {
+ "id": "224884",
+ "kwhConsumed": 413.58601176249186,
+ "year": 2016,
+ "month": 4
+ },
+ {
+ "id": "213932",
+ "kwhConsumed": 420.4185337083377,
+ "year": 2016,
+ "month": 3
+ },
+ {
+ "id": "231520",
+ "kwhConsumed": 667.7135738435337,
+ "year": 2016,
+ "month": 2
+ },
+ {
+ "id": "251361",
+ "kwhConsumed": 948.5574342081977,
+ "year": 2016,
+ "month": 1
+ },
+ {
+ "id": "302898",
+ "kwhConsumed": 416.1155705667878,
+ "year": 2015,
+ "month": 12
+ },
+ {
+ "id": "249812",
+ "kwhConsumed": 492.01592723491416,
+ "year": 2015,
+ "month": 11
+ },
+ {
+ "id": "502823",
+ "kwhConsumed": 391.6237536780693,
+ "year": 2015,
+ "month": 10
+ },
+ {
+ "id": "343253",
+ "kwhConsumed": 233.017284782912,
+ "year": 2015,
+ "month": 9
+ },
+ {
+ "id": "176109",
+ "kwhConsumed": 225.32065990362955,
+ "year": 2015,
+ "month": 8
+ },
+ {
+ "id": "371581",
+ "kwhConsumed": 249.26145458769824,
+ "year": 2015,
+ "month": 7
+ },
+ {
+ "id": "484285",
+ "kwhConsumed": 130.0484731978196,
+ "year": 2015,
+ "month": 6
+ },
+ {
+ "id": "483251",
+ "kwhConsumed": 206.3580797531119,
+ "year": 2015,
+ "month": 5
+ },
+ {
+ "id": "492532",
+ "kwhConsumed": 326.9787859487174,
+ "year": 2015,
+ "month": 4
+ },
+ {
+ "id": "63238",
+ "kwhConsumed": 549.686306366201,
+ "year": 2015,
+ "month": 3
}
+ ]
}
-}
\ No newline at end of file
+ }
+}
diff --git a/webapp/src/hooks/use-mobile.tsx b/webapp/src/hooks/use-mobile.tsx
index 2b0fe1d..a93d583 100644
--- a/webapp/src/hooks/use-mobile.tsx
+++ b/webapp/src/hooks/use-mobile.tsx
@@ -1,19 +1,21 @@
-import * as React from "react"
+import * as React from "react";
-const MOBILE_BREAKPOINT = 768
+const MOBILE_BREAKPOINT = 768;
export function useIsMobile() {
- const [isMobile, setIsMobile] = React.useState(undefined)
+ const [isMobile, setIsMobile] = React.useState(
+ undefined,
+ );
React.useEffect(() => {
- const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`)
+ const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);
const onChange = () => {
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
- }
- mql.addEventListener("change", onChange)
- setIsMobile(window.innerWidth < MOBILE_BREAKPOINT)
- return () => mql.removeEventListener("change", onChange)
- }, [])
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
+ };
+ mql.addEventListener("change", onChange);
+ setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);
+ return () => mql.removeEventListener("change", onChange);
+ }, []);
- return !!isMobile
+ return !!isMobile;
}
diff --git a/webapp/src/index.css b/webapp/src/index.css
index 06c0da8..c4e364e 100644
--- a/webapp/src/index.css
+++ b/webapp/src/index.css
@@ -15,180 +15,145 @@
@custom-variant dark (&:is(.dark *));
@layer base {
- * {
- @apply border-border outline-ring/50;
- }
+ * {
+ @apply border-border outline-ring/50;
+ }
- body {
- @apply bg-background text-foreground;
- }
+ body {
+ @apply bg-background text-foreground;
+ }
}
/* THEMING SHADCN/UI AJUSTE AVEC LA CHARTE GRAPHIQUE ALL4TREES */
:root {
-
- font-family: var(--font-body-primary), var(--font-title-primary), var(--font-body-secondary), var(--font-title-secondary), system-ui, sans-serif;
- line-height: 1.5;
- font-weight: 400;
-
- color-scheme: light dark;
- color: rgba(255, 255, 255, 0.87);
- background-color: #242424;
-
- font-synthesis: none;
- text-rendering: optimizeLegibility;
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- --radius: 0.625rem;
-
- /* LIGHT MODE SHADCN */
- --background: var(--color-alabaster);
- --foreground: var(--color-nuit);
- --card: #ffffff;
- --card-foreground: var(--color-nuit);
- --popover: #ffffff;
- --popover-foreground: var(--color-nuit);
- --primary: var(--color-vert-kelly);
- --primary-foreground: var(--color-bleu);
- --secondary: var(--color-jaune-vert);
- --secondary-foreground: var(--color-nuit);
- --muted: #e5e7eb;
- --muted-foreground: var(--color-onyx);
- --accent: var(--color-citrouille);
- --accent-foreground: #ffffff;
- --destructive: #dc2626;
- --border: #e5e7eb;
- --input: #ffffff;
- --ring: var(--color-vert-kelly);
- --chart-1: var(--color-bleu);
- --chart-2: var(--color-vert-de-gris);
- --chart-3: var(--color-vert-kelly);
- --chart-4: var(--color-citrouille);
- --chart-5: var(--color-jaune-vert);
- --sidebar: var(--color-alabaster);
- --sidebar-foreground: var(--color-alabaster);
- --sidebar-primary: var(--color-brunswick-green);
- --sidebar-primary-foreground: var(--color-alabaster);
- --sidebar-accent: var(--color-citrouille);
- --sidebar-accent-foreground: #ffffff;
- --sidebar-border: #e5e7eb;
- --sidebar-ring: var(--color-vert-kelly);
+ font-family:
+ var(--font-body-primary), var(--font-title-primary),
+ var(--font-body-secondary), var(--font-title-secondary), system-ui,
+ sans-serif;
+ line-height: 1.5;
+ font-weight: 400;
+
+ color-scheme: light dark;
+ color: rgba(255, 255, 255, 0.87);
+ background-color: #242424;
+
+ font-synthesis: none;
+ text-rendering: optimizeLegibility;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ --radius: 0.625rem;
+
+ /* LIGHT MODE SHADCN */
+ --background: var(--color-alabaster);
+ --foreground: var(--color-nuit);
+ --card: #ffffff;
+ --card-foreground: var(--color-nuit);
+ --popover: #ffffff;
+ --popover-foreground: var(--color-nuit);
+ --primary: var(--color-vert-kelly);
+ --primary-foreground: var(--color-bleu);
+ --secondary: var(--color-jaune-vert);
+ --secondary-foreground: var(--color-nuit);
+ --muted: #e5e7eb;
+ --muted-foreground: var(--color-onyx);
+ --accent: var(--color-citrouille);
+ --accent-foreground: #ffffff;
+ --destructive: #dc2626;
+ --border: #e5e7eb;
+ --input: #ffffff;
+ --ring: var(--color-vert-kelly);
+ --chart-1: var(--color-bleu);
+ --chart-2: var(--color-vert-de-gris);
+ --chart-3: var(--color-vert-kelly);
+ --chart-4: var(--color-citrouille);
+ --chart-5: var(--color-jaune-vert);
+ --sidebar: var(--color-alabaster);
+ --sidebar-foreground: var(--color-alabaster);
+ --sidebar-primary: var(--color-brunswick-green);
+ --sidebar-primary-foreground: var(--color-alabaster);
+ --sidebar-accent: var(--color-citrouille);
+ --sidebar-accent-foreground: #ffffff;
+ --sidebar-border: #e5e7eb;
+ --sidebar-ring: var(--color-vert-kelly);
}
body {
- background-color: var(--foreground);
- font-family: var(--font-body-primary);
+ background-color: var(--foreground);
+ font-family: var(--font-body-primary);
}
a {
- font-weight: 500;
- color: var(--primary);
- text-decoration: inherit;
+ font-weight: 500;
+ color: var(--primary);
+ text-decoration: inherit;
}
a:hover {
- color: var(--secondary);
+ color: var(--secondary);
}
button {
- border-radius: 8px;
- border: 1px solid transparent;
- padding: 0.6em 1.2em;
- font-size: 1em;
- font-weight: 500;
- font-family: inherit;
- color: var(--foreground);
- border-color: var(--border);
- background-color: var(--primary);
- cursor: pointer;
- transition: border-color 0.25s;
+ border-radius: 8px;
+ border: 1px solid transparent;
+ padding: 0.6em 1.2em;
+ font-size: 1em;
+ font-weight: 500;
+ font-family: inherit;
+ color: var(--foreground);
+ border-color: var(--border);
+ background-color: var(--primary);
+ cursor: pointer;
+ transition: border-color 0.25s;
}
button:hover {
- background-color: var(--secondary);
+ background-color: var(--secondary);
}
-
@theme inline {
- --radius-sm: calc(var(--radius) - 4px);
- --radius-md: calc(var(--radius) - 2px);
- --radius-lg: var(--radius);
- --radius-xl: calc(var(--radius) + 4px);
- --radius-2xl: calc(var(--radius) + 8px);
- --radius-3xl: calc(var(--radius) + 12px);
- --radius-4xl: calc(var(--radius) + 16px);
- --color-background: var(--background);
- --color-foreground: var(--foreground);
- --color-card: var(--card);
- --color-card-foreground: var(--card-foreground);
- --color-popover: var(--popover);
- --color-popover-foreground: var(--popover-foreground);
- --color-primary: var(--primary);
- --color-primary-foreground: var(--primary-foreground);
- --color-secondary: var(--secondary);
- --color-secondary-foreground: var(--secondary-foreground);
- --color-muted: var(--muted);
- --color-muted-foreground: var(--muted-foreground);
- --color-accent: var(--accent);
- --color-accent-foreground: var(--accent-foreground);
- --color-destructive: var(--destructive);
- --color-border: var(--border);
- --color-input: var(--input);
- --color-ring: var(--ring);
- --color-chart-1: var(--chart-1);
- --color-chart-2: var(--chart-2);
- --color-chart-3: var(--chart-3);
- --color-chart-4: var(--chart-4);
- --color-chart-5: var(--chart-5);
- --color-sidebar: var(--sidebar);
- --color-sidebar-foreground: var(--sidebar-foreground);
- --color-sidebar-primary: var(--sidebar-primary);
- --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
- --color-sidebar-accent: var(--sidebar-accent);
- --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
- --color-sidebar-border: var(--sidebar-border);
- --color-sidebar-ring: var(--sidebar-ring);
+ --radius-sm: calc(var(--radius) - 4px);
+ --radius-md: calc(var(--radius) - 2px);
+ --radius-lg: var(--radius);
+ --radius-xl: calc(var(--radius) + 4px);
+ --radius-2xl: calc(var(--radius) + 8px);
+ --radius-3xl: calc(var(--radius) + 12px);
+ --radius-4xl: calc(var(--radius) + 16px);
+ --color-background: var(--background);
+ --color-foreground: var(--foreground);
+ --color-card: var(--card);
+ --color-card-foreground: var(--card-foreground);
+ --color-popover: var(--popover);
+ --color-popover-foreground: var(--popover-foreground);
+ --color-primary: var(--primary);
+ --color-primary-foreground: var(--primary-foreground);
+ --color-secondary: var(--secondary);
+ --color-secondary-foreground: var(--secondary-foreground);
+ --color-muted: var(--muted);
+ --color-muted-foreground: var(--muted-foreground);
+ --color-accent: var(--accent);
+ --color-accent-foreground: var(--accent-foreground);
+ --color-destructive: var(--destructive);
+ --color-border: var(--border);
+ --color-input: var(--input);
+ --color-ring: var(--ring);
+ --color-chart-1: var(--chart-1);
+ --color-chart-2: var(--chart-2);
+ --color-chart-3: var(--chart-3);
+ --color-chart-4: var(--chart-4);
+ --color-chart-5: var(--chart-5);
+ --color-sidebar: var(--sidebar);
+ --color-sidebar-foreground: var(--sidebar-foreground);
+ --color-sidebar-primary: var(--sidebar-primary);
+ --color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
+ --color-sidebar-accent: var(--sidebar-accent);
+ --color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
+ --color-sidebar-border: var(--sidebar-border);
+ --color-sidebar-ring: var(--sidebar-ring);
}
/* DARK MODE SHADCN */
@media (prefers-color-scheme: dark) {
- :root {
- --background: var(--color-nuit);
- --foreground: var(--color-alabaster);
- --card: var(--color-onyx);
- --card-foreground: var(--color-alabaster);
- --popover: var(--color-onyx);
- --popover-foreground: var(--color-alabaster);
- --primary: var(--color-brunswick-green);
- --primary-foreground: var(--color-nuit);
- --secondary: var(--color-vert-de-gris);
- --secondary-foreground: var(--color-nuit);
- --muted: var(--color-onyx);
- --muted-foreground: #9ca3af;
- --accent: var(--color-citrouille);
- --accent-foreground: var(--color-nuit);
- --destructive: #ef4444;
- --border: rgba(255, 255, 255, 0.15);
- --input: rgba(255, 255, 255, 0.05);
- --ring: var(--color-jaune-vert);
- --chart-1: #60a5fa;
- --chart-2: #22d3ee;
- --chart-3: #86efac;
- --chart-4: #fbbf24;
- --chart-5: #f97316;
- --sidebar: var(--color-onyx);
- --sidebar-foreground: var(--color-alabaster);
- --sidebar-primary: var(--color-onyx);
- --sidebar-primary-foreground: var(--color-vert-kelly);
- --sidebar-accent: var(--color-citrouille);
- --sidebar-accent-foreground: var(--color-nuit);
- --sidebar-border: rgba(255, 255, 255, 0.15);
- --sidebar-ring: var(--color-jaune-vert);
- }
-}
-
-/* Alternative : Support de la classe `.dark` pour contrôle manuel */
-.dark {
+ :root {
--background: var(--color-nuit);
--foreground: var(--color-alabaster);
--card: var(--color-onyx);
@@ -207,6 +172,11 @@ button:hover {
--border: rgba(255, 255, 255, 0.15);
--input: rgba(255, 255, 255, 0.05);
--ring: var(--color-jaune-vert);
+ --chart-1: #60a5fa;
+ --chart-2: #22d3ee;
+ --chart-3: #86efac;
+ --chart-4: #fbbf24;
+ --chart-5: #f97316;
--sidebar: var(--color-onyx);
--sidebar-foreground: var(--color-alabaster);
--sidebar-primary: var(--color-onyx);
@@ -215,9 +185,40 @@ button:hover {
--sidebar-accent-foreground: var(--color-nuit);
--sidebar-border: rgba(255, 255, 255, 0.15);
--sidebar-ring: var(--color-jaune-vert);
- --chart-1: #60a5fa;
- --chart-2: #22d3ee;
- --chart-3: #86efac;
- --chart-4: #fbbf24;
- --chart-5: #f97316;
-}
\ No newline at end of file
+ }
+}
+
+/* Alternative : Support de la classe `.dark` pour contrôle manuel */
+.dark {
+ --background: var(--color-nuit);
+ --foreground: var(--color-alabaster);
+ --card: var(--color-onyx);
+ --card-foreground: var(--color-alabaster);
+ --popover: var(--color-onyx);
+ --popover-foreground: var(--color-alabaster);
+ --primary: var(--color-brunswick-green);
+ --primary-foreground: var(--color-nuit);
+ --secondary: var(--color-vert-de-gris);
+ --secondary-foreground: var(--color-nuit);
+ --muted: var(--color-onyx);
+ --muted-foreground: #9ca3af;
+ --accent: var(--color-citrouille);
+ --accent-foreground: var(--color-nuit);
+ --destructive: #ef4444;
+ --border: rgba(255, 255, 255, 0.15);
+ --input: rgba(255, 255, 255, 0.05);
+ --ring: var(--color-jaune-vert);
+ --sidebar: var(--color-onyx);
+ --sidebar-foreground: var(--color-alabaster);
+ --sidebar-primary: var(--color-onyx);
+ --sidebar-primary-foreground: var(--color-vert-kelly);
+ --sidebar-accent: var(--color-citrouille);
+ --sidebar-accent-foreground: var(--color-nuit);
+ --sidebar-border: rgba(255, 255, 255, 0.15);
+ --sidebar-ring: var(--color-jaune-vert);
+ --chart-1: #60a5fa;
+ --chart-2: #22d3ee;
+ --chart-3: #86efac;
+ --chart-4: #fbbf24;
+ --chart-5: #f97316;
+}
diff --git a/webapp/src/lib/utils.ts b/webapp/src/lib/utils.ts
index bd0c391..365058c 100644
--- a/webapp/src/lib/utils.ts
+++ b/webapp/src/lib/utils.ts
@@ -1,6 +1,6 @@
-import { clsx, type ClassValue } from "clsx"
-import { twMerge } from "tailwind-merge"
+import { type ClassValue, clsx } from "clsx";
+import { twMerge } from "tailwind-merge";
export function cn(...inputs: ClassValue[]) {
- return twMerge(clsx(inputs))
+ return twMerge(clsx(inputs));
}
diff --git a/webapp/src/main.tsx b/webapp/src/main.tsx
index e99750c..d2dc45d 100644
--- a/webapp/src/main.tsx
+++ b/webapp/src/main.tsx
@@ -1,10 +1,11 @@
-import { StrictMode } from 'react'
-import { createRoot } from 'react-dom/client'
-import './index.css'
-import App from './app/App.tsx'
+import { StrictMode } from "react";
-createRoot(document.getElementById('root')!).render(
+import App from "./app/App.tsx";
+import "./index.css";
+import { createRoot } from "react-dom/client";
+
+createRoot(document.getElementById("root")!).render(
,
-)
+);
diff --git a/webapp/src/pages/LoginPage.tsx b/webapp/src/pages/LoginPage.tsx
index 8ec65b0..530076f 100644
--- a/webapp/src/pages/LoginPage.tsx
+++ b/webapp/src/pages/LoginPage.tsx
@@ -1,7 +1,7 @@
export function LoginPage() {
- return (
-
-
Login Page
-
- );
-}
\ No newline at end of file
+ return (
+
+
Login Page
+
+ );
+}
diff --git a/webapp/src/pages/MainPage.tsx b/webapp/src/pages/MainPage.tsx
index 0910980..26e889c 100644
--- a/webapp/src/pages/MainPage.tsx
+++ b/webapp/src/pages/MainPage.tsx
@@ -1,63 +1,72 @@
-import { useApi } from "@providers";
-import { Header } from "@components";
-import { SidebarProvider } from "@ui/sidebar";
-import { DashboardPopover, MapSidebar, Map } from "@/widgets";
import { useEffect, useState } from "react";
+import { useApi } from "@providers";
+
+import { Header } from "@components/Header";
import {
- ResizableHandle,
- ResizablePanel,
- ResizablePanelGroup,
-} from "@/components/ui/resizable"
+ ResizableHandle,
+ ResizablePanel,
+ ResizablePanelGroup,
+} from "@components/ui/resizable";
+
+import { DashboardPopover, Map, MapSidebar } from "@widgets";
+
+import { SidebarProvider } from "@ui/sidebar";
export interface MainPageProps {
- userData?: unknown;
+ userData?: unknown;
}
export function MainPage() {
- const client = useApi();
- const [data, setData] = useState(null);
-
- useEffect(() => {
- client.getData()
- .then((json) => setData(json.data))
- .catch((err) => console.error("fetchData error", err));
- }, []);
- return (
-
-
console.log("Login clicked")}
- onLogout={() => console.log("Logout clicked")}
- isLogin={false} />
-
- {/* TODO: Integrate Sidebar with Resizable Panels smoothly: https://github.com/huntabyte/shadcn-svelte/discussions/1657 */}
-
-
-
-
-
-
-
-
-
-
-
- {/** @ts-expect-error Need to type data */}
-
-
-
-
-
-
-
-
-
-
+ const client = useApi();
+ const [data, setData] = useState(null);
+
+ useEffect(() => {
+ client
+ .getData()
+ .then((json) => setData(json.data))
+ .catch((err) => console.error("fetchData error", err));
+ }, []);
+ return (
+
+
console.log("Login clicked")}
+ onLogout={() => console.log("Logout clicked")}
+ isLogin={false}
+ />
+
+ {/* TODO: Integrate Sidebar with Resizable Panels smoothly: https://github.com/huntabyte/shadcn-svelte/discussions/1657 */}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
- );
+
+
+
+
+ );
}
-
diff --git a/webapp/src/pages/index.ts b/webapp/src/pages/index.ts
index 316470a..e4c7407 100644
--- a/webapp/src/pages/index.ts
+++ b/webapp/src/pages/index.ts
@@ -1,2 +1,2 @@
-export { LoginPage } from './LoginPage';
-export { MainPage } from './MainPage';
\ No newline at end of file
+export { LoginPage } from "./LoginPage";
+export { MainPage } from "./MainPage";
diff --git a/webapp/src/widgets/DashboardPopover.tsx b/webapp/src/widgets/DashboardPopover.tsx
index 5193e7f..8edb1a9 100644
--- a/webapp/src/widgets/DashboardPopover.tsx
+++ b/webapp/src/widgets/DashboardPopover.tsx
@@ -1,36 +1,42 @@
import { ExampleGraph, type GraphConsoElecProps } from "@components";
+
import { Button } from "@ui/button";
-import { Popover, PopoverTrigger, PopoverContent } from "@ui/popover";
+import { Popover, PopoverContent, PopoverTrigger } from "@ui/popover";
export interface DashboardProps {
- graphData: {
- clientByName: { fullName: GraphConsoElecProps["name"], consumptionSet: GraphConsoElecProps["chartData"] }
+ graphData: {
+ clientByName: {
+ fullName: GraphConsoElecProps["name"];
+ consumptionSet: GraphConsoElecProps["chartData"];
};
- dataType: string;
+ };
+ dataType: string;
}
export function DashboardPopover({ graphData, dataType }: DashboardProps) {
- return (
-
-
-
-
-
-
-
-
Dashboard
-
- Simple graphs to represent data
-
-
-
- {graphData && dataType === "example" && (
-
- )}
-
-
-
-
-
- );
-}
\ No newline at end of file
+ return (
+
+
+
+
+
+
+
+
Dashboard
+
+ Simple graphs to represent data
+
+
+
+ {graphData && dataType === "example" && (
+
+ )}
+
+
+
+
+ );
+}
diff --git a/webapp/src/widgets/Map.tsx b/webapp/src/widgets/Map.tsx
index e2c3dd3..50b50b5 100644
--- a/webapp/src/widgets/Map.tsx
+++ b/webapp/src/widgets/Map.tsx
@@ -1,42 +1,48 @@
// @ts-expect-error Could not find a declaration file for module 'coordo'.
-import { createMap } from "coordo"
-import { useEffect, useRef, useState, type FC } from "react";
+import { createMap } from "coordo";
+import { type FC, useEffect, useRef, useState } from "react";
export type MapApi = {
- getDataForLayer: (layerId: string) => unknown;
-}
+ getDataForLayer: (layerId: string) => unknown;
+};
// Hook personnalisé pour initialiser la carte
function useMap(containerSelector: string) {
- const [mapApi, setMapApi] = useState({} as MapApi);
- const isInitialized = useRef(false);
-
- useEffect(() => {
- if (isInitialized.current) return;
-
- try {
- const api = createMap(containerSelector);
- setMapApi(api);
- isInitialized.current = true;
- } catch (error) {
- console.error("Erreur lors de l'initialisation de la carte:", error);
- }
- }, [containerSelector]);
-
- return mapApi;
+ const [mapApi, setMapApi] = useState({} as MapApi);
+ const isInitialized = useRef(false);
+
+ useEffect(() => {
+ if (isInitialized.current) return;
+
+ try {
+ const api = createMap(containerSelector);
+ setMapApi(api);
+ isInitialized.current = true;
+ } catch (error) {
+ console.error("Erreur lors de l'initialisation de la carte:", error);
+ }
+ }, [containerSelector]);
+
+ return mapApi;
}
export const Map: FC = () => {
- const mapApi = useMap("#map");
-
- return (
- console.log(mapApi.getDataForLayer("my-layer"))}>
-
-
- );
-}
-
+ const mapApi = useMap("#map");
+
+ return (
+ console.log(mapApi.getDataForLayer("my-layer"))}
+ >
+
+
+ );
+};
diff --git a/webapp/src/widgets/MapSidebar.tsx b/webapp/src/widgets/MapSidebar.tsx
index aa4c211..3c8a142 100644
--- a/webapp/src/widgets/MapSidebar.tsx
+++ b/webapp/src/widgets/MapSidebar.tsx
@@ -1,40 +1,44 @@
-import { useState } from "react"
+import { useState } from "react";
-import { Label } from "@ui/label"
-import { RadioGroup, RadioGroupItem } from "@ui/radio-group"
-import { Slider } from "@ui/slider"
+import { Label } from "@ui/label";
+import { RadioGroup, RadioGroupItem } from "@ui/radio-group";
+import { Slider } from "@ui/slider";
export function MapSidebar() {
- const [value, setValue] = useState([10])
+ const [value, setValue] = useState([10]);
- return (
- <>
- Section de filtres
-
-
-
-
-
-
-
-
-
-
-
-
-
- {value}
-
-
-
-
-
- >
- )
-}
\ No newline at end of file
+ return (
+ <>
+ Section de filtres
+
+
+
+
+
+
+
+
+
+
+
+ >
+ );
+}
diff --git a/webapp/src/widgets/index.ts b/webapp/src/widgets/index.ts
index c0f06c6..00e8abe 100644
--- a/webapp/src/widgets/index.ts
+++ b/webapp/src/widgets/index.ts
@@ -1,3 +1,3 @@
export { DashboardPopover } from "./DashboardPopover";
export { MapSidebar } from "./MapSidebar";
-export { Map } from "./Map";
\ No newline at end of file
+export { Map } from "./Map";
diff --git a/webapp/tailwind.config.ts b/webapp/tailwind.config.ts
index 9c89dd2..85d7273 100644
--- a/webapp/tailwind.config.ts
+++ b/webapp/tailwind.config.ts
@@ -43,16 +43,10 @@ export default {
],
// Corps principal : Arial
- "a4t-body-primary": [
- "Arial",
- ...defaultTheme.fontFamily.sans,
- ],
+ "a4t-body-primary": ["Arial", ...defaultTheme.fontFamily.sans],
// Corps secondaire : Open Sans
- "a4t-body-secondary": [
- "Open Sans",
- ...defaultTheme.fontFamily.sans,
- ],
+ "a4t-body-secondary": ["Open Sans", ...defaultTheme.fontFamily.sans],
},
screens: {
mdl: "920px",
diff --git a/webapp/tsconfig.app.json b/webapp/tsconfig.app.json
index b97100a..c99cecb 100644
--- a/webapp/tsconfig.app.json
+++ b/webapp/tsconfig.app.json
@@ -4,15 +4,9 @@
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
"target": "ES2022",
"useDefineForClassFields": true,
- "lib": [
- "ES2022",
- "DOM",
- "DOM.Iterable"
- ],
+ "lib": ["ES2022", "DOM", "DOM.Iterable"],
"module": "ESNext",
- "types": [
- "vite/client"
- ],
+ "types": ["vite/client"],
"skipLibCheck": true,
/* Bundler mode */
"moduleResolution": "bundler",
@@ -27,9 +21,7 @@
"noUnusedParameters": true,
"erasableSyntaxOnly": true,
"noFallthroughCasesInSwitch": true,
- "noUncheckedSideEffectImports": true,
+ "noUncheckedSideEffectImports": true
},
- "include": [
- "src"
- ]
-}
\ No newline at end of file
+ "include": ["src"]
+}
diff --git a/webapp/tsconfig.json b/webapp/tsconfig.json
index b649482..b5d6e68 100644
--- a/webapp/tsconfig.json
+++ b/webapp/tsconfig.json
@@ -11,39 +11,17 @@
"compilerOptions": {
"baseUrl": ".",
"paths": {
- "@/*": [
- "./src/*"
- ],
- "@app/*": [
- "./src/app/*"
- ],
- "@providers": [
- "./src/app/providers/index.ts"
- ],
- "@components": [
- "./src/components/index.ts"
- ],
- "@components/*": [
- "./src/components/*"
- ],
- "@pages": [
- "./src/pages/index.ts"
- ],
- "@pages/*": [
- "./src/pages/*"
- ],
- "@widgets": [
- "./src/widgets/index.ts"
- ],
- "@widgets/*": [
- "./src/widgets/*"
- ],
- "@ui/*": [
- "./src/components/ui/*"
- ],
- "@assets/*": [
- "./src/assets/*"
- ]
+ "@/*": ["./src/*"],
+ "@app/*": ["./src/app/*"],
+ "@providers": ["./src/app/providers/index.ts"],
+ "@components": ["./src/components/index.ts"],
+ "@components/*": ["./src/components/*"],
+ "@pages": ["./src/pages/index.ts"],
+ "@pages/*": ["./src/pages/*"],
+ "@widgets": ["./src/widgets/index.ts"],
+ "@widgets/*": ["./src/widgets/*"],
+ "@ui/*": ["./src/components/ui/*"],
+ "@assets/*": ["./src/assets/*"]
}
}
-}
\ No newline at end of file
+}
diff --git a/webapp/vite.config.ts b/webapp/vite.config.ts
index cb3294f..8af3926 100644
--- a/webapp/vite.config.ts
+++ b/webapp/vite.config.ts
@@ -1,25 +1,23 @@
-import { defineConfig } from 'vite'
-import react from '@vitejs/plugin-react'
-import tailwindcss from '@tailwindcss/vite'
+import path from "path";
-import path from 'path';
+import { defineConfig } from "vite";
+
+import tailwindcss from "@tailwindcss/vite";
+import react from "@vitejs/plugin-react";
// https://vite.dev/config/
export default defineConfig({
resolve: {
alias: {
- '@': path.resolve(__dirname, './src'),
- '@app': path.resolve(__dirname, './src/app'),
- "@providers": path.resolve(__dirname, './src/app/providers'),
- '@components': path.resolve(__dirname, './src/components'),
- '@widgets': path.resolve(__dirname, './src/widgets'),
- "@assets": path.resolve(__dirname, './src/assets'),
- "@pages": path.resolve(__dirname, './src/pages'),
- "@ui": path.resolve(__dirname, './src/components/ui'),
+ "@": path.resolve(__dirname, "./src"),
+ "@app": path.resolve(__dirname, "./src/app"),
+ "@providers": path.resolve(__dirname, "./src/app/providers"),
+ "@components": path.resolve(__dirname, "./src/components"),
+ "@widgets": path.resolve(__dirname, "./src/widgets"),
+ "@assets": path.resolve(__dirname, "./src/assets"),
+ "@pages": path.resolve(__dirname, "./src/pages"),
+ "@ui": path.resolve(__dirname, "./src/components/ui"),
},
},
- plugins: [
- react(),
- tailwindcss()
- ],
-})
+ plugins: [react(), tailwindcss()],
+});
diff --git a/webapp/webappTree.md b/webapp/webappTree.md
index 2c07808..79ee671 100644
--- a/webapp/webappTree.md
+++ b/webapp/webappTree.md
@@ -61,4 +61,4 @@ src
|-- Map.tsx
|-- MapSidebar.tsx
`-- index.ts
-```
\ No newline at end of file
+```