feature: add status texts

This commit is contained in:
AzizbekFayziyev 2025-06-03 18:46:48 +05:00
parent 10043ca946
commit e4ad2c4066
11 changed files with 430 additions and 237 deletions

282
package-lock.json generated
View file

@ -40,14 +40,14 @@
"sequelize": "^6.37.3",
"socket.io": "^4.7.5",
"socket.io-client": "^4.7.5",
"tsx": "^4.19.0",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4",
"zano_ui": "file:./submodules/zano_ui"
},
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"nodemon": "^3.1.7"
"nodemon": "^3.1.7",
"tsx": "^4.19.4"
}
},
"node_modules/@aashutoshrathi/word-wrap": {
@ -2335,12 +2335,14 @@
}
},
"node_modules/@esbuild/aix-ppc64": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz",
"integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.5.tgz",
"integrity": "sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"aix"
@ -2350,12 +2352,14 @@
}
},
"node_modules/@esbuild/android-arm": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz",
"integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.5.tgz",
"integrity": "sha512-AdJKSPeEHgi7/ZhuIPtcQKr5RQdo6OO2IL87JkianiMYMPbCtot9fxPbrMiBADOWWm3T2si9stAiVsGbTQFkbA==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
@ -2365,12 +2369,14 @@
}
},
"node_modules/@esbuild/android-arm64": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz",
"integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.5.tgz",
"integrity": "sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
@ -2380,12 +2386,14 @@
}
},
"node_modules/@esbuild/android-x64": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz",
"integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.5.tgz",
"integrity": "sha512-D2GyJT1kjvO//drbRT3Hib9XPwQeWd9vZoBJn+bu/lVsOZ13cqNdDeqIF/xQ5/VmWvMduP6AmXvylO/PIc2isw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"android"
@ -2395,12 +2403,14 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz",
"integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.5.tgz",
"integrity": "sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
@ -2410,12 +2420,14 @@
}
},
"node_modules/@esbuild/darwin-x64": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz",
"integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.5.tgz",
"integrity": "sha512-1iT4FVL0dJ76/q1wd7XDsXrSW+oLoquptvh4CLR4kITDtqi2e/xwXwdCVH8hVHU43wgJdsq7Gxuzcs6Iq/7bxQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
@ -2425,12 +2437,14 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz",
"integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.5.tgz",
"integrity": "sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
@ -2440,12 +2454,14 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz",
"integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.5.tgz",
"integrity": "sha512-PrikaNjiXdR2laW6OIjlbeuCPrPaAl0IwPIaRv+SMV8CiM8i2LqVUHFC1+8eORgWyY7yhQY+2U2fA55mBzReaw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"freebsd"
@ -2455,12 +2471,14 @@
}
},
"node_modules/@esbuild/linux-arm": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz",
"integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.5.tgz",
"integrity": "sha512-cPzojwW2okgh7ZlRpcBEtsX7WBuqbLrNXqLU89GxWbNt6uIg78ET82qifUy3W6OVww6ZWobWub5oqZOVtwolfw==",
"cpu": [
"arm"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
@ -2470,12 +2488,14 @@
}
},
"node_modules/@esbuild/linux-arm64": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz",
"integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.5.tgz",
"integrity": "sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
@ -2485,12 +2505,14 @@
}
},
"node_modules/@esbuild/linux-ia32": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz",
"integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.5.tgz",
"integrity": "sha512-sQ7l00M8bSv36GLV95BVAdhJ2QsIbCuCjh/uYrWiMQSUuV+LpXwIqhgJDcvMTj+VsQmqAHL2yYaasENvJ7CDKA==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
@ -2500,12 +2522,14 @@
}
},
"node_modules/@esbuild/linux-loong64": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz",
"integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.5.tgz",
"integrity": "sha512-0ur7ae16hDUC4OL5iEnDb0tZHDxYmuQyhKhsPBV8f99f6Z9KQM02g33f93rNH5A30agMS46u2HP6qTdEt6Q1kg==",
"cpu": [
"loong64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
@ -2515,12 +2539,14 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz",
"integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.5.tgz",
"integrity": "sha512-kB/66P1OsHO5zLz0i6X0RxlQ+3cu0mkxS3TKFvkb5lin6uwZ/ttOkP3Z8lfR9mJOBk14ZwZ9182SIIWFGNmqmg==",
"cpu": [
"mips64el"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
@ -2530,12 +2556,14 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz",
"integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.5.tgz",
"integrity": "sha512-UZCmJ7r9X2fe2D6jBmkLBMQetXPXIsZjQJCjgwpVDz+YMcS6oFR27alkgGv3Oqkv07bxdvw7fyB71/olceJhkQ==",
"cpu": [
"ppc64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
@ -2545,12 +2573,14 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz",
"integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.5.tgz",
"integrity": "sha512-kTxwu4mLyeOlsVIFPfQo+fQJAV9mh24xL+y+Bm6ej067sYANjyEw1dNHmvoqxJUCMnkBdKpvOn0Ahql6+4VyeA==",
"cpu": [
"riscv64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
@ -2560,12 +2590,14 @@
}
},
"node_modules/@esbuild/linux-s390x": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz",
"integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.5.tgz",
"integrity": "sha512-K2dSKTKfmdh78uJ3NcWFiqyRrimfdinS5ErLSn3vluHNeHVnBAFWC8a4X5N+7FgVE1EjXS1QDZbpqZBjfrqMTQ==",
"cpu": [
"s390x"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
@ -2575,12 +2607,14 @@
}
},
"node_modules/@esbuild/linux-x64": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz",
"integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.5.tgz",
"integrity": "sha512-uhj8N2obKTE6pSZ+aMUbqq+1nXxNjZIIjCjGLfsWvVpy7gKCOL6rsY1MhRh9zLtUtAI7vpgLMK6DxjO8Qm9lJw==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"linux"
@ -2589,13 +2623,32 @@
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-arm64": {
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.5.tgz",
"integrity": "sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
],
"engines": {
"node": ">=18"
}
},
"node_modules/@esbuild/netbsd-x64": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz",
"integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.5.tgz",
"integrity": "sha512-WOb5fKrvVTRMfWFNCroYWWklbnXH0Q5rZppjq0vQIdlsQKuw6mdSihwSo4RV/YdQ5UCKKvBy7/0ZZYLBZKIbwQ==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"netbsd"
@ -2605,12 +2658,14 @@
}
},
"node_modules/@esbuild/openbsd-arm64": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz",
"integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.5.tgz",
"integrity": "sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
@ -2620,12 +2675,14 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz",
"integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.5.tgz",
"integrity": "sha512-G4hE405ErTWraiZ8UiSoesH8DaCsMm0Cay4fsFWOOUcz8b8rC6uCvnagr+gnioEjWn0wC+o1/TAHt+It+MpIMg==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"openbsd"
@ -2635,12 +2692,14 @@
}
},
"node_modules/@esbuild/sunos-x64": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz",
"integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.5.tgz",
"integrity": "sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"sunos"
@ -2650,12 +2709,14 @@
}
},
"node_modules/@esbuild/win32-arm64": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz",
"integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.5.tgz",
"integrity": "sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==",
"cpu": [
"arm64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
@ -2665,12 +2726,14 @@
}
},
"node_modules/@esbuild/win32-ia32": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz",
"integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.5.tgz",
"integrity": "sha512-onOJ02pqs9h1iMJ1PQphR+VZv8qBMQ77Klcsqv9CNW2w6yLqoURLcgERAIurY6QE63bbLuqgP9ATqajFLK5AMQ==",
"cpu": [
"ia32"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
@ -2680,12 +2743,14 @@
}
},
"node_modules/@esbuild/win32-x64": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz",
"integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.5.tgz",
"integrity": "sha512-TXv6YnJ8ZMVdX+SXWVBo/0p8LTcrUYngpWjvm91TMjjBQii7Oz11Lw5lbDV5Y0TzuhSJHwiH4hEtC1I42mMS0g==",
"cpu": [
"x64"
],
"dev": true,
"license": "MIT",
"optional": true,
"os": [
"win32"
@ -10212,10 +10277,12 @@
}
},
"node_modules/esbuild": {
"version": "0.23.1",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz",
"integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==",
"version": "0.25.5",
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.5.tgz",
"integrity": "sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"bin": {
"esbuild": "bin/esbuild"
},
@ -10223,30 +10290,31 @@
"node": ">=18"
},
"optionalDependencies": {
"@esbuild/aix-ppc64": "0.23.1",
"@esbuild/android-arm": "0.23.1",
"@esbuild/android-arm64": "0.23.1",
"@esbuild/android-x64": "0.23.1",
"@esbuild/darwin-arm64": "0.23.1",
"@esbuild/darwin-x64": "0.23.1",
"@esbuild/freebsd-arm64": "0.23.1",
"@esbuild/freebsd-x64": "0.23.1",
"@esbuild/linux-arm": "0.23.1",
"@esbuild/linux-arm64": "0.23.1",
"@esbuild/linux-ia32": "0.23.1",
"@esbuild/linux-loong64": "0.23.1",
"@esbuild/linux-mips64el": "0.23.1",
"@esbuild/linux-ppc64": "0.23.1",
"@esbuild/linux-riscv64": "0.23.1",
"@esbuild/linux-s390x": "0.23.1",
"@esbuild/linux-x64": "0.23.1",
"@esbuild/netbsd-x64": "0.23.1",
"@esbuild/openbsd-arm64": "0.23.1",
"@esbuild/openbsd-x64": "0.23.1",
"@esbuild/sunos-x64": "0.23.1",
"@esbuild/win32-arm64": "0.23.1",
"@esbuild/win32-ia32": "0.23.1",
"@esbuild/win32-x64": "0.23.1"
"@esbuild/aix-ppc64": "0.25.5",
"@esbuild/android-arm": "0.25.5",
"@esbuild/android-arm64": "0.25.5",
"@esbuild/android-x64": "0.25.5",
"@esbuild/darwin-arm64": "0.25.5",
"@esbuild/darwin-x64": "0.25.5",
"@esbuild/freebsd-arm64": "0.25.5",
"@esbuild/freebsd-x64": "0.25.5",
"@esbuild/linux-arm": "0.25.5",
"@esbuild/linux-arm64": "0.25.5",
"@esbuild/linux-ia32": "0.25.5",
"@esbuild/linux-loong64": "0.25.5",
"@esbuild/linux-mips64el": "0.25.5",
"@esbuild/linux-ppc64": "0.25.5",
"@esbuild/linux-riscv64": "0.25.5",
"@esbuild/linux-s390x": "0.25.5",
"@esbuild/linux-x64": "0.25.5",
"@esbuild/netbsd-arm64": "0.25.5",
"@esbuild/netbsd-x64": "0.25.5",
"@esbuild/openbsd-arm64": "0.25.5",
"@esbuild/openbsd-x64": "0.25.5",
"@esbuild/sunos-x64": "0.25.5",
"@esbuild/win32-arm64": "0.25.5",
"@esbuild/win32-ia32": "0.25.5",
"@esbuild/win32-x64": "0.25.5"
}
},
"node_modules/escalade": {
@ -12128,6 +12196,7 @@
"version": "4.7.6",
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.6.tgz",
"integrity": "sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA==",
"dev": true,
"dependencies": {
"resolve-pkg-maps": "^1.0.0"
},
@ -19775,6 +19844,7 @@
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz",
"integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==",
"dev": true,
"funding": {
"url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1"
}
@ -22247,11 +22317,13 @@
"integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg=="
},
"node_modules/tsx": {
"version": "4.19.0",
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.0.tgz",
"integrity": "sha512-bV30kM7bsLZKZIOCHeMNVMJ32/LuJzLVajkQI/qf92J2Qr08ueLQvW00PUZGiuLPP760UINwupgUj8qrSCPUKg==",
"version": "4.19.4",
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.4.tgz",
"integrity": "sha512-gK5GVzDkJK1SI1zwHf32Mqxf2tSJkNx+eYcNly5+nHvWqXUJYUkWBQtKauoESz3ymezAI++ZwT855x5p5eop+Q==",
"dev": true,
"license": "MIT",
"dependencies": {
"esbuild": "~0.23.0",
"esbuild": "~0.25.0",
"get-tsconfig": "^4.7.5"
},
"bin": {

View file

@ -36,7 +36,6 @@
"sequelize": "^6.37.3",
"socket.io": "^4.7.5",
"socket.io-client": "^4.7.5",
"tsx": "^4.19.0",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4",
"zano_ui": "file:./submodules/zano_ui"
@ -68,6 +67,7 @@
},
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "^7.21.11",
"nodemon": "^3.1.7"
"nodemon": "^3.1.7",
"tsx": "^4.19.4"
}
}

