State management
This commit is contained in:
@@ -1,5 +1,4 @@
|
|||||||
{
|
{
|
||||||
"$schema": "./node_modules/@biomejs/biome/configuration_schema.json",
|
|
||||||
"organizeImports": {
|
"organizeImports": {
|
||||||
"enabled": true
|
"enabled": true
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,8 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/gun.jpg" />
|
<link rel="icon" type="image/svg+xml" href="/gun.jpg" />
|
||||||
|
<link rel="preconnect" href="https://fonts.gstatic.com">
|
||||||
|
<link href="https://fonts.googleapis.com/css2?family=Jost:ital,wght@0,100;0,200;0,400;1,100;1,200&display=swap" rel="stylesheet"/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Pull the Trigger</title>
|
<title>Pull the Trigger</title>
|
||||||
</head>
|
</head>
|
||||||
|
|||||||
220
package-lock.json
generated
220
package-lock.json
generated
@@ -9,27 +9,27 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hello-pangea/dnd": "^18.0.1",
|
"@hello-pangea/dnd": "^18.0.1",
|
||||||
"@mantine/core": "^7.17.5",
|
"@mantine/core": "^7.17.7",
|
||||||
"@mantine/hooks": "^7.17.5",
|
"@mantine/hooks": "^7.17.7",
|
||||||
"@mantine/notifications": "^7.17.5",
|
"@mantine/notifications": "^7.17.7",
|
||||||
"@tanstack/react-query": "^5.74.4",
|
"@tanstack/react-query": "^5.75.1",
|
||||||
"@tanstack/react-query-devtools": "^5.74.6",
|
"@tanstack/react-query-devtools": "^5.75.1",
|
||||||
"@tanstack/react-query-persist-client": "^5.74.6",
|
"@tanstack/react-query-persist-client": "^5.75.1",
|
||||||
"idb-keyval": "^6.2.1",
|
"idb-keyval": "^6.2.1",
|
||||||
"jotai": "^2.12.3",
|
"jotai": "^2.12.3",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"react-query": "^3.39.3",
|
"react-query": "^3.39.3",
|
||||||
"react-router-dom": "^7.5.2",
|
"react-router-dom": "^7.5.3",
|
||||||
"recharts": "^2.15.3"
|
"recharts": "^2.15.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^22.15.2",
|
"@types/node": "^22.15.3",
|
||||||
"@types/react": "^19.1.2",
|
"@types/react": "^19.1.2",
|
||||||
"@types/react-dom": "^19.1.2",
|
"@types/react-dom": "^19.1.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.31.0",
|
"@typescript-eslint/eslint-plugin": "^8.31.1",
|
||||||
"@typescript-eslint/parser": "^8.31.0",
|
"@typescript-eslint/parser": "^8.31.1",
|
||||||
"@vitejs/plugin-react": "^4.4.1",
|
"@vitejs/plugin-react": "^4.4.1",
|
||||||
"@vitest/coverage-v8": "^3.1.2",
|
"@vitest/coverage-v8": "^3.1.2",
|
||||||
"@vitest/ui": "^3.1.2",
|
"@vitest/ui": "^3.1.2",
|
||||||
@@ -37,7 +37,7 @@
|
|||||||
"eslint-plugin-react-hooks": "^5.2.0",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.20",
|
"eslint-plugin-react-refresh": "^0.4.20",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vite": "^6.3.3",
|
"vite": "^6.3.4",
|
||||||
"vite-plugin-dts": "~4.5.3",
|
"vite-plugin-dts": "~4.5.3",
|
||||||
"vite-plugin-eslint": "^1.8.1",
|
"vite-plugin-eslint": "^1.8.1",
|
||||||
"vite-tsconfig-paths": "^5.1.4",
|
"vite-tsconfig-paths": "^5.1.4",
|
||||||
@@ -1198,9 +1198,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mantine/core": {
|
"node_modules/@mantine/core": {
|
||||||
"version": "7.17.5",
|
"version": "7.17.7",
|
||||||
"resolved": "https://registry.npmjs.org/@mantine/core/-/core-7.17.5.tgz",
|
"resolved": "https://registry.npmjs.org/@mantine/core/-/core-7.17.7.tgz",
|
||||||
"integrity": "sha512-66g/lr281cDPfucjtPw8gFo/yNS9G5iSKqysvPGuDpUBG2bEw8FsJMIsU0bMXtravToIpa3vJRrFUuPndPGnpQ==",
|
"integrity": "sha512-JMyV4/jPATXxmE31g8TJxsrH7XvdrA5pwT4gg25zBl1KE5vLBpBLLjsHG728+bDKuf+bDV+8lw+1kqgW7FcplQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@floating-ui/react": "^0.26.28",
|
"@floating-ui/react": "^0.26.28",
|
||||||
@@ -1211,40 +1211,40 @@
|
|||||||
"type-fest": "^4.27.0"
|
"type-fest": "^4.27.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@mantine/hooks": "7.17.5",
|
"@mantine/hooks": "7.17.7",
|
||||||
"react": "^18.x || ^19.x",
|
"react": "^18.x || ^19.x",
|
||||||
"react-dom": "^18.x || ^19.x"
|
"react-dom": "^18.x || ^19.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mantine/hooks": {
|
"node_modules/@mantine/hooks": {
|
||||||
"version": "7.17.5",
|
"version": "7.17.7",
|
||||||
"resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-7.17.5.tgz",
|
"resolved": "https://registry.npmjs.org/@mantine/hooks/-/hooks-7.17.7.tgz",
|
||||||
"integrity": "sha512-Q/3AHI1fjl+W7xQ3jEoMmSoTxLqxMI2gPfxIjd73OPmRpPenYWR1zk/diirXXm2t7JOrAbmpA3/O1gzmgqzc/Q==",
|
"integrity": "sha512-5MIvN/YAcewc97nG3jVrlnFqAExnJRBNWmV6UgGHWbiZiPSCh5o2RJE/5ZVGSfkexDpav9gkm2jkWkIbemVqVA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^18.x || ^19.x"
|
"react": "^18.x || ^19.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mantine/notifications": {
|
"node_modules/@mantine/notifications": {
|
||||||
"version": "7.17.5",
|
"version": "7.17.7",
|
||||||
"resolved": "https://registry.npmjs.org/@mantine/notifications/-/notifications-7.17.5.tgz",
|
"resolved": "https://registry.npmjs.org/@mantine/notifications/-/notifications-7.17.7.tgz",
|
||||||
"integrity": "sha512-dLbrSm7ct97fb0Yv8ImVj9mVNkjnD/xkDCP1PANt/shM9xDh0TguqQTvborb+8Wxh1g+RtWVML/an5rVsHbKmg==",
|
"integrity": "sha512-T6m4uUPEkPcTdo7J29lDey5YDJkVh/t6kWaCGQ0xDX1tzGGGPtaf1Exj1N0EtrIetbXPuEE8+yvq5P7wUJ3t9w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@mantine/store": "7.17.5",
|
"@mantine/store": "7.17.7",
|
||||||
"react-transition-group": "4.4.5"
|
"react-transition-group": "4.4.5"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@mantine/core": "7.17.5",
|
"@mantine/core": "7.17.7",
|
||||||
"@mantine/hooks": "7.17.5",
|
"@mantine/hooks": "7.17.7",
|
||||||
"react": "^18.x || ^19.x",
|
"react": "^18.x || ^19.x",
|
||||||
"react-dom": "^18.x || ^19.x"
|
"react-dom": "^18.x || ^19.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@mantine/store": {
|
"node_modules/@mantine/store": {
|
||||||
"version": "7.17.5",
|
"version": "7.17.7",
|
||||||
"resolved": "https://registry.npmjs.org/@mantine/store/-/store-7.17.5.tgz",
|
"resolved": "https://registry.npmjs.org/@mantine/store/-/store-7.17.7.tgz",
|
||||||
"integrity": "sha512-HQzy4rBlUFyw+39TgiAV+TGuQivMWYeQlnMctKJlaxwVY5ZTdF2IpJ/JZcjkGrmrZvBwUQ8IOMFvt2eZc20P1Q==",
|
"integrity": "sha512-a2XmX6/ixuT+q1H7uNZq3opKZWlxS67XWU2fxCc/E/XHbzik25i2oj9inFpIZMT7UmhUkxj4/pbJQGMs3T5liw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": "^18.x || ^19.x"
|
"react": "^18.x || ^19.x"
|
||||||
@@ -1876,9 +1876,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/query-core": {
|
"node_modules/@tanstack/query-core": {
|
||||||
"version": "5.74.4",
|
"version": "5.75.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.74.4.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.75.0.tgz",
|
||||||
"integrity": "sha512-YuG0A0+3i9b2Gfo9fkmNnkUWh5+5cFhWBN0pJAHkHilTx6A0nv8kepkk4T4GRt4e5ahbtFj2eTtkiPcVU1xO4A==",
|
"integrity": "sha512-rk8KQuCdhoRkzjRVF3QxLgAfFUyS0k7+GCQjlGEpEGco+qazJ0eMH6aO1DjDjibH7/ik383nnztua3BG+lOnwg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -1886,9 +1886,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/query-devtools": {
|
"node_modules/@tanstack/query-devtools": {
|
||||||
"version": "5.74.6",
|
"version": "5.74.7",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.74.6.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/query-devtools/-/query-devtools-5.74.7.tgz",
|
||||||
"integrity": "sha512-djaFT11mVCOW3e0Ezfyiq7T6OoHy2LRI1fUFQvj+G6+/4A1FkuRMNUhQkdP1GXlx8id0f1/zd5fgDpIy5SU/Iw==",
|
"integrity": "sha512-nSNlfuGdnHf4yB0S+BoNYOE1o3oAH093weAYZolIHfS2stulyA/gWfSk/9H4ZFk5mAAHb5vNqAeJOmbdcGPEQw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -1896,12 +1896,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/query-persist-client-core": {
|
"node_modules/@tanstack/query-persist-client-core": {
|
||||||
"version": "5.74.6",
|
"version": "5.75.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/query-persist-client-core/-/query-persist-client-core-5.74.6.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/query-persist-client-core/-/query-persist-client-core-5.75.0.tgz",
|
||||||
"integrity": "sha512-9OJ4tz4evC53tS4NfxaohctFjE9/sqvK4U5HlUBsBcQRI/fn+75lIpD9RcLIbUPcx78hPC35NSUKD7OX6YNw4Q==",
|
"integrity": "sha512-/EeURZCen5hw1u4B7s/UbbwrtvNBX/VNWhR8rNtXvXmY9020YtvRd95SCblUVd8kcia4knPM+T+UThskowKmVA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/query-core": "5.74.4"
|
"@tanstack/query-core": "5.75.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -1909,12 +1909,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/react-query": {
|
"node_modules/@tanstack/react-query": {
|
||||||
"version": "5.74.4",
|
"version": "5.75.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.74.4.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.75.1.tgz",
|
||||||
"integrity": "sha512-mAbxw60d4ffQ4qmRYfkO1xzRBPUEf/72Dgo3qqea0J66nIKuDTLEqQt0ku++SDFlMGMnB6uKDnEG1xD/TDse4Q==",
|
"integrity": "sha512-tN+gG+eXCHYm+VpmdXUP1rfE9LUrRzgYozTkBZtJV1/WFM3vwWNKQC8G6b2RKcs+2cPg+hdToZHZfjL3bF4yIQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/query-core": "5.74.4"
|
"@tanstack/query-core": "5.75.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
@@ -1925,36 +1925,36 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/react-query-devtools": {
|
"node_modules/@tanstack/react-query-devtools": {
|
||||||
"version": "5.74.6",
|
"version": "5.75.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.74.6.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/react-query-devtools/-/react-query-devtools-5.75.1.tgz",
|
||||||
"integrity": "sha512-vlsDwz4/FsblK0h7VAlXUdJ+9OV+i1n8OLb8CLLAZqu0M9GCnbajytZwsRmns33PXBZ6wQBJ859kg6aajx+e9Q==",
|
"integrity": "sha512-6S71fJRBlb0adlG5z/OHRqZqtHoPYVCklf/KCnOoZ3vdx9O/K9BLvqeeDeMUkZ6Rak/IupbEbvBsFoUiMHwZiQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/query-devtools": "5.74.6"
|
"@tanstack/query-devtools": "5.74.7"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
"url": "https://github.com/sponsors/tannerlinsley"
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@tanstack/react-query": "^5.74.4",
|
"@tanstack/react-query": "^5.75.1",
|
||||||
"react": "^18 || ^19"
|
"react": "^18 || ^19"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@tanstack/react-query-persist-client": {
|
"node_modules/@tanstack/react-query-persist-client": {
|
||||||
"version": "5.74.6",
|
"version": "5.75.1",
|
||||||
"resolved": "https://registry.npmjs.org/@tanstack/react-query-persist-client/-/react-query-persist-client-5.74.6.tgz",
|
"resolved": "https://registry.npmjs.org/@tanstack/react-query-persist-client/-/react-query-persist-client-5.75.1.tgz",
|
||||||
"integrity": "sha512-gGJ+4IKIRWC9JeChBOvGgZj1lQcP3bAT8Kofv1Csx4CbqkyhbALlUkpiUXYyVpeS60acXS6NRAajlfzRtfsE+Q==",
|
"integrity": "sha512-o7Dqw2Moon+4BtjT0+sizrRP8jFv2CNOOFicRWsmEsjA4qRi6H+9JXYtakayLh4xNhD5V4IDJ1817ZfhBsXqeQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tanstack/query-persist-client-core": "5.74.6"
|
"@tanstack/query-persist-client-core": "5.75.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
"type": "github",
|
"type": "github",
|
||||||
"url": "https://github.com/sponsors/tannerlinsley"
|
"url": "https://github.com/sponsors/tannerlinsley"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@tanstack/react-query": "^5.74.4",
|
"@tanstack/react-query": "^5.75.1",
|
||||||
"react": "^18 || ^19"
|
"react": "^18 || ^19"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2083,9 +2083,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "22.15.2",
|
"version": "22.15.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.15.3.tgz",
|
||||||
"integrity": "sha512-uKXqKN9beGoMdBfcaTY1ecwz6ctxuJAcUlwE55938g0ZJ8lRxwAZqRz2AJ4pzpt5dHdTPMB863UZ0ESiFUcP7A==",
|
"integrity": "sha512-lX7HFZeHf4QG/J7tBZqrCAXwz9J5RD56Y6MpP0eJkka8p+K0RY/yBTW7CYFJ4VGCclxqOLKmiGP5juQc6MKgcw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
@@ -2103,9 +2103,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/react-dom": {
|
"node_modules/@types/react-dom": {
|
||||||
"version": "19.1.2",
|
"version": "19.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.1.3.tgz",
|
||||||
"integrity": "sha512-XGJkWF41Qq305SKWEILa1O8vzhb3aOo3ogBlSmiqNko/WmRb6QIaweuZCXjKygVDXpzXb5wyxKTSOsmkuqj+Qw==",
|
"integrity": "sha512-rJXC08OG0h3W6wDMFxQrZF00Kq6qQvw0djHRdzl3U5DnIERz0MRce3WVc7IS6JYBwtaP/DwYtRRjVlvivNveKg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
@@ -2119,17 +2119,17 @@
|
|||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/eslint-plugin": {
|
"node_modules/@typescript-eslint/eslint-plugin": {
|
||||||
"version": "8.31.0",
|
"version": "8.31.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.31.1.tgz",
|
||||||
"integrity": "sha512-evaQJZ/J/S4wisevDvC1KFZkPzRetH8kYZbkgcTRyql3mcKsf+ZFDV1BVWUGTCAW5pQHoqn5gK5b8kn7ou9aFQ==",
|
"integrity": "sha512-oUlH4h1ABavI4F0Xnl8/fOtML/eu8nI2A1nYd+f+55XI0BLu+RIqKoCiZKNo6DtqZBEQm5aNKA20G3Z5w3R6GQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/regexpp": "^4.10.0",
|
"@eslint-community/regexpp": "^4.10.0",
|
||||||
"@typescript-eslint/scope-manager": "8.31.0",
|
"@typescript-eslint/scope-manager": "8.31.1",
|
||||||
"@typescript-eslint/type-utils": "8.31.0",
|
"@typescript-eslint/type-utils": "8.31.1",
|
||||||
"@typescript-eslint/utils": "8.31.0",
|
"@typescript-eslint/utils": "8.31.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.31.0",
|
"@typescript-eslint/visitor-keys": "8.31.1",
|
||||||
"graphemer": "^1.4.0",
|
"graphemer": "^1.4.0",
|
||||||
"ignore": "^5.3.1",
|
"ignore": "^5.3.1",
|
||||||
"natural-compare": "^1.4.0",
|
"natural-compare": "^1.4.0",
|
||||||
@@ -2149,16 +2149,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/parser": {
|
"node_modules/@typescript-eslint/parser": {
|
||||||
"version": "8.31.0",
|
"version": "8.31.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.31.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.31.1.tgz",
|
||||||
"integrity": "sha512-67kYYShjBR0jNI5vsf/c3WG4u+zDnCTHTPqVMQguffaWWFs7artgwKmfwdifl+r6XyM5LYLas/dInj2T0SgJyw==",
|
"integrity": "sha512-oU/OtYVydhXnumd0BobL9rkJg7wFJ9bFFPmSmB/bf/XWN85hlViji59ko6bSKBXyseT9V8l+CN1nwmlbiN0G7Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/scope-manager": "8.31.0",
|
"@typescript-eslint/scope-manager": "8.31.1",
|
||||||
"@typescript-eslint/types": "8.31.0",
|
"@typescript-eslint/types": "8.31.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.31.0",
|
"@typescript-eslint/typescript-estree": "8.31.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.31.0",
|
"@typescript-eslint/visitor-keys": "8.31.1",
|
||||||
"debug": "^4.3.4"
|
"debug": "^4.3.4"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2174,14 +2174,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/scope-manager": {
|
"node_modules/@typescript-eslint/scope-manager": {
|
||||||
"version": "8.31.0",
|
"version": "8.31.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.31.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.31.1.tgz",
|
||||||
"integrity": "sha512-knO8UyF78Nt8O/B64i7TlGXod69ko7z6vJD9uhSlm0qkAbGeRUSudcm0+K/4CrRjrpiHfBCjMWlc08Vav1xwcw==",
|
"integrity": "sha512-BMNLOElPxrtNQMIsFHE+3P0Yf1z0dJqV9zLdDxN/xLlWMlXK/ApEsVEKzpizg9oal8bAT5Sc7+ocal7AC1HCVw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.31.0",
|
"@typescript-eslint/types": "8.31.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.31.0"
|
"@typescript-eslint/visitor-keys": "8.31.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -2192,14 +2192,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/type-utils": {
|
"node_modules/@typescript-eslint/type-utils": {
|
||||||
"version": "8.31.0",
|
"version": "8.31.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.31.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.31.1.tgz",
|
||||||
"integrity": "sha512-DJ1N1GdjI7IS7uRlzJuEDCgDQix3ZVYVtgeWEyhyn4iaoitpMBX6Ndd488mXSx0xah/cONAkEaYyylDyAeHMHg==",
|
"integrity": "sha512-fNaT/m9n0+dpSp8G/iOQ05GoHYXbxw81x+yvr7TArTuZuCA6VVKbqWYVZrV5dVagpDTtj/O8k5HBEE/p/HM5LA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/typescript-estree": "8.31.0",
|
"@typescript-eslint/typescript-estree": "8.31.1",
|
||||||
"@typescript-eslint/utils": "8.31.0",
|
"@typescript-eslint/utils": "8.31.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"ts-api-utils": "^2.0.1"
|
"ts-api-utils": "^2.0.1"
|
||||||
},
|
},
|
||||||
@@ -2216,9 +2216,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/types": {
|
"node_modules/@typescript-eslint/types": {
|
||||||
"version": "8.31.0",
|
"version": "8.31.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.31.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.31.1.tgz",
|
||||||
"integrity": "sha512-Ch8oSjVyYyJxPQk8pMiP2FFGYatqXQfQIaMp+TpuuLlDachRWpUAeEu1u9B/v/8LToehUIWyiKcA/w5hUFRKuQ==",
|
"integrity": "sha512-SfepaEFUDQYRoA70DD9GtytljBePSj17qPxFHA/h3eg6lPTqGJ5mWOtbXCk1YrVU1cTJRd14nhaXWFu0l2troQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -2230,14 +2230,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/typescript-estree": {
|
"node_modules/@typescript-eslint/typescript-estree": {
|
||||||
"version": "8.31.0",
|
"version": "8.31.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.31.1.tgz",
|
||||||
"integrity": "sha512-xLmgn4Yl46xi6aDSZ9KkyfhhtnYI15/CvHbpOy/eR5NWhK/BK8wc709KKwhAR0m4ZKRP7h07bm4BWUYOCuRpQQ==",
|
"integrity": "sha512-kaA0ueLe2v7KunYOyWYtlf/QhhZb7+qh4Yw6Ni5kgukMIG+iP773tjgBiLWIXYumWCwEq3nLW+TUywEp8uEeag==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.31.0",
|
"@typescript-eslint/types": "8.31.1",
|
||||||
"@typescript-eslint/visitor-keys": "8.31.0",
|
"@typescript-eslint/visitor-keys": "8.31.1",
|
||||||
"debug": "^4.3.4",
|
"debug": "^4.3.4",
|
||||||
"fast-glob": "^3.3.2",
|
"fast-glob": "^3.3.2",
|
||||||
"is-glob": "^4.0.3",
|
"is-glob": "^4.0.3",
|
||||||
@@ -2257,16 +2257,16 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/utils": {
|
"node_modules/@typescript-eslint/utils": {
|
||||||
"version": "8.31.0",
|
"version": "8.31.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.31.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.31.1.tgz",
|
||||||
"integrity": "sha512-qi6uPLt9cjTFxAb1zGNgTob4x9ur7xC6mHQJ8GwEzGMGE9tYniublmJaowOJ9V2jUzxrltTPfdG2nKlWsq0+Ww==",
|
"integrity": "sha512-2DSI4SNfF5T4oRveQ4nUrSjUqjMND0nLq9rEkz0gfGr3tg0S5KB6DhwR+WZPCjzkZl3cH+4x2ce3EsL50FubjQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.4.0",
|
"@eslint-community/eslint-utils": "^4.4.0",
|
||||||
"@typescript-eslint/scope-manager": "8.31.0",
|
"@typescript-eslint/scope-manager": "8.31.1",
|
||||||
"@typescript-eslint/types": "8.31.0",
|
"@typescript-eslint/types": "8.31.1",
|
||||||
"@typescript-eslint/typescript-estree": "8.31.0"
|
"@typescript-eslint/typescript-estree": "8.31.1"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
@@ -2281,13 +2281,13 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@typescript-eslint/visitor-keys": {
|
"node_modules/@typescript-eslint/visitor-keys": {
|
||||||
"version": "8.31.0",
|
"version": "8.31.1",
|
||||||
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.0.tgz",
|
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.31.1.tgz",
|
||||||
"integrity": "sha512-QcGHmlRHWOl93o64ZUMNewCdwKGU6WItOU52H0djgNmn1EOrhVudrDzXz4OycCRSCPwFCDrE2iIt5vmuUdHxuQ==",
|
"integrity": "sha512-I+/rgqOVBn6f0o7NDTmAPWWC6NuqhV174lfYvAm9fUaWeiefLdux9/YI3/nLugEn9L8fcSi0XmpKi/r5u0nmpw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@typescript-eslint/types": "8.31.0",
|
"@typescript-eslint/types": "8.31.1",
|
||||||
"eslint-visitor-keys": "^4.2.0"
|
"eslint-visitor-keys": "^4.2.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
@@ -4933,9 +4933,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-router": {
|
"node_modules/react-router": {
|
||||||
"version": "7.5.2",
|
"version": "7.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-router/-/react-router-7.5.3.tgz",
|
||||||
"integrity": "sha512-9Rw8r199klMnlGZ8VAsV/I8WrIF6IyJ90JQUdboupx1cdkgYqwnrYjH+I/nY/7cA1X5zia4mDJqH36npP7sxGQ==",
|
"integrity": "sha512-3iUDM4/fZCQ89SXlDa+Ph3MevBrozBAI655OAfWQlTm9nBR0IKlrmNwFow5lPHttbwvITZfkeeeZFP6zt3F7pw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"cookie": "^1.0.1",
|
"cookie": "^1.0.1",
|
||||||
@@ -4956,12 +4956,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-router-dom": {
|
"node_modules/react-router-dom": {
|
||||||
"version": "7.5.2",
|
"version": "7.5.3",
|
||||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.5.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-7.5.3.tgz",
|
||||||
"integrity": "sha512-yk1XW8Fj7gK7flpYBXF3yzd2NbX6P7Kxjvs2b5nu1M04rb5pg/Zc4fGdBNTeT4eDYL2bvzWNyKaIMJX/RKHTTg==",
|
"integrity": "sha512-cK0jSaTyW4jV9SRKAItMIQfWZ/D6WEZafgHuuCb9g+SjhLolY78qc+De4w/Cz9ybjvLzShAmaIMEXt8iF1Cm+A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"react-router": "7.5.2"
|
"react-router": "7.5.3"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.0.0"
|
"node": ">=20.0.0"
|
||||||
@@ -5851,9 +5851,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/vite": {
|
"node_modules/vite": {
|
||||||
"version": "6.3.3",
|
"version": "6.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/vite/-/vite-6.3.4.tgz",
|
||||||
"integrity": "sha512-5nXH+QsELbFKhsEfWLkHrvgRpTdGJzqOZ+utSdmPTvwHmvU6ITTm3xx+mRusihkcI8GeC7lCDyn3kDtiki9scw==",
|
"integrity": "sha512-BiReIiMS2fyFqbqNT/Qqt4CVITDU9M9vE+DKcVAsB+ZV0wvTKd+3hMbkpxz1b+NmEDMegpVbisKiAZOnvO92Sw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
24
package.json
24
package.json
@@ -11,27 +11,27 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@hello-pangea/dnd": "^18.0.1",
|
"@hello-pangea/dnd": "^18.0.1",
|
||||||
"@mantine/core": "^7.17.5",
|
"@mantine/core": "^7.17.7",
|
||||||
"@mantine/hooks": "^7.17.5",
|
"@mantine/hooks": "^7.17.7",
|
||||||
"@mantine/notifications": "^7.17.5",
|
"@mantine/notifications": "^7.17.7",
|
||||||
"@tanstack/react-query": "^5.74.4",
|
"@tanstack/react-query": "^5.75.1",
|
||||||
"@tanstack/react-query-devtools": "^5.74.6",
|
"@tanstack/react-query-devtools": "^5.75.1",
|
||||||
"@tanstack/react-query-persist-client": "^5.74.6",
|
"@tanstack/react-query-persist-client": "^5.75.1",
|
||||||
"idb-keyval": "^6.2.1",
|
"idb-keyval": "^6.2.1",
|
||||||
"jotai": "^2.12.3",
|
"jotai": "^2.12.3",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0",
|
"react-dom": "^19.1.0",
|
||||||
"react-icons": "^5.5.0",
|
"react-icons": "^5.5.0",
|
||||||
"react-query": "^3.39.3",
|
"react-query": "^3.39.3",
|
||||||
"react-router-dom": "^7.5.2",
|
"react-router-dom": "^7.5.3",
|
||||||
"recharts": "^2.15.3"
|
"recharts": "^2.15.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^22.15.2",
|
"@types/node": "^22.15.3",
|
||||||
"@types/react": "^19.1.2",
|
"@types/react": "^19.1.2",
|
||||||
"@types/react-dom": "^19.1.2",
|
"@types/react-dom": "^19.1.3",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.31.0",
|
"@typescript-eslint/eslint-plugin": "^8.31.1",
|
||||||
"@typescript-eslint/parser": "^8.31.0",
|
"@typescript-eslint/parser": "^8.31.1",
|
||||||
"@vitejs/plugin-react": "^4.4.1",
|
"@vitejs/plugin-react": "^4.4.1",
|
||||||
"@vitest/coverage-v8": "^3.1.2",
|
"@vitest/coverage-v8": "^3.1.2",
|
||||||
"@vitest/ui": "^3.1.2",
|
"@vitest/ui": "^3.1.2",
|
||||||
@@ -39,7 +39,7 @@
|
|||||||
"eslint-plugin-react-hooks": "^5.2.0",
|
"eslint-plugin-react-hooks": "^5.2.0",
|
||||||
"eslint-plugin-react-refresh": "^0.4.20",
|
"eslint-plugin-react-refresh": "^0.4.20",
|
||||||
"typescript": "^5.8.3",
|
"typescript": "^5.8.3",
|
||||||
"vite": "^6.3.3",
|
"vite": "^6.3.4",
|
||||||
"vite-plugin-dts": "~4.5.3",
|
"vite-plugin-dts": "~4.5.3",
|
||||||
"vite-plugin-eslint": "^1.8.1",
|
"vite-plugin-eslint": "^1.8.1",
|
||||||
"vite-tsconfig-paths": "^5.1.4",
|
"vite-tsconfig-paths": "^5.1.4",
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import { Loading, MainLayout } from './components';
|
|||||||
import '@mantine/core/styles.css';
|
import '@mantine/core/styles.css';
|
||||||
import '@mantine/notifications/styles.css';
|
import '@mantine/notifications/styles.css';
|
||||||
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
|
import { ReactQueryDevtools } from '@tanstack/react-query-devtools';
|
||||||
import './index.css';
|
|
||||||
import { Homepage, Settings } from 'pages';
|
import { Homepage, Settings } from 'pages';
|
||||||
import type { Theme, ThemePlaylist } from 'types';
|
import type { Theme, ThemePlaylist } from 'types';
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,8 @@ export default function WeatherGraphs({
|
|||||||
{payload.map((item: any) => (
|
{payload.map((item: any) => (
|
||||||
<Text
|
<Text
|
||||||
key={item.name}
|
key={item.name}
|
||||||
size='sm'
|
size='md'
|
||||||
|
c={item.stroke}
|
||||||
>{`${item.name} - ${item.value}${item.unit}`}</Text>
|
>{`${item.name} - ${item.value}${item.unit}`}</Text>
|
||||||
))}
|
))}
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -41,7 +41,6 @@ export function useCommonHooks() {
|
|||||||
key: 'theme',
|
key: 'theme',
|
||||||
defaultValue: 'blackboard',
|
defaultValue: 'blackboard',
|
||||||
});
|
});
|
||||||
|
|
||||||
const [currentThemePlaylist, setCurrentThemePlaylist] = useLocalStorage<string>({
|
const [currentThemePlaylist, setCurrentThemePlaylist] = useLocalStorage<string>({
|
||||||
key: 'themePlaylist',
|
key: 'themePlaylist',
|
||||||
defaultValue: 'All',
|
defaultValue: 'All',
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
@import url("https://fonts.googleapis.com/css2?family=Jost:ital,wght@0,100;0,200;0,400;1,100;1,200&display=swap");
|
|
||||||
@@ -24,6 +24,7 @@ import * as vsc from 'react-icons/vsc';
|
|||||||
import { popoverClasses, selectClasses, textInputClasses } from 'styles';
|
import { popoverClasses, selectClasses, textInputClasses } from 'styles';
|
||||||
import type { Application } from 'types';
|
import type { Application } from 'types';
|
||||||
import AddItemModal from '../Shared/AddItemModal';
|
import AddItemModal from '../Shared/AddItemModal';
|
||||||
|
import NoItemsFound from '../Shared/NoItemsFound';
|
||||||
import SettingsHeader from '../Shared/SettingsHeader';
|
import SettingsHeader from '../Shared/SettingsHeader';
|
||||||
import AppSettingsItem from './AppSettingsItem';
|
import AppSettingsItem from './AppSettingsItem';
|
||||||
import DebouncedApplication from './DebouncedApplication';
|
import DebouncedApplication from './DebouncedApplication';
|
||||||
@@ -54,6 +55,7 @@ const ApplicationSettings = () => {
|
|||||||
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
||||||
const [dragging, setDragging] = useState(false);
|
const [dragging, setDragging] = useState(false);
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
function onDragEnd(result: any) {
|
function onDragEnd(result: any) {
|
||||||
if (!result.destination) {
|
if (!result.destination) {
|
||||||
@@ -81,17 +83,22 @@ const ApplicationSettings = () => {
|
|||||||
closeModal();
|
closeModal();
|
||||||
setNewApplication(defaultApplication);
|
setNewApplication(defaultApplication);
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (applicationData && !isAppsFetching) {
|
if (applicationData && !isAppsFetching) {
|
||||||
setApplications(
|
setApplications(
|
||||||
applicationData
|
applicationData
|
||||||
.filter((a: Application) =>
|
.filter(
|
||||||
a.name.toLowerCase().includes(debouncedSearch.toLowerCase()),
|
(a: Application) =>
|
||||||
|
a.name.toLowerCase().includes(debouncedSearch.toLowerCase()) ||
|
||||||
|
a.url.toLowerCase().includes(debouncedSearch.toLowerCase()) ||
|
||||||
|
a.baseUrl.toLowerCase().includes(debouncedSearch.toLowerCase()),
|
||||||
)
|
)
|
||||||
.sort((a: Application, b: Application) => (a.index > b.index ? 1 : -1)),
|
.sort((a: Application, b: Application) => (a.index > b.index ? 1 : -1)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (debouncedSearch === searchValue) {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
}, [applicationData, isAppsFetching, debouncedSearch]);
|
}, [applicationData, isAppsFetching, debouncedSearch]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -103,7 +110,6 @@ const ApplicationSettings = () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, [applicationList]);
|
}, [applicationList]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack w={'100%'}>
|
<Stack w={'100%'}>
|
||||||
<AddItemModal
|
<AddItemModal
|
||||||
@@ -253,11 +259,13 @@ const ApplicationSettings = () => {
|
|||||||
title={'Applications'}
|
title={'Applications'}
|
||||||
tooltip={{
|
tooltip={{
|
||||||
title:
|
title:
|
||||||
'Applications are the applicationData that will be displayed on the homepage.',
|
'Applications are the app buttons that will be displayed on the homepage.',
|
||||||
highlightList: [
|
highlightList: [
|
||||||
'Applications',
|
'Applications',
|
||||||
'applicationData',
|
'applicationData',
|
||||||
'application',
|
'application',
|
||||||
|
'app',
|
||||||
|
'apps',
|
||||||
'name',
|
'name',
|
||||||
'base url',
|
'base url',
|
||||||
'url',
|
'url',
|
||||||
@@ -270,6 +278,8 @@ const ApplicationSettings = () => {
|
|||||||
searchValue={searchValue}
|
searchValue={searchValue}
|
||||||
setSearchValue={setSearchValue}
|
setSearchValue={setSearchValue}
|
||||||
searchPlaceholder={'Search Applications...'}
|
searchPlaceholder={'Search Applications...'}
|
||||||
|
isLoading={isLoading}
|
||||||
|
setIsLoading={setIsLoading}
|
||||||
/>
|
/>
|
||||||
{dragging ? (
|
{dragging ? (
|
||||||
<DragDropContext onDragEnd={onDragEnd}>
|
<DragDropContext onDragEnd={onDragEnd}>
|
||||||
@@ -361,7 +371,8 @@ const ApplicationSettings = () => {
|
|||||||
align='center'
|
align='center'
|
||||||
>
|
>
|
||||||
<Grid columns={18} w={'75%'}>
|
<Grid columns={18} w={'75%'}>
|
||||||
{applications?.map((application: Application) => (
|
{applications.length > 0 ? (
|
||||||
|
applications?.map((application: Application) => (
|
||||||
<GridCol span={6} key={application.id}>
|
<GridCol span={6} key={application.id}>
|
||||||
<Popover
|
<Popover
|
||||||
withArrow
|
withArrow
|
||||||
@@ -393,7 +404,16 @@ const ApplicationSettings = () => {
|
|||||||
</Popover.Dropdown>
|
</Popover.Dropdown>
|
||||||
</Popover>
|
</Popover>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
))}
|
))
|
||||||
|
) : (
|
||||||
|
<GridCol
|
||||||
|
w={'100%'}
|
||||||
|
span={18}
|
||||||
|
style={{ display: 'flex', justifyContent: 'center' }}
|
||||||
|
>
|
||||||
|
<NoItemsFound />
|
||||||
|
</GridCol>
|
||||||
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import { textInputClasses } from 'styles';
|
import { textInputClasses } from 'styles';
|
||||||
import type { Bookmark, BookmarkGroup } from 'types';
|
import type { Bookmark, BookmarkGroup } from 'types';
|
||||||
import AddItemModal from '../Shared/AddItemModal';
|
import AddItemModal from '../Shared/AddItemModal';
|
||||||
|
import NoItemsFound from '../Shared/NoItemsFound';
|
||||||
import SettingsHeader from '../Shared/SettingsHeader';
|
import SettingsHeader from '../Shared/SettingsHeader';
|
||||||
import DebouncedGroupSettingsItem from './DebouncedGroupSettingsItem';
|
import DebouncedGroupSettingsItem from './DebouncedGroupSettingsItem';
|
||||||
const BookmarkSettings = () => {
|
const BookmarkSettings = () => {
|
||||||
@@ -33,6 +34,7 @@ const BookmarkSettings = () => {
|
|||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
const [debouncedGroupSearch] = useDebouncedValue(searchValue, 500);
|
const [debouncedGroupSearch] = useDebouncedValue(searchValue, 500);
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setNewGroup(defaultGroup);
|
setNewGroup(defaultGroup);
|
||||||
@@ -94,6 +96,9 @@ const BookmarkSettings = () => {
|
|||||||
);
|
);
|
||||||
setGroups(groupList);
|
setGroups(groupList);
|
||||||
}
|
}
|
||||||
|
if (debouncedGroupSearch === searchValue) {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
}, [groupData, groupsIsFetched, debouncedGroupSearch]);
|
}, [groupData, groupsIsFetched, debouncedGroupSearch]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -194,6 +199,8 @@ const BookmarkSettings = () => {
|
|||||||
searchValue={searchValue}
|
searchValue={searchValue}
|
||||||
setSearchValue={setSearchValue}
|
setSearchValue={setSearchValue}
|
||||||
searchPlaceholder={'Search Bookmark Groups...'}
|
searchPlaceholder={'Search Bookmark Groups...'}
|
||||||
|
isLoading={isLoading}
|
||||||
|
setIsLoading={setIsLoading}
|
||||||
/>
|
/>
|
||||||
{dragging ? (
|
{dragging ? (
|
||||||
<DragDropContext onDragEnd={onDragEnd}>
|
<DragDropContext onDragEnd={onDragEnd}>
|
||||||
@@ -285,7 +292,8 @@ const BookmarkSettings = () => {
|
|||||||
align='center'
|
align='center'
|
||||||
>
|
>
|
||||||
<Group w={isMobile ? undefined : '75%'} align='start' justify='center'>
|
<Group w={isMobile ? undefined : '75%'} align='start' justify='center'>
|
||||||
{groups?.map((group: BookmarkGroup) => (
|
{groups.length > 0 ? (
|
||||||
|
groups?.map((group: BookmarkGroup) => (
|
||||||
<DebouncedGroupSettingsItem
|
<DebouncedGroupSettingsItem
|
||||||
key={group.id}
|
key={group.id}
|
||||||
bookmarkGroup={group}
|
bookmarkGroup={group}
|
||||||
@@ -294,7 +302,12 @@ const BookmarkSettings = () => {
|
|||||||
.sort((a: Bookmark, b: Bookmark) => (a.index > b.index ? 1 : -1))}
|
.sort((a: Bookmark, b: Bookmark) => (a.index > b.index ? 1 : -1))}
|
||||||
searchTerm={searchValue}
|
searchTerm={searchValue}
|
||||||
/>
|
/>
|
||||||
))}
|
))
|
||||||
|
) : (
|
||||||
|
<Group w={'100%'} style={{ display: 'flex', justifyContent: 'center' }}>
|
||||||
|
<NoItemsFound />
|
||||||
|
</Group>
|
||||||
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -286,7 +286,7 @@ function DebouncedGroupSettingsItem({
|
|||||||
>
|
>
|
||||||
<Popover.Target>
|
<Popover.Target>
|
||||||
<Button
|
<Button
|
||||||
className={buttonClasses.tableButton}
|
className={buttonClasses.newItemButton}
|
||||||
classNames={buttonClasses}
|
classNames={buttonClasses}
|
||||||
w={'min-content'}
|
w={'min-content'}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import { textInputClasses } from 'styles';
|
import { textInputClasses } from 'styles';
|
||||||
import type { Message } from 'types';
|
import type { Message } from 'types';
|
||||||
import AddItemModal from '../Shared/AddItemModal';
|
import AddItemModal from '../Shared/AddItemModal';
|
||||||
|
import NoItemsFound from '../Shared/NoItemsFound';
|
||||||
import SettingsHeader from '../Shared/SettingsHeader';
|
import SettingsHeader from '../Shared/SettingsHeader';
|
||||||
import DebouncedMessage from './DebouncedMessage';
|
import DebouncedMessage from './DebouncedMessage';
|
||||||
|
|
||||||
@@ -23,6 +24,7 @@ const MessageSettings = () => {
|
|||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
||||||
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
const [modalOpened, { open: openModal, close: closeModal }] = useDisclosure(false);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setNewMessage('');
|
setNewMessage('');
|
||||||
@@ -38,6 +40,9 @@ const MessageSettings = () => {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (debouncedSearch === searchValue) {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
}, [messageData, isMessagesFetched, debouncedSearch]);
|
}, [messageData, isMessagesFetched, debouncedSearch]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -67,6 +72,8 @@ const MessageSettings = () => {
|
|||||||
searchValue={searchValue}
|
searchValue={searchValue}
|
||||||
setSearchValue={setSearchValue}
|
setSearchValue={setSearchValue}
|
||||||
searchPlaceholder={'Search Message content...'}
|
searchPlaceholder={'Search Message content...'}
|
||||||
|
isLoading={isLoading}
|
||||||
|
setIsLoading={setIsLoading}
|
||||||
/>
|
/>
|
||||||
<AddItemModal
|
<AddItemModal
|
||||||
modalOpened={modalOpened}
|
modalOpened={modalOpened}
|
||||||
@@ -122,7 +129,8 @@ const MessageSettings = () => {
|
|||||||
align='center'
|
align='center'
|
||||||
>
|
>
|
||||||
<Grid w={'75%'}>
|
<Grid w={'75%'}>
|
||||||
{messages?.map((message: Message) => (
|
{messages.length > 0 ? (
|
||||||
|
messages?.map((message: Message) => (
|
||||||
<GridCol span={isMobile ? 12 : 6} key={message.id}>
|
<GridCol span={isMobile ? 12 : 6} key={message.id}>
|
||||||
<DebouncedMessage
|
<DebouncedMessage
|
||||||
label={`ID# ${message.id}`}
|
label={`ID# ${message.id}`}
|
||||||
@@ -130,7 +138,16 @@ const MessageSettings = () => {
|
|||||||
setMessage={setMessage}
|
setMessage={setMessage}
|
||||||
/>
|
/>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
))}
|
))
|
||||||
|
) : (
|
||||||
|
<GridCol
|
||||||
|
w={'100%'}
|
||||||
|
span={12}
|
||||||
|
style={{ display: 'flex', justifyContent: 'center' }}
|
||||||
|
>
|
||||||
|
<NoItemsFound />
|
||||||
|
</GridCol>
|
||||||
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -17,8 +17,9 @@ const PersonalizationSettings = () => {
|
|||||||
const [personal, setPersonal] = useState<PersonalData>();
|
const [personal, setPersonal] = useState<PersonalData>();
|
||||||
const [update, setUpdate] = useState<any>({});
|
const [update, setUpdate] = useState<any>({});
|
||||||
const [debounced] = useDebouncedValue(update, 1000);
|
const [debounced] = useDebouncedValue(update, 1000);
|
||||||
const { mutateAsync: editRow } = useMutationAPI();
|
const { mutateAsync } = useMutationAPI();
|
||||||
const { isMobile } = useCommonHooks();
|
const { isMobile } = useCommonHooks();
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (personalData && personalIsFetched) {
|
if (personalData && personalIsFetched) {
|
||||||
setPersonal(personalData[0]);
|
setPersonal(personalData[0]);
|
||||||
@@ -28,7 +29,7 @@ const PersonalizationSettings = () => {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (Object.keys(debounced).length) {
|
if (Object.keys(debounced).length) {
|
||||||
setPersonal(update);
|
setPersonal(update);
|
||||||
editRow({ method: 'PATCH', endpoint: endpoint, body: debounced });
|
mutateAsync({ method: 'PATCH', endpoint: endpoint, body: debounced });
|
||||||
setUpdate({});
|
setUpdate({});
|
||||||
}
|
}
|
||||||
}, [debounced]);
|
}, [debounced]);
|
||||||
@@ -61,6 +62,8 @@ const PersonalizationSettings = () => {
|
|||||||
searchValue={undefined}
|
searchValue={undefined}
|
||||||
setSearchValue={() => {}}
|
setSearchValue={() => {}}
|
||||||
searchPlaceholder={undefined}
|
searchPlaceholder={undefined}
|
||||||
|
isLoading={false}
|
||||||
|
setIsLoading={() => {}}
|
||||||
/>
|
/>
|
||||||
<Stack
|
<Stack
|
||||||
align='center'
|
align='center'
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import { popoverClasses, textInputClasses } from 'styles';
|
import { popoverClasses, textInputClasses } from 'styles';
|
||||||
import type { Provider } from 'types';
|
import type { Provider } from 'types';
|
||||||
import AddItemModal from '../Shared/AddItemModal';
|
import AddItemModal from '../Shared/AddItemModal';
|
||||||
|
import NoItemsFound from '../Shared/NoItemsFound';
|
||||||
import SettingsHeader from '../Shared/SettingsHeader';
|
import SettingsHeader from '../Shared/SettingsHeader';
|
||||||
import DebouncedSearchProvider from './DebouncedSearchProvider';
|
import DebouncedSearchProvider from './DebouncedSearchProvider';
|
||||||
import SearchProviderSettingsItem from './SearchProviderSettingsItem';
|
import SearchProviderSettingsItem from './SearchProviderSettingsItem';
|
||||||
@@ -38,6 +39,7 @@ const SearchProviderSettings = () => {
|
|||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setNewProvider(defaultProvider);
|
setNewProvider(defaultProvider);
|
||||||
@@ -48,12 +50,17 @@ const SearchProviderSettings = () => {
|
|||||||
if (providerData && providerDataIsFetched) {
|
if (providerData && providerDataIsFetched) {
|
||||||
setProviders(
|
setProviders(
|
||||||
providerData
|
providerData
|
||||||
.filter((a: Provider) =>
|
.filter(
|
||||||
a.name.toLowerCase().includes(debouncedSearch.toLowerCase()),
|
(a: Provider) =>
|
||||||
|
a.name.toLowerCase().includes(debouncedSearch.toLowerCase()) ||
|
||||||
|
a.url.toLowerCase().includes(debouncedSearch.toLowerCase()),
|
||||||
)
|
)
|
||||||
.sort((a: Provider, b: Provider) => (a.prefix > b.prefix ? 1 : -1)),
|
.sort((a: Provider, b: Provider) => (a.prefix > b.prefix ? 1 : -1)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (debouncedSearch === searchValue) {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
}, [providerData, providerDataIsFetched, debouncedSearch]);
|
}, [providerData, providerDataIsFetched, debouncedSearch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -138,16 +145,18 @@ const SearchProviderSettings = () => {
|
|||||||
<SettingsHeader
|
<SettingsHeader
|
||||||
setDragging={undefined}
|
setDragging={undefined}
|
||||||
openModal={openModal}
|
openModal={openModal}
|
||||||
title={'Search providerData'}
|
title={'Search Providers'}
|
||||||
tooltip={{
|
tooltip={{
|
||||||
title: 'Search providerData and shortcuts can be configured here.',
|
title: 'Search providers and shortcuts can be configured here.',
|
||||||
highlightList: ['providerData', 'search', 'provider', 'prefix'],
|
highlightList: ['providerData', 'search', 'provider', 'prefix'],
|
||||||
description:
|
description:
|
||||||
'providerData can be used in the search bar. By starting a search with the prefix, it will be redirected to the url of the provider to complete the search.',
|
'Providers can be used in the search bar. By starting a search with the prefix, it will be redirected to the url of the provider to complete the search.',
|
||||||
}}
|
}}
|
||||||
searchValue={searchValue}
|
searchValue={searchValue}
|
||||||
setSearchValue={setSearchValue}
|
setSearchValue={setSearchValue}
|
||||||
searchPlaceholder={'Search Search providerData...'}
|
searchPlaceholder={'Search Search providerData...'}
|
||||||
|
isLoading={isLoading}
|
||||||
|
setIsLoading={setIsLoading}
|
||||||
/>
|
/>
|
||||||
<Stack
|
<Stack
|
||||||
mt={isMobile ? '9rem' : '6rem'}
|
mt={isMobile ? '9rem' : '6rem'}
|
||||||
@@ -156,7 +165,8 @@ const SearchProviderSettings = () => {
|
|||||||
align='center'
|
align='center'
|
||||||
>
|
>
|
||||||
<Grid columns={18} w={'75%'}>
|
<Grid columns={18} w={'75%'}>
|
||||||
{providers?.map((provider: Provider) => (
|
{providers.length > 0 ? (
|
||||||
|
providers?.map((provider: Provider) => (
|
||||||
<GridCol span={isMobile ? 18 : 6} key={provider.id}>
|
<GridCol span={isMobile ? 18 : 6} key={provider.id}>
|
||||||
<Popover
|
<Popover
|
||||||
withArrow
|
withArrow
|
||||||
@@ -181,7 +191,16 @@ const SearchProviderSettings = () => {
|
|||||||
</Popover.Dropdown>
|
</Popover.Dropdown>
|
||||||
</Popover>
|
</Popover>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
))}
|
))
|
||||||
|
) : (
|
||||||
|
<GridCol
|
||||||
|
w={'100%'}
|
||||||
|
span={18}
|
||||||
|
style={{ display: 'flex', justifyContent: 'center' }}
|
||||||
|
>
|
||||||
|
<NoItemsFound />
|
||||||
|
</GridCol>
|
||||||
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
22
src/pages/settings/components/Shared/NoItemsFound.tsx
Normal file
22
src/pages/settings/components/Shared/NoItemsFound.tsx
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
import { Card, Text } from '@mantine/core';
|
||||||
|
import { cardClasses } from 'styles';
|
||||||
|
|
||||||
|
function NoItemsFound() {
|
||||||
|
return (
|
||||||
|
<Card
|
||||||
|
className={cardClasses.settingsItem}
|
||||||
|
classNames={cardClasses}
|
||||||
|
w={'50%'}
|
||||||
|
h={'100%'}
|
||||||
|
p={'xl'}
|
||||||
|
m={'xl'}
|
||||||
|
style={{ display: 'flex', justifyContent: 'center', alignItems: 'center' }}
|
||||||
|
>
|
||||||
|
<Text fw={300} size={'xl'}>
|
||||||
|
No items found
|
||||||
|
</Text>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NoItemsFound;
|
||||||
@@ -10,7 +10,7 @@ import {
|
|||||||
TextInput,
|
TextInput,
|
||||||
} from '@mantine/core';
|
} from '@mantine/core';
|
||||||
import { useCommonHooks } from 'hooks';
|
import { useCommonHooks } from 'hooks';
|
||||||
import { FiHelpCircle, FiPlus } from 'react-icons/fi';
|
import { FiHelpCircle, FiLoader, FiPlus } from 'react-icons/fi';
|
||||||
import {
|
import {
|
||||||
actionIconClasses,
|
actionIconClasses,
|
||||||
buttonClasses,
|
buttonClasses,
|
||||||
@@ -28,6 +28,8 @@ function SettingsHeader({
|
|||||||
searchValue,
|
searchValue,
|
||||||
setSearchValue,
|
setSearchValue,
|
||||||
searchPlaceholder,
|
searchPlaceholder,
|
||||||
|
isLoading,
|
||||||
|
setIsLoading,
|
||||||
}: {
|
}: {
|
||||||
setDragging: undefined | ((dragging: boolean) => void);
|
setDragging: undefined | ((dragging: boolean) => void);
|
||||||
openModal: () => void;
|
openModal: () => void;
|
||||||
@@ -40,6 +42,8 @@ function SettingsHeader({
|
|||||||
searchValue: string | undefined;
|
searchValue: string | undefined;
|
||||||
setSearchValue: (searchValue: string) => void;
|
setSearchValue: (searchValue: string) => void;
|
||||||
searchPlaceholder: string | undefined;
|
searchPlaceholder: string | undefined;
|
||||||
|
isLoading: boolean;
|
||||||
|
setIsLoading: (isLoading: boolean) => void;
|
||||||
}) {
|
}) {
|
||||||
const { isMobile } = useCommonHooks();
|
const { isMobile } = useCommonHooks();
|
||||||
return (
|
return (
|
||||||
@@ -105,7 +109,7 @@ function SettingsHeader({
|
|||||||
</Popover>
|
</Popover>
|
||||||
{searchValue !== undefined && (
|
{searchValue !== undefined && (
|
||||||
<Button
|
<Button
|
||||||
className={buttonClasses.tableButton}
|
className={buttonClasses.newItemButton}
|
||||||
classNames={buttonClasses}
|
classNames={buttonClasses}
|
||||||
onClick={openModal}
|
onClick={openModal}
|
||||||
>
|
>
|
||||||
@@ -123,11 +127,22 @@ function SettingsHeader({
|
|||||||
placeholder={searchPlaceholder ?? 'Search...'}
|
placeholder={searchPlaceholder ?? 'Search...'}
|
||||||
value={searchValue}
|
value={searchValue}
|
||||||
onInput={(event: any) => {
|
onInput={(event: any) => {
|
||||||
|
setIsLoading(true);
|
||||||
setSearchValue(event.target.value);
|
setSearchValue(event.target.value);
|
||||||
}}
|
}}
|
||||||
style={{
|
style={{
|
||||||
zIndex: 100,
|
zIndex: 100,
|
||||||
}}
|
}}
|
||||||
|
rightSection={
|
||||||
|
isLoading && (
|
||||||
|
<ActionIcon
|
||||||
|
className={actionIconClasses.loadingSpinner}
|
||||||
|
classNames={actionIconClasses}
|
||||||
|
>
|
||||||
|
<FiLoader />
|
||||||
|
</ActionIcon>
|
||||||
|
)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{setDragging && (
|
{setDragging && (
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
import { Box, Group, Stack, Text } from '@mantine/core';
|
import { Box, Group, Stack, Text } from '@mantine/core';
|
||||||
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
import { useDebouncedValue, useDisclosure } from '@mantine/hooks';
|
||||||
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
import { useCommonHooks, useMutationAPI, useQueryAPI } from 'hooks';
|
||||||
import { useState } from 'react';
|
import { useEffect, useState } from 'react';
|
||||||
import { FiChevronRight } from 'react-icons/fi';
|
import { FiChevronRight } from 'react-icons/fi';
|
||||||
import { textClasses } from 'styles';
|
import { textClasses } from 'styles';
|
||||||
import type { ThemePlaylist } from 'types';
|
import type { ThemePlaylist } from 'types';
|
||||||
|
import NoItemsFound from '../Shared/NoItemsFound';
|
||||||
import SettingsHeader from '../Shared/SettingsHeader';
|
import SettingsHeader from '../Shared/SettingsHeader';
|
||||||
import ThemePlaylistCard from './ThemePlaylistCard';
|
import ThemePlaylistCard from './ThemePlaylistCard';
|
||||||
import ThemePlaylistModal from './ThemePlaylistModal';
|
import ThemePlaylistModal from './ThemePlaylistModal';
|
||||||
@@ -15,9 +16,10 @@ function ThemePlaylists() {
|
|||||||
endpoint: themesEndpoint,
|
endpoint: themesEndpoint,
|
||||||
});
|
});
|
||||||
const themePlaylistsEndpoint = 'api/themePlaylists';
|
const themePlaylistsEndpoint = 'api/themePlaylists';
|
||||||
const { data: themePlaylistData } = useQueryAPI({
|
const { data: themePlaylistData, isFetched: isThemePlaylistDataFetched } = useQueryAPI({
|
||||||
endpoint: themePlaylistsEndpoint,
|
endpoint: themePlaylistsEndpoint,
|
||||||
});
|
});
|
||||||
|
const [themePlaylists, setThemePlaylists] = useState<ThemePlaylist[]>([]);
|
||||||
const defaultPlaylist = {
|
const defaultPlaylist = {
|
||||||
id: undefined,
|
id: undefined,
|
||||||
default: 0,
|
default: 0,
|
||||||
@@ -31,6 +33,7 @@ function ThemePlaylists() {
|
|||||||
const { currentThemePlaylist, theme, isMobile } = useCommonHooks();
|
const { currentThemePlaylist, theme, isMobile } = useCommonHooks();
|
||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
const handleOpen = (playlist: ThemePlaylist) => {
|
const handleOpen = (playlist: ThemePlaylist) => {
|
||||||
setSelectedPlaylist(playlist);
|
setSelectedPlaylist(playlist);
|
||||||
@@ -51,6 +54,19 @@ function ThemePlaylists() {
|
|||||||
close();
|
close();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (themePlaylistData && isThemePlaylistDataFetched) {
|
||||||
|
setThemePlaylists(
|
||||||
|
themePlaylistData.filter((a: ThemePlaylist) =>
|
||||||
|
a.name.toLowerCase().includes(debouncedSearch.toLowerCase()),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (debouncedSearch === searchValue) {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
}, [themePlaylistData, isThemePlaylistDataFetched, debouncedSearch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack>
|
<Stack>
|
||||||
<ThemePlaylistModal
|
<ThemePlaylistModal
|
||||||
@@ -77,6 +93,8 @@ function ThemePlaylists() {
|
|||||||
searchValue={searchValue}
|
searchValue={searchValue}
|
||||||
setSearchValue={setSearchValue}
|
setSearchValue={setSearchValue}
|
||||||
searchPlaceholder={'Search Theme Playlists...'}
|
searchPlaceholder={'Search Theme Playlists...'}
|
||||||
|
isLoading={isLoading}
|
||||||
|
setIsLoading={setIsLoading}
|
||||||
/>
|
/>
|
||||||
<Group mt={'6rem'} justify='center' align='center' pos={'relative'}>
|
<Group mt={'6rem'} justify='center' align='center' pos={'relative'}>
|
||||||
<Text p={0} className={textClasses.settingsSubTitle} classNames={textClasses}>
|
<Text p={0} className={textClasses.settingsSubTitle} classNames={textClasses}>
|
||||||
@@ -84,11 +102,9 @@ function ThemePlaylists() {
|
|||||||
</Text>
|
</Text>
|
||||||
</Group>
|
</Group>
|
||||||
<Group justify='center' align='center' pos={'relative'}>
|
<Group justify='center' align='center' pos={'relative'}>
|
||||||
{themePlaylistData
|
{themePlaylists.length > 0 ? (
|
||||||
?.filter((playlist: ThemePlaylist) => playlist.default === 1)
|
themePlaylists
|
||||||
?.filter((a: ThemePlaylist) =>
|
.filter((playlist: ThemePlaylist) => playlist.default === 1)
|
||||||
a.name.toLowerCase().includes(debouncedSearch.toLowerCase()),
|
|
||||||
)
|
|
||||||
.map((cardPlaylist: ThemePlaylist) => {
|
.map((cardPlaylist: ThemePlaylist) => {
|
||||||
return (
|
return (
|
||||||
<Group key={cardPlaylist.name} pos={'relative'}>
|
<Group key={cardPlaylist.name} pos={'relative'}>
|
||||||
@@ -118,7 +134,12 @@ function ThemePlaylists() {
|
|||||||
</Box>
|
</Box>
|
||||||
</Group>
|
</Group>
|
||||||
);
|
);
|
||||||
})}
|
})
|
||||||
|
) : (
|
||||||
|
<Group w={'100%'} style={{ display: 'flex', justifyContent: 'center' }}>
|
||||||
|
<NoItemsFound />
|
||||||
|
</Group>
|
||||||
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
<Group justify='center' align='center' pos={'relative'}>
|
<Group justify='center' align='center' pos={'relative'}>
|
||||||
<Text p={0} className={textClasses.settingsSubTitle} classNames={textClasses}>
|
<Text p={0} className={textClasses.settingsSubTitle} classNames={textClasses}>
|
||||||
@@ -131,11 +152,9 @@ function ThemePlaylists() {
|
|||||||
pos={'relative'}
|
pos={'relative'}
|
||||||
mb={isMobile ? '6rem' : undefined}
|
mb={isMobile ? '6rem' : undefined}
|
||||||
>
|
>
|
||||||
{themePlaylistData
|
{themePlaylists.length > 0 ? (
|
||||||
?.filter((playlist: ThemePlaylist) => playlist.default === 0)
|
themePlaylists
|
||||||
?.filter((a: ThemePlaylist) =>
|
.filter((playlist: ThemePlaylist) => playlist.default === 0)
|
||||||
a.name.toLowerCase().includes(debouncedSearch.toLowerCase()),
|
|
||||||
)
|
|
||||||
.sort((a: ThemePlaylist, b: ThemePlaylist) => (a.name > b.name ? 1 : -1))
|
.sort((a: ThemePlaylist, b: ThemePlaylist) => (a.name > b.name ? 1 : -1))
|
||||||
.map((cardPlaylist: ThemePlaylist) => {
|
.map((cardPlaylist: ThemePlaylist) => {
|
||||||
return (
|
return (
|
||||||
@@ -166,7 +185,12 @@ function ThemePlaylists() {
|
|||||||
</Box>
|
</Box>
|
||||||
</Group>
|
</Group>
|
||||||
);
|
);
|
||||||
})}
|
})
|
||||||
|
) : (
|
||||||
|
<Group w={'100%'} style={{ display: 'flex', justifyContent: 'center' }}>
|
||||||
|
<NoItemsFound />
|
||||||
|
</Group>
|
||||||
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import { FaDice } from 'react-icons/fa';
|
|||||||
import { FiChevronRight } from 'react-icons/fi';
|
import { FiChevronRight } from 'react-icons/fi';
|
||||||
import { switchClasses } from 'styles';
|
import { switchClasses } from 'styles';
|
||||||
import type { Theme, ThemePlaylist } from 'types';
|
import type { Theme, ThemePlaylist } from 'types';
|
||||||
|
import NoItemsFound from '../Shared/NoItemsFound';
|
||||||
import SettingsHeader from '../Shared/SettingsHeader';
|
import SettingsHeader from '../Shared/SettingsHeader';
|
||||||
import ThemeCard from './ThemeCard';
|
import ThemeCard from './ThemeCard';
|
||||||
import ThemeModal from './ThemeModal';
|
import ThemeModal from './ThemeModal';
|
||||||
@@ -13,9 +14,10 @@ import ThemeModal from './ThemeModal';
|
|||||||
function ThemesSettings() {
|
function ThemesSettings() {
|
||||||
const themesEndpoint = 'api/themes';
|
const themesEndpoint = 'api/themes';
|
||||||
const backgroundsEndpoint = 'api/backgrounds';
|
const backgroundsEndpoint = 'api/backgrounds';
|
||||||
const { data: allThemeData } = useQueryAPI({
|
const { data: allThemeData, isFetched: isAllThemeDataFetched } = useQueryAPI({
|
||||||
endpoint: 'api/themes',
|
endpoint: 'api/themes',
|
||||||
});
|
});
|
||||||
|
const [allThemes, setAllThemes] = useState<Theme[]>([]);
|
||||||
const { data: backgroundData, isFetched: isBackgroundFetched } = useQueryAPI({
|
const { data: backgroundData, isFetched: isBackgroundFetched } = useQueryAPI({
|
||||||
endpoint: backgroundsEndpoint,
|
endpoint: backgroundsEndpoint,
|
||||||
});
|
});
|
||||||
@@ -42,6 +44,7 @@ function ThemesSettings() {
|
|||||||
const [pickerOpen, { open: openPicker, close: closePicker }] = useDisclosure(false);
|
const [pickerOpen, { open: openPicker, close: closePicker }] = useDisclosure(false);
|
||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
const { currentTheme, setCurrentTheme, theme, isMobile, setCurrentThemePlaylist } =
|
const { currentTheme, setCurrentTheme, theme, isMobile, setCurrentThemePlaylist } =
|
||||||
useCommonHooks();
|
useCommonHooks();
|
||||||
|
|
||||||
@@ -87,6 +90,19 @@ function ThemesSettings() {
|
|||||||
}
|
}
|
||||||
}, [themePlaylistData]);
|
}, [themePlaylistData]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (allThemeData && isAllThemeDataFetched) {
|
||||||
|
setAllThemes(
|
||||||
|
allThemeData.filter((a: Theme) =>
|
||||||
|
a.name.toLowerCase().includes(debouncedSearch.toLowerCase()),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (debouncedSearch === searchValue) {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
|
}, [allThemeData, isAllThemeDataFetched, debouncedSearch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Stack w={'100%'} align='center'>
|
<Stack w={'100%'} align='center'>
|
||||||
<ThemeModal
|
<ThemeModal
|
||||||
@@ -117,6 +133,8 @@ function ThemesSettings() {
|
|||||||
searchValue={searchValue}
|
searchValue={searchValue}
|
||||||
setSearchValue={setSearchValue}
|
setSearchValue={setSearchValue}
|
||||||
searchPlaceholder={'Search Themes...'}
|
searchPlaceholder={'Search Themes...'}
|
||||||
|
isLoading={isLoading}
|
||||||
|
setIsLoading={setIsLoading}
|
||||||
/>
|
/>
|
||||||
<Switch
|
<Switch
|
||||||
label={
|
label={
|
||||||
@@ -150,7 +168,7 @@ function ThemesSettings() {
|
|||||||
mb={isMobile ? '6rem' : '1rem'}
|
mb={isMobile ? '6rem' : '1rem'}
|
||||||
>
|
>
|
||||||
<Overlay
|
<Overlay
|
||||||
display={currentTheme === 'random' ? 'flex' : 'none'}
|
display={currentTheme === 'random' && debouncedSearch === '' ? 'flex' : 'none'}
|
||||||
blur={5}
|
blur={5}
|
||||||
style={{
|
style={{
|
||||||
zIndex: 190,
|
zIndex: 190,
|
||||||
@@ -161,11 +179,8 @@ function ThemesSettings() {
|
|||||||
}}
|
}}
|
||||||
pos={'absolute'}
|
pos={'absolute'}
|
||||||
/>
|
/>
|
||||||
{allThemeData
|
{allThemes.length > 0 ? (
|
||||||
?.filter((a: Theme) =>
|
allThemes.map((cardTheme: Theme) => (
|
||||||
a.name.toLowerCase().includes(debouncedSearch.toLowerCase()),
|
|
||||||
)
|
|
||||||
.map((cardTheme: Theme) => (
|
|
||||||
<Group key={cardTheme.name} pos={'relative'}>
|
<Group key={cardTheme.name} pos={'relative'}>
|
||||||
{cardTheme.name === currentTheme && (
|
{cardTheme.name === currentTheme && (
|
||||||
<FiChevronRight
|
<FiChevronRight
|
||||||
@@ -198,7 +213,15 @@ function ThemesSettings() {
|
|||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
</Group>
|
</Group>
|
||||||
))}
|
))
|
||||||
|
) : (
|
||||||
|
<Group
|
||||||
|
w={'100%'}
|
||||||
|
style={{ zIndex: 1000, display: 'flex', justifyContent: 'center' }}
|
||||||
|
>
|
||||||
|
<NoItemsFound />
|
||||||
|
</Group>
|
||||||
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
</Stack>
|
</Stack>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { useEffect, useState } from 'react';
|
|||||||
import { popoverClasses, textInputClasses } from 'styles';
|
import { popoverClasses, textInputClasses } from 'styles';
|
||||||
import type { WolClient } from 'types';
|
import type { WolClient } from 'types';
|
||||||
import AddItemModal from '../Shared/AddItemModal';
|
import AddItemModal from '../Shared/AddItemModal';
|
||||||
|
import NoItemsFound from '../Shared/NoItemsFound';
|
||||||
import SettingsHeader from '../Shared/SettingsHeader';
|
import SettingsHeader from '../Shared/SettingsHeader';
|
||||||
import DebouncedWolClient from './DebouncedWolClient';
|
import DebouncedWolClient from './DebouncedWolClient';
|
||||||
import WolClientSettingsItem from './WolClientSettingsItem';
|
import WolClientSettingsItem from './WolClientSettingsItem';
|
||||||
@@ -36,6 +37,7 @@ const WolClientSettings = () => {
|
|||||||
const [searchValue, setSearchValue] = useState('');
|
const [searchValue, setSearchValue] = useState('');
|
||||||
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
const [debouncedSearch] = useDebouncedValue(searchValue, 500);
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
|
||||||
const handleClose = () => {
|
const handleClose = () => {
|
||||||
setNewWolClient(defaultWolClient);
|
setNewWolClient(defaultWolClient);
|
||||||
@@ -50,6 +52,9 @@ const WolClientSettings = () => {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if (debouncedSearch === searchValue) {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
}, [wolClientsData, wolClientsIsFetched, debouncedSearch]);
|
}, [wolClientsData, wolClientsIsFetched, debouncedSearch]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@@ -131,6 +136,8 @@ const WolClientSettings = () => {
|
|||||||
searchValue={searchValue}
|
searchValue={searchValue}
|
||||||
setSearchValue={setSearchValue}
|
setSearchValue={setSearchValue}
|
||||||
searchPlaceholder={'Search Clients...'}
|
searchPlaceholder={'Search Clients...'}
|
||||||
|
isLoading={isLoading}
|
||||||
|
setIsLoading={setIsLoading}
|
||||||
/>
|
/>
|
||||||
<Stack
|
<Stack
|
||||||
mt={isMobile ? '9rem' : '6rem'}
|
mt={isMobile ? '9rem' : '6rem'}
|
||||||
@@ -139,7 +146,8 @@ const WolClientSettings = () => {
|
|||||||
align='center'
|
align='center'
|
||||||
>
|
>
|
||||||
<Grid columns={18} w={'75%'}>
|
<Grid columns={18} w={'75%'}>
|
||||||
{wolClients?.map((client: WolClient) => (
|
{wolClients.length > 0 ? (
|
||||||
|
wolClients?.map((client: WolClient) => (
|
||||||
<GridCol w={'100%'} span={isMobile ? 18 : 6} key={client.id}>
|
<GridCol w={'100%'} span={isMobile ? 18 : 6} key={client.id}>
|
||||||
<Popover
|
<Popover
|
||||||
withArrow
|
withArrow
|
||||||
@@ -162,7 +170,16 @@ const WolClientSettings = () => {
|
|||||||
</Popover.Dropdown>
|
</Popover.Dropdown>
|
||||||
</Popover>
|
</Popover>
|
||||||
</GridCol>
|
</GridCol>
|
||||||
))}
|
))
|
||||||
|
) : (
|
||||||
|
<GridCol
|
||||||
|
w={'100%'}
|
||||||
|
span={18}
|
||||||
|
style={{ display: 'flex', justifyContent: 'center' }}
|
||||||
|
>
|
||||||
|
<NoItemsFound />
|
||||||
|
</GridCol>
|
||||||
|
)}
|
||||||
</Grid>
|
</Grid>
|
||||||
</Stack>
|
</Stack>
|
||||||
</Stack>
|
</Stack>
|
||||||
|
|||||||
@@ -93,3 +93,36 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.loadingSpinner {
|
||||||
|
&.root {
|
||||||
|
transition: all .1s ease;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border-radius: 100%;
|
||||||
|
border: none;
|
||||||
|
background-color: transparent;
|
||||||
|
color: var(--mantine-color-primary-0);
|
||||||
|
.icon {
|
||||||
|
font-size: 24px;
|
||||||
|
}
|
||||||
|
.loader {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
:hover {
|
||||||
|
background-color: var(--mantine-color-primary-0) !important;
|
||||||
|
color: var(--mantine-color-accent-0) !important;
|
||||||
|
transition: all .1s ease;
|
||||||
|
}
|
||||||
|
animation: rotation 1s linear infinite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes rotation {
|
||||||
|
from {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.tableButton {
|
.newItemButton {
|
||||||
&.root {
|
&.root {
|
||||||
&.loader {
|
&.loader {
|
||||||
display: none;
|
display: none;
|
||||||
|
|||||||
Reference in New Issue
Block a user