View file

@ -0,0 +1,10 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_724_744)">
<path d="M8.0002 10.7503C8.67069 10.7503 9.2157 11.2943 9.21464 11.966C9.21464 12.6368 8.67073 13.1793 8.0002 13.1793C7.32942 13.1793 6.78575 12.6365 6.78575 11.966C6.78575 11.2955 7.32942 10.7517 8.0002 10.7503ZM7.48831 2.82035H8.51314C8.99405 2.82035 9.38122 3.26696 9.38122 3.82193L9.07662 8.74167C9.07662 9.29651 8.68839 9.74325 8.00005 9.74325C7.31172 9.74325 6.92454 9.29665 6.92454 8.74167L6.61994 3.82193C6.62034 3.26723 7.00753 2.82035 7.48831 2.82035ZM8.0002 0.400513C3.80341 0.400513 0.400024 3.8025 0.400024 8.00068C0.400024 12.1975 3.80283 15.5995 8.0002 15.5995C12.197 15.6008 15.6 12.1975 15.6 8.00068C15.6 3.80253 12.1972 0.400513 8.0002 0.400513Z" fill="#9EAACC"/>
</g>
<defs>
<clipPath id="clip0_724_744">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 927 B

View file

@ -3,8 +3,22 @@
border-radius: 10px;
overflow: hidden;
h3 {
&__title {
padding: 18px 20px;
display: flex;
gap: 20px;
.status__badge {
background-color: #091233;
padding: 6px;
padding-right: 12px;
border-radius: 20px;
display: flex;
align-items: center;
gap: 6px;
font-size: 14px;
font-weight: 400;
}
}
@media screen and (max-width: 761px) {

View file

@ -3,11 +3,12 @@ import Table from "@/components/default/Table/Table";
import Block from "@/interfaces/state/Block";
import Info from "@/interfaces/state/Info";
import Fetch from "@/utils/methods";
import Utils from "@/utils/utils";
import Utils, { classes } from "@/utils/utils";
import styles from "./LatestBlocks.module.scss";
import { useState, useEffect } from "react";
import { useState, useEffect, useRef } from "react";
import Link from "next/link";
import BigNumber from "bignumber.js";
import InfoIcon from "@/assets/images/UI/info.svg";
export const latestBlocksInitState = {
itemsInPage: 10,
@ -15,8 +16,9 @@ export const latestBlocksInitState = {
}
function LatestBlocks({ fetchedInfo, fetchedLatestBlocks }: { fetchedInfo: Info | null, fetchedLatestBlocks: Block[] }) {
const [info, setInfo] = useState<Info | null>(fetchedInfo);
const prevTxCount = useRef<number>(0);
const [headerStatus, setHeaderStatus] = useState<JSX.Element | null>(null);
useEffect(() => {
async function fetchInfo() {
@ -63,31 +65,53 @@ function LatestBlocks({ fetchedInfo, fetchedLatestBlocks }: { fetchedInfo: Info
onGoToBlockEnter();
}, [goToBlock, info, itemsOnPage]);
useEffect(() => {
async function fetchBlocks() {
const items = parseInt(itemsOnPage, 10) || 0;
const pageNumber = parseInt(page, 10) || 0;
if (pageNumber === 0) return;
if (!info) return;
const { height, database_height } = info;
try {
setHeaderStatus(<>Scanning new transactions...</>);
const heightToRequest = Math.min(height, database_height);
const result = await Fetch.getBlockDetails(heightToRequest - items * pageNumber, items);
if (result.success === false) return;
if (!(result instanceof Array)) return;
setBlocks(
Utils.transformToBlocks(result, true)
);
const items = parseInt(itemsOnPage, 10) || 0;
const pageNumber = parseInt(page, 10) || 0;
if (pageNumber === 0 || !info) return;
const { height, database_height } = info;
const heightToRequest = Math.min(height, database_height);
const result = await Fetch.getBlockDetails(heightToRequest - items * pageNumber, items);
if (result.success === false || !(result instanceof Array)) return;
const transformed = Utils.transformToBlocks(result, true);
const currentTxCount = transformed.reduce((acc, block) => acc + (block.transactions || 0), 0);
const prevCount = prevTxCount.current;
prevTxCount.current = currentTxCount;
setBlocks(transformed);
if (currentTxCount > prevCount) {
const diff = currentTxCount - prevCount;
setHeaderStatus(
<>
<span>{diff} more transaction{diff > 1 ? "s" : ""}</span> has come in
</>
);
} else {
setHeaderStatus(null);
}
} catch (error) {
console.error(error);
setHeaderStatus(null);
}
}
fetchBlocks();
const id = setInterval(fetchBlocks, 20 * 1e3);
const id = setInterval(fetchBlocks, 20 * 1000);
return () => clearInterval(id);
}, [info, itemsOnPage, page]);
const tableHeaders = [ "HEIGHT", "TIMESTAMP (UTC)", "AGE", "SIZE", "TRANSACTIONS", "HASH" ];
const tableHeaders = ["HEIGHT", "TIMESTAMP (UTC)", "AGE", "SIZE", "TRANSACTIONS", "HASH"];
const tableElements = blocks.map(e => {
const hash = e.hash;
@ -106,12 +130,16 @@ function LatestBlocks({ fetchedInfo, fetchedLatestBlocks }: { fetchedInfo: Info
});
return (
<div className={styles["blockchain__latest_blocks"] + " " + styles["custom-scroll"]}>
<h3>Latest Blocks</h3>
<Table
<div className={classes(styles["blockchain__latest_blocks"], styles["custom-scroll"])}>
<h3 className={styles["blockchain__latest_blocks__title"]}>
Latest Blocks <span className={styles["status__badge"]}><InfoIcon /> Last updated 26 mins ago</span>
</h3>
<Table
headerStatus={headerStatus}
pagination
headers={tableHeaders}
elements={tableElements}
headers={tableHeaders}
elements={tableElements}
itemsOnPage={itemsOnPage}
setItemsOnPage={setItemsOnPage}
page={page}
@ -119,7 +147,7 @@ function LatestBlocks({ fetchedInfo, fetchedLatestBlocks }: { fetchedInfo: Info
goToBlock={goToBlock}
setGoToBlock={setGoToBlock}
pagesTotal={pagesAmount}
// goToBlockEnter={onGoToBlockEnter}
// goToBlockEnter={onGoToBlockEnter}
/>
</div>
)

View file

@ -4,18 +4,35 @@
border-spacing: 0;
overflow-x: hidden;
p, a {
&__info_status {
background: #5D31C8;
th {
color: #FFFFFF !important;
text-transform: none !important;
font-weight: 600;
font-size: 14px;
text-align-last: left;
span {
color: #68A1FF;
}
}
}
p,
a {
font-size: 13px;
}
&.table__text_nowrap {
> * {
>* {
white-space: nowrap;
}
}
tr {
> * {
>* {
padding: 12px 20px;
@media screen and (max-width: 1170px) {
@ -33,7 +50,7 @@
}
thead {
background: linear-gradient(to right,#1b3a8a,#32439f);
background: linear-gradient(to right, #1b3a8a, #32439f);
th {
font-size: 14px;
@ -79,7 +96,7 @@
align-items: center;
gap: 12px;
> div {
>div {
display: flex;
button {
@ -90,7 +107,7 @@
justify-content: center;
align-items: center;
&:first-child > svg {
&:first-child>svg {
transform: rotateY(180deg);
}
@ -105,19 +122,19 @@
display: flex;
gap: 29px;
> div {
>div {
display: flex;
align-items: center;
gap: 8px;
&:last-child input {
max-width: 90px;
max-width: 90px;
}
}
}
}
.preloader{
.preloader {
margin: 20px 0;
display: grid;
place-content: center;

View file

@ -1,7 +1,8 @@
import { Dispatch, SetStateAction } from "react";
import { Dispatch, ReactNode, SetStateAction } from "react";
interface TableProps {
headers: string[];
headerStatus?: ReactNode | null;
elements: React.ReactNode[][];
pagination?: boolean;
hidePaginationBlock?: boolean;

View file

@ -5,7 +5,7 @@ import Input from "../../UI/Input/Input";
import TableProps from "./Table.props";
import Preloader from "@/components/UI/Preloader/Preloader";
function Table(props: TableProps) {
function Table(props: TableProps) {
function onNumberInput(event: React.FormEvent<HTMLInputElement>, setState?: React.Dispatch<React.SetStateAction<string>>, max?: number) {
if (!setState) return;
const newValue = event.currentTarget.value;
@ -17,15 +17,16 @@ function Table(props: TableProps) {
setState(newValue);
}
const {
headers,
elements,
pagination,
className,
hidePaginationBlock,
itemsOnPage,
setItemsOnPage,
page,
const {
headers,
headerStatus,
elements,
pagination,
className,
hidePaginationBlock,
itemsOnPage,
setItemsOnPage,
page,
setPage,
goToBlock,
setGoToBlock,
@ -46,87 +47,90 @@ function Table(props: TableProps) {
<div className={className}>
{!isLoading ? <>
<table className={`${styles.table} ${!textWrap ? styles["table__text_nowrap"] : ""}`}>
<thead>
<tr>
{
headers.map(e => <th key={nanoid(16)}>{e}</th>)
}
</tr>
</thead>
<tbody>
{elements.map(row =>
<tr key={nanoid(16)}>
<thead>
<tr>
{
row.map((e, i) =>
<td
style={columnsWidth ? { width: `${columnsWidth[i]}%` } : undefined}
key={nanoid(16)}
>
{e}
</td>
)
headers.map(e => <th key={nanoid(16)}>{e}</th>)
}
</tr>
)}
</tbody>
</table>
<Pagination pagination={pagination}/>
{headerStatus && <tr className={styles.table__info_status}>
<th colSpan={headers.length}>{headerStatus}</th>
</tr>}
</thead>
<tbody>
{elements.map(row =>
<tr key={nanoid(16)}>
{
row.map((e, i) =>
<td
style={columnsWidth ? { width: `${columnsWidth[i]}%` } : undefined}
key={nanoid(16)}
>
{e}
</td>
)
}
</tr>
)}
</tbody>
</table>
<Pagination pagination={pagination} />
</> : <div className={styles.preloader}>
<Preloader/>
</div>}
<Preloader />
</div>}
</div>
)
function Pagination ({pagination}:{pagination:boolean | undefined}) {
function Pagination({ pagination }: { pagination: boolean | undefined }) {
if (!pagination) return null
return <div className={styles["table__pagination"]}>
<div className={styles["table__pagination__pages"]}>
<p>Pages: </p>
<div>
<button
className={page === "1" ? styles.disabled : undefined}
onClick={() => changePage(-1)}
>
<ArrowImg />
</button>
<button
onClick={() => changePage(1)}
>
<ArrowImg />
</button>
</div>
<Input
type="text"
value={page}
onInput={(e) => onNumberInput(e, setPage)}
/>
</div>
{pagesTotal && <p>Pages total: {pagesTotal}</p>}
<div className={styles["table__pagination__blocks"]}>
<div>
<p>Items on page: </p>
<Input
type="text"
value={itemsOnPage}
onInput={(e) => onNumberInput(e, setItemsOnPage, 50)}
return <div className={styles["table__pagination"]}>
<div className={styles["table__pagination__pages"]}>
<p>Pages: </p>
<div>
<button
className={page === "1" ? styles.disabled : undefined}
onClick={() => changePage(-1)}
>
<ArrowImg />
</button>
<button
onClick={() => changePage(1)}
>
<ArrowImg />
</button>
</div>
<Input
type="text"
value={page}
onInput={(e) => onNumberInput(e, setPage)}
/>
</div>
{!hidePaginationBlock &&
{pagesTotal && <p>Pages total: {pagesTotal}</p>}
<div className={styles["table__pagination__blocks"]}>
<div>
<p>Go to block: </p>
<p>Items on page: </p>
<Input
type="text"
placeholder="number"
value={goToBlock}
onInput={(e) => onNumberInput(e, setGoToBlock)}
onEnterPress={goToBlockEnter}
type="text"
value={itemsOnPage}
onInput={(e) => onNumberInput(e, setItemsOnPage, 50)}
/>
</div>
}
{!hidePaginationBlock &&
<div>
<p>Go to block: </p>
<Input
type="text"
placeholder="number"
value={goToBlock}
onInput={(e) => onNumberInput(e, setGoToBlock)}
onEnterPress={goToBlockEnter}
/>
</div>
}
</div>
</div>
</div>
}
}

View file

@ -7,4 +7,6 @@ interface Block {
hash: string;
}
export type ExplorerStatusType = "online" | "offline" | "syncing";
export default Block;

View file

@ -8,9 +8,10 @@ import { useEffect, useState } from "react";
import Fetch from "@/utils/methods";
import VisibilityInfo from "@/interfaces/state/VisibilityInfo";
import Info from "@/interfaces/state/Info";
import Block from "@/interfaces/state/Block";
import Block, { ExplorerStatusType } from "@/interfaces/state/Block";
import { GetServerSideProps } from "next";
import { getMainPageProps } from "@/utils/ssr";
import { classes } from "@/utils/utils";
export interface MainPageProps {
visibilityInfo: VisibilityInfo | null;
isOnline: boolean;
@ -23,7 +24,7 @@ function MainPage({ visibilityInfo: fetchedVisibilityInfo, isOnline: fetchedIsOn
const [burgerOpened, setBurgerOpened] = useState(false);
const [visibilityInfo, setVisibilityInfo] = useState<VisibilityInfo | null>(fetchedVisibilityInfo);
const [isOnline, setIsOnline] = useState(fetchedIsOnline);
const [explorerStatus, setExplorerStatus] = useState<ExplorerStatusType>(fetchedIsOnline ? "online" : "offline");
useEffect(() => {
async function fetchVisibilityInfo() {
@ -33,16 +34,18 @@ function MainPage({ visibilityInfo: fetchedVisibilityInfo, isOnline: fetchedIsOn
}
async function checkOnline() {
try {
setExplorerStatus("syncing");
const result = await Fetch.getInfo();
if (result.status === "OK") {
setIsOnline(true);
setExplorerStatus("online");
} else {
setIsOnline(false);
setExplorerStatus("offline");
}
} catch (error) {
console.log(error);
setIsOnline(false);
setExplorerStatus("offline");
}
}
@ -53,19 +56,23 @@ function MainPage({ visibilityInfo: fetchedVisibilityInfo, isOnline: fetchedIsOn
return (
<div className={styles["blockchain"]}>
<Header
page="Blockchain"
burgerOpened={burgerOpened}
setBurgerOpened={setBurgerOpened}
<Header
page="Blockchain"
burgerOpened={burgerOpened}
setBurgerOpened={setBurgerOpened}
/>
<InfoTopPanel
burgerOpened={burgerOpened}
title="Blockchain"
<InfoTopPanel
burgerOpened={burgerOpened}
title="Blockchain"
content={
<div className={styles["info__top__daemon"]}>
<p>Daemon state: {isOnline ? 'Online' : 'Offline'}</p>
<p>Default network fee: 0,01</p>
<p>Minimum network fee: 0,01</p>
<p className={styles["info__top__daemon_item"]}>Explorer state:
<span className={classes(styles["explorer__status"], styles[explorerStatus])}>
<span className={styles["status__item"]} /> {explorerStatus}
</span>
</p>
<p className={styles["info__top__daemon_item"]}>Default network fee: 0,01</p>
<p className={styles["info__top__daemon_item"]}>Minimum network fee: 0,01</p>
</div>
}
/>

View file

@ -6,14 +6,52 @@
.info__top__daemon {
display: flex;
gap: 25px;
> p {
&_item {
font-size: 14px;
color: #9eaacc;
display: flex;
align-items: center;
gap: 8px;
.explorer__status {
background: linear-gradient(90deg, #0C153A 0%, #091233 100%);
padding: 4px 8px;
border-radius: 50px;
font-size: 12px;
font-weight: 400;
display: flex;
align-items: center;
gap: 5px;
&.offline {
.status__item {
background-color: #FF6767;
}
}
&.online {
.status__item {
background-color: #47EFFB;
}
}
&.syncing {
.status__item {
background-color: #E6C54E;
}
}
.status__item {
width: 8px;
height: 8px;
border-radius: 50%;
}
}
}
@media screen and (max-width: 991px) {
> p:not(:first-child) {
>p:not(:first-child) {
display: none;
}
}