updated admin and user and res code
This commit is contained in:
parent
81ee2290de
commit
3554698475
226
package-lock.json
generated
226
package-lock.json
generated
@ -13,11 +13,15 @@
|
|||||||
"@testing-library/react": "^16.2.0",
|
"@testing-library/react": "^16.2.0",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
"axios": "^1.8.3",
|
"axios": "^1.8.3",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"http": "^0.0.1-security",
|
||||||
|
"jsonwebtoken": "^9.0.2",
|
||||||
"lucide-react": "^0.479.0",
|
"lucide-react": "^0.479.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-router-dom": "^7.3.0",
|
"react-router-dom": "^7.3.0",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
|
"sanitize-html": "^2.14.0",
|
||||||
"socket.io-client": "^4.8.1",
|
"socket.io-client": "^4.8.1",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
},
|
},
|
||||||
@ -4585,6 +4589,7 @@
|
|||||||
"version": "1.8.3",
|
"version": "1.8.3",
|
||||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.3.tgz",
|
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.3.tgz",
|
||||||
"integrity": "sha512-iP4DebzoNlP/YN2dpwCgb8zoCmhtkajzS48JvwmkSkXvPI3DHc7m+XYL5tGnSlJtR6nImXZmdCuN5aP8dh1d8A==",
|
"integrity": "sha512-iP4DebzoNlP/YN2dpwCgb8zoCmhtkajzS48JvwmkSkXvPI3DHc7m+XYL5tGnSlJtR6nImXZmdCuN5aP8dh1d8A==",
|
||||||
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"follow-redirects": "^1.15.6",
|
"follow-redirects": "^1.15.6",
|
||||||
"form-data": "^4.0.0",
|
"form-data": "^4.0.0",
|
||||||
@ -5160,6 +5165,12 @@
|
|||||||
"node-int64": "^0.4.0"
|
"node-int64": "^0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/buffer-equal-constant-time": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==",
|
||||||
|
"license": "BSD-3-Clause"
|
||||||
|
},
|
||||||
"node_modules/buffer-from": {
|
"node_modules/buffer-from": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
|
||||||
@ -5727,6 +5738,19 @@
|
|||||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/cors": {
|
||||||
|
"version": "2.8.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
|
||||||
|
"integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"object-assign": "^4",
|
||||||
|
"vary": "^1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.10"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/cosmiconfig": {
|
"node_modules/cosmiconfig": {
|
||||||
"version": "7.1.0",
|
"version": "7.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
|
||||||
@ -6620,6 +6644,15 @@
|
|||||||
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz",
|
||||||
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
|
"integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA=="
|
||||||
},
|
},
|
||||||
|
"node_modules/ecdsa-sig-formatter": {
|
||||||
|
"version": "1.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz",
|
||||||
|
"integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==",
|
||||||
|
"license": "Apache-2.0",
|
||||||
|
"dependencies": {
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/ee-first": {
|
"node_modules/ee-first": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||||
@ -8769,6 +8802,11 @@
|
|||||||
"entities": "^2.0.0"
|
"entities": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/http": {
|
||||||
|
"version": "0.0.1-security",
|
||||||
|
"resolved": "https://registry.npmjs.org/http/-/http-0.0.1-security.tgz",
|
||||||
|
"integrity": "sha512-RnDvP10Ty9FxqOtPZuxtebw1j4L/WiqNMDtuc1YMH1XQm5TgDRaR1G9u8upL6KD1bXHSp9eSXo/ED+8Q7FAr+g=="
|
||||||
|
},
|
||||||
"node_modules/http-deceiver": {
|
"node_modules/http-deceiver": {
|
||||||
"version": "1.2.7",
|
"version": "1.2.7",
|
||||||
"resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
|
"resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz",
|
||||||
@ -9319,6 +9357,15 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-plain-object": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-potential-custom-element-name": {
|
"node_modules/is-potential-custom-element-name": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
|
||||||
@ -10645,6 +10692,28 @@
|
|||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jsonwebtoken": {
|
||||||
|
"version": "9.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
|
||||||
|
"integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"jws": "^3.2.2",
|
||||||
|
"lodash.includes": "^4.3.0",
|
||||||
|
"lodash.isboolean": "^3.0.3",
|
||||||
|
"lodash.isinteger": "^4.0.4",
|
||||||
|
"lodash.isnumber": "^3.0.3",
|
||||||
|
"lodash.isplainobject": "^4.0.6",
|
||||||
|
"lodash.isstring": "^4.0.1",
|
||||||
|
"lodash.once": "^4.0.0",
|
||||||
|
"ms": "^2.1.1",
|
||||||
|
"semver": "^7.5.4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=12",
|
||||||
|
"npm": ">=6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/jsx-ast-utils": {
|
"node_modules/jsx-ast-utils": {
|
||||||
"version": "3.3.5",
|
"version": "3.3.5",
|
||||||
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
|
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz",
|
||||||
@ -10659,6 +10728,27 @@
|
|||||||
"node": ">=4.0"
|
"node": ">=4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/jwa": {
|
||||||
|
"version": "1.4.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz",
|
||||||
|
"integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"buffer-equal-constant-time": "1.0.1",
|
||||||
|
"ecdsa-sig-formatter": "1.0.11",
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/jws": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
|
||||||
|
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"jwa": "^1.4.1",
|
||||||
|
"safe-buffer": "^5.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/keyv": {
|
"node_modules/keyv": {
|
||||||
"version": "4.5.4",
|
"version": "4.5.4",
|
||||||
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
|
||||||
@ -10791,6 +10881,42 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
|
||||||
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
|
"integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow=="
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.includes": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isboolean": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isinteger": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isnumber": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isplainobject": {
|
||||||
|
"version": "4.0.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||||
|
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/lodash.isstring": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/lodash.memoize": {
|
"node_modules/lodash.memoize": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
|
||||||
@ -10801,6 +10927,12 @@
|
|||||||
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz",
|
||||||
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
|
"integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="
|
||||||
},
|
},
|
||||||
|
"node_modules/lodash.once": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||||
|
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/lodash.sortby": {
|
"node_modules/lodash.sortby": {
|
||||||
"version": "4.7.0",
|
"version": "4.7.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
|
||||||
@ -11595,6 +11727,12 @@
|
|||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"url": "https://github.com/sponsors/sindresorhus"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/parse-srcset": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/parse-srcset/-/parse-srcset-1.0.2.tgz",
|
||||||
|
"integrity": "sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/parse5": {
|
"node_modules/parse5": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
|
||||||
@ -14078,6 +14216,94 @@
|
|||||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||||
},
|
},
|
||||||
|
"node_modules/sanitize-html": {
|
||||||
|
"version": "2.14.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/sanitize-html/-/sanitize-html-2.14.0.tgz",
|
||||||
|
"integrity": "sha512-CafX+IUPxZshXqqRaG9ZClSlfPVjSxI0td7n07hk8QO2oO+9JDnlcL8iM8TWeOXOIBFgIOx6zioTzM53AOMn3g==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"deepmerge": "^4.2.2",
|
||||||
|
"escape-string-regexp": "^4.0.0",
|
||||||
|
"htmlparser2": "^8.0.0",
|
||||||
|
"is-plain-object": "^5.0.0",
|
||||||
|
"parse-srcset": "^1.0.2",
|
||||||
|
"postcss": "^8.3.11"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sanitize-html/node_modules/dom-serializer": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": "^2.3.0",
|
||||||
|
"domhandler": "^5.0.2",
|
||||||
|
"entities": "^4.2.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/cheeriojs/dom-serializer?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sanitize-html/node_modules/domhandler": {
|
||||||
|
"version": "5.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz",
|
||||||
|
"integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": "^2.3.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/domhandler?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sanitize-html/node_modules/domutils": {
|
||||||
|
"version": "3.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz",
|
||||||
|
"integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"dependencies": {
|
||||||
|
"dom-serializer": "^2.0.0",
|
||||||
|
"domelementtype": "^2.3.0",
|
||||||
|
"domhandler": "^5.0.3"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/domutils?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sanitize-html/node_modules/entities": {
|
||||||
|
"version": "4.5.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
|
||||||
|
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
|
||||||
|
"license": "BSD-2-Clause",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.12"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/sanitize-html/node_modules/htmlparser2": {
|
||||||
|
"version": "8.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz",
|
||||||
|
"integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==",
|
||||||
|
"funding": [
|
||||||
|
"https://github.com/fb55/htmlparser2?sponsor=1",
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/fb55"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"domelementtype": "^2.3.0",
|
||||||
|
"domhandler": "^5.0.3",
|
||||||
|
"domutils": "^3.0.1",
|
||||||
|
"entities": "^4.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/sanitize.css": {
|
"node_modules/sanitize.css": {
|
||||||
"version": "13.0.0",
|
"version": "13.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/sanitize.css/-/sanitize.css-13.0.0.tgz",
|
||||||
|
|||||||
@ -8,11 +8,15 @@
|
|||||||
"@testing-library/react": "^16.2.0",
|
"@testing-library/react": "^16.2.0",
|
||||||
"@testing-library/user-event": "^13.5.0",
|
"@testing-library/user-event": "^13.5.0",
|
||||||
"axios": "^1.8.3",
|
"axios": "^1.8.3",
|
||||||
|
"cors": "^2.8.5",
|
||||||
|
"http": "^0.0.1-security",
|
||||||
|
"jsonwebtoken": "^9.0.2",
|
||||||
"lucide-react": "^0.479.0",
|
"lucide-react": "^0.479.0",
|
||||||
"react": "^19.0.0",
|
"react": "^19.0.0",
|
||||||
"react-dom": "^19.0.0",
|
"react-dom": "^19.0.0",
|
||||||
"react-router-dom": "^7.3.0",
|
"react-router-dom": "^7.3.0",
|
||||||
"react-scripts": "5.0.1",
|
"react-scripts": "5.0.1",
|
||||||
|
"sanitize-html": "^2.14.0",
|
||||||
"socket.io-client": "^4.8.1",
|
"socket.io-client": "^4.8.1",
|
||||||
"web-vitals": "^2.1.4"
|
"web-vitals": "^2.1.4"
|
||||||
},
|
},
|
||||||
|
|||||||
247
src/App.css
247
src/App.css
@ -0,0 +1,247 @@
|
|||||||
|
/* Admin Panel Styles */
|
||||||
|
:root {
|
||||||
|
--primary-color: #3498db;
|
||||||
|
--secondary-color: #2ecc71;
|
||||||
|
--danger-color: #e74c3c;
|
||||||
|
--light-color: #f4f4f4;
|
||||||
|
--dark-color: #333;
|
||||||
|
--success-color: #27ae60;
|
||||||
|
--warning-color: #f39c12;
|
||||||
|
--error-color: #c0392b;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
background-color: #f8f9fa;
|
||||||
|
color: var(--dark-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.container {
|
||||||
|
max-width: 1200px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Login Page */
|
||||||
|
.login-container {
|
||||||
|
max-width: 400px;
|
||||||
|
margin: 100px auto;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-container h2 {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
color: var(--primary-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group input, .form-group select {
|
||||||
|
width: 100%;
|
||||||
|
padding: 8px;
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: var(--error-color);
|
||||||
|
background-color: #fadbd8;
|
||||||
|
padding: 8px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Buttons */
|
||||||
|
.btn-primary, .btn-secondary, .btn-danger {
|
||||||
|
display: inline-block;
|
||||||
|
padding: 8px 16px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: 600;
|
||||||
|
text-align: center;
|
||||||
|
text-decoration: none;
|
||||||
|
margin-right: 5px;
|
||||||
|
transition: background-color 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary {
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary {
|
||||||
|
background-color: var(--secondary-color);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-danger {
|
||||||
|
background-color: var(--danger-color);
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-primary:hover {
|
||||||
|
background-color: #2980b9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-secondary:hover {
|
||||||
|
background-color: #27ae60;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-danger:hover {
|
||||||
|
background-color: #c0392b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Dashboard */
|
||||||
|
.dashboard-container {
|
||||||
|
min-height: 100vh;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-header {
|
||||||
|
background-color: var(--primary-color);
|
||||||
|
color: white;
|
||||||
|
padding: 15px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-nav {
|
||||||
|
background-color: var(--light-color);
|
||||||
|
display: flex;
|
||||||
|
padding: 10px;
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link {
|
||||||
|
color: var(--dark-color);
|
||||||
|
text-decoration: none;
|
||||||
|
padding: 8px 16px;
|
||||||
|
margin-right: 10px;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link:hover {
|
||||||
|
background-color: #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dashboard-content {
|
||||||
|
flex: 1;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Team List */
|
||||||
|
.team-list-container {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-list-container h2 {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-table th, .team-table td {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-table th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forms */
|
||||||
|
.team-form-container, .result-form-container {
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 20px;
|
||||||
|
background-color: white;
|
||||||
|
border-radius: 5px;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-form-container h2, .result-form-container h2 {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calendar */
|
||||||
|
.calendar-container {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-picker {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.date-picker label {
|
||||||
|
margin-right: 10px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.results-container {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.results-container h3 {
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.results-table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.results-table th, .results-table td {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
padding: 10px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.results-table th {
|
||||||
|
background-color: #f2f2f2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Responsive adjustments */
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.dashboard-nav {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-link {
|
||||||
|
margin-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.team-table, .results-table {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
595
src/App.js
595
src/App.js
@ -1,24 +1,587 @@
|
|||||||
import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
|
import React, { useState, useEffect } from 'react';
|
||||||
import Home from "./pages/Home";
|
import { BrowserRouter as Router, Route, Routes, Navigate, Link } from 'react-router-dom';
|
||||||
import Admin from "./pages/Admin";
|
import './App.css';
|
||||||
import TeamsResults from "./pages/TeamResult";
|
import { useParams,useNavigate,useLocation } from 'react-router-dom';
|
||||||
import AdminPanel from "./pages/AdminPannel";
|
import Home from './pages/Home';
|
||||||
import { SattaUserView } from "./pages/UserView";
|
import TeamResults from './pages/TeamResult';
|
||||||
|
// Auth Context
|
||||||
|
const AuthContext = React.createContext();
|
||||||
|
|
||||||
|
const AuthProvider = ({ children }) => {
|
||||||
|
const [token, setToken] = useState(localStorage.getItem('token'));
|
||||||
|
|
||||||
|
const login = (newToken) => {
|
||||||
|
localStorage.setItem('token', newToken);
|
||||||
|
setToken(newToken);
|
||||||
|
};
|
||||||
|
|
||||||
|
const logout = () => {
|
||||||
|
localStorage.removeItem('token');
|
||||||
|
setToken(null);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AuthContext.Provider value={{ token, login, logout, isAuthenticated: !!token }}>
|
||||||
|
{children}
|
||||||
|
</AuthContext.Provider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// API Service
|
||||||
|
const API_URL = 'http://localhost:5500';
|
||||||
|
|
||||||
|
const apiService = {
|
||||||
|
login: async (accessKey, password) => {
|
||||||
|
const response = await fetch(`${API_URL}/admin/login`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ accessKey, password })
|
||||||
|
});
|
||||||
|
console.log(accessKey);
|
||||||
|
|
||||||
|
|
||||||
export default function App() {
|
if (!response.ok) {
|
||||||
|
throw new Error('Login failed');
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
},
|
||||||
|
|
||||||
|
getTeams: async (token) => {
|
||||||
|
const response = await fetch(`${API_URL}/api/teams`, {
|
||||||
|
headers: { 'Authorization': `Bearer ${token}` }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Failed to fetch teams');
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
},
|
||||||
|
|
||||||
|
createTeam: async (teamData, token) => {
|
||||||
|
const response = await fetch(`${API_URL}/api/teams`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
},
|
||||||
|
body: JSON.stringify(teamData)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Failed to create team');
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
},
|
||||||
|
|
||||||
|
updateTeam: async (id, teamData, token) => {
|
||||||
|
const response = await fetch(`${API_URL}/api/teams/${id}`, {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
},
|
||||||
|
body: JSON.stringify(teamData)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Failed to update team');
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteTeam: async (id, token) => {
|
||||||
|
const response = await fetch(`${API_URL}/api/teams/${id}`, {
|
||||||
|
method: 'DELETE',
|
||||||
|
headers: { 'Authorization': `Bearer ${token}` }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Failed to delete team');
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
},
|
||||||
|
|
||||||
|
publishResult: async (resultData, token) => {
|
||||||
|
const response = await fetch(`${API_URL}/admin/results`, {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'Authorization': `Bearer ${token}`
|
||||||
|
},
|
||||||
|
body: JSON.stringify(resultData)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Failed to publish result');
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
},
|
||||||
|
|
||||||
|
getDailyResults: async (date, token) => {
|
||||||
|
const response = await fetch(`${API_URL}/api/results/daily?date=${date}`, {
|
||||||
|
headers: { 'Authorization': `Bearer ${token}` }
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!response.ok) {
|
||||||
|
throw new Error('Failed to fetch daily results');
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.json();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Components
|
||||||
|
const Login = () => {
|
||||||
|
const [accessKey, setAccessKey] = useState('');
|
||||||
|
const [password, setPassword] = useState('');
|
||||||
|
const [error, setError] = useState('');
|
||||||
|
const { login } = React.useContext(AuthContext);
|
||||||
|
|
||||||
|
const handleSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
try {
|
||||||
|
const data = await apiService.login(accessKey, password);
|
||||||
|
login(data.token);
|
||||||
|
} catch (err) {
|
||||||
|
setError('Invalid credentials');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="login-container">
|
||||||
|
<h2>Admin Login</h2>
|
||||||
|
{error && <div className="error">{error}</div>}
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
<div className="form-group">
|
||||||
|
<label>Access Key</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={accessKey}
|
||||||
|
onChange={(e) => setAccessKey(e.target.value)}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label>Password</label>
|
||||||
|
<input
|
||||||
|
type="password"
|
||||||
|
value={password}
|
||||||
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button type="submit" className="btn-primary">Login</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const TeamList = () => {
|
||||||
|
const [teams, setTeams] = useState([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [error, setError] = useState('');
|
||||||
|
const { token } = React.useContext(AuthContext);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchTeams = async () => {
|
||||||
|
try {
|
||||||
|
const data = await apiService.getTeams(token);
|
||||||
|
setTeams(data);
|
||||||
|
setLoading(false);
|
||||||
|
} catch (err) {
|
||||||
|
setError('Failed to fetch teams');
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchTeams();
|
||||||
|
}, [token]);
|
||||||
|
|
||||||
|
const handleDelete = async (id) => {
|
||||||
|
if (window.confirm('Are you sure you want to delete this team?')) {
|
||||||
|
try {
|
||||||
|
await apiService.deleteTeam(id, token);
|
||||||
|
setTeams(teams.filter(team => team.id !== id));
|
||||||
|
} catch (err) {
|
||||||
|
setError('Failed to delete team');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (loading) return <div>Loading...</div>;
|
||||||
|
if (error) return <div className="error">{error}</div>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="team-list-container">
|
||||||
|
<h2>Team Management</h2>
|
||||||
|
<Link to="/teams/new" className="btn-primary">Add New Team</Link>
|
||||||
|
<table className="team-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>ID</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{teams.map(team => (
|
||||||
|
<tr key={team.id}>
|
||||||
|
<td>{team.id}</td>
|
||||||
|
<td>{team.name}</td>
|
||||||
|
<td>
|
||||||
|
<Link to={`/teams/edit/${team.id}`} className="btn-secondary">Edit</Link>
|
||||||
|
<button
|
||||||
|
onClick={() => handleDelete(team.id)}
|
||||||
|
className="btn-danger"
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const TeamForm = ({ isEdit = false }) => {
|
||||||
|
const [name, setName] = useState('');
|
||||||
|
const [submitting, setSubmitting] = useState(false);
|
||||||
|
const [error, setError] = useState('');
|
||||||
|
const { token } = React.useContext(AuthContext);
|
||||||
|
const { id } = useParams();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (isEdit && id) {
|
||||||
|
const fetchTeam = async () => {
|
||||||
|
try {
|
||||||
|
const teams = await apiService.getTeams(token);
|
||||||
|
const team = teams.find(t => t.id === parseInt(id));
|
||||||
|
if (team) {
|
||||||
|
setName(team.name);
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setError('Failed to fetch team details');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchTeam();
|
||||||
|
}
|
||||||
|
}, [isEdit, id, token]);
|
||||||
|
|
||||||
|
const handleSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setSubmitting(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (isEdit) {
|
||||||
|
await apiService.updateTeam(id, { name }, token);
|
||||||
|
} else {
|
||||||
|
await apiService.createTeam({ name }, token);
|
||||||
|
}
|
||||||
|
navigate('/teams');
|
||||||
|
} catch (err) {
|
||||||
|
setError(isEdit ? 'Failed to update team' : 'Failed to create team');
|
||||||
|
setSubmitting(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="team-form-container">
|
||||||
|
<h2>{isEdit ? 'Edit Team' : 'Add New Team'}</h2>
|
||||||
|
{error && <div className="error">{error}</div>}
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
<div className="form-group">
|
||||||
|
<label>Team Name</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value={name}
|
||||||
|
onChange={(e) => setName(e.target.value)}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="btn-primary"
|
||||||
|
disabled={submitting}
|
||||||
|
>
|
||||||
|
{submitting ? 'Saving...' : (isEdit ? 'Update Team' : 'Create Team')}
|
||||||
|
</button>
|
||||||
|
<Link to="/teams" className="btn-secondary">Cancel</Link>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ResultCalendar = () => {
|
||||||
|
const [date, setDate] = useState(new Date().toISOString().split('T')[0]);
|
||||||
|
const [results, setResults] = useState([]);
|
||||||
|
const [teams, setTeams] = useState([]);
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [error, setError] = useState('');
|
||||||
|
const { token } = React.useContext(AuthContext);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchData = async () => {
|
||||||
|
try {
|
||||||
|
const [teamsData, resultsData] = await Promise.all([
|
||||||
|
apiService.getTeams(token),
|
||||||
|
apiService.getDailyResults(date, token)
|
||||||
|
]);
|
||||||
|
setTeams(teamsData);
|
||||||
|
setResults(resultsData);
|
||||||
|
setLoading(false);
|
||||||
|
} catch (err) {
|
||||||
|
setError('Failed to fetch data');
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchData();
|
||||||
|
}, [date, token]);
|
||||||
|
|
||||||
|
const handleDateChange = (e) => {
|
||||||
|
setDate(e.target.value);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (loading) return <div>Loading...</div>;
|
||||||
|
if (error) return <div className="error">{error}</div>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="calendar-container">
|
||||||
|
<h2>Results Calendar</h2>
|
||||||
|
<div className="date-picker">
|
||||||
|
<label>Select Date: </label>
|
||||||
|
<input
|
||||||
|
type="date"
|
||||||
|
value={date}
|
||||||
|
onChange={handleDateChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="results-container">
|
||||||
|
<h3>Results for {date}</h3>
|
||||||
|
<Link to={`/results/new?date=${date}`} className="btn-primary">Add New Result</Link>
|
||||||
|
|
||||||
|
{results.length === 0 ? (
|
||||||
|
<p>No results for this date.</p>
|
||||||
|
) : (
|
||||||
|
<table className="results-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>Team</th>
|
||||||
|
<th>Result</th>
|
||||||
|
<th>Actions</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{results.map(result => (
|
||||||
|
<tr key={result.id}>
|
||||||
|
<td>{result.team}</td>
|
||||||
|
<td>{result.result}</td>
|
||||||
|
<td>
|
||||||
|
<Link to={`/results/edit/${result.id}?date=${date}`} className="btn-secondary">Edit</Link>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const ResultForm = ({ isEdit = false }) => {
|
||||||
|
const [formData, setFormData] = useState({
|
||||||
|
team_id: '',
|
||||||
|
result: '',
|
||||||
|
result_date: new Date().toISOString().split('T')[0]
|
||||||
|
});
|
||||||
|
const [teams, setTeams] = useState([]);
|
||||||
|
const [submitting, setSubmitting] = useState(false);
|
||||||
|
const [error, setError] = useState('');
|
||||||
|
const { token } = React.useContext(AuthContext);
|
||||||
|
const { id } = useParams();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const fetchTeams = async () => {
|
||||||
|
try {
|
||||||
|
const teamsData = await apiService.getTeams(token);
|
||||||
|
setTeams(teamsData);
|
||||||
|
|
||||||
|
// Set date from query params if available
|
||||||
|
const params = new URLSearchParams(location.search);
|
||||||
|
const dateParam = params.get('date');
|
||||||
|
if (dateParam) {
|
||||||
|
setFormData(prev => ({ ...prev, result_date: dateParam }));
|
||||||
|
}
|
||||||
|
|
||||||
|
// If editing, fetch the result details
|
||||||
|
if (isEdit && id) {
|
||||||
|
// This is a simplified approach. In a real app, you'd have an API endpoint to fetch a specific result
|
||||||
|
const results = await apiService.getDailyResults(dateParam, token);
|
||||||
|
const result = results.find(r => r.id === parseInt(id));
|
||||||
|
if (result) {
|
||||||
|
setFormData({
|
||||||
|
team_id: result.team_id,
|
||||||
|
result: result.result,
|
||||||
|
result_date: result.result_date
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
setError('Failed to fetch data');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
fetchTeams();
|
||||||
|
}, [isEdit, id, token, location.search]);
|
||||||
|
|
||||||
|
const handleChange = (e) => {
|
||||||
|
const { name, value } = e.target;
|
||||||
|
setFormData(prev => ({ ...prev, [name]: value }));
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleSubmit = async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
setSubmitting(true);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await apiService.publishResult(formData, token);
|
||||||
|
navigate(`/results?date=${formData.result_date}`);
|
||||||
|
} catch (err) {
|
||||||
|
setError('Failed to publish result');
|
||||||
|
setSubmitting(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="result-form-container">
|
||||||
|
<h2>{isEdit ? 'Edit Result' : 'Add New Result'}</h2>
|
||||||
|
{error && <div className="error">{error}</div>}
|
||||||
|
<form onSubmit={handleSubmit}>
|
||||||
|
<div className="form-group">
|
||||||
|
<label>Team</label>
|
||||||
|
<select
|
||||||
|
name="team_id"
|
||||||
|
value={formData.team_id}
|
||||||
|
onChange={handleChange}
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<option value="">Select a team</option>
|
||||||
|
{teams.map(team => (
|
||||||
|
<option key={team.id} value={team.id}>{team.name}</option>
|
||||||
|
))}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label>Result</label>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="result"
|
||||||
|
value={formData.result}
|
||||||
|
onChange={handleChange}
|
||||||
|
placeholder="e.g., Win 3-2"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className="form-group">
|
||||||
|
<label>Date</label>
|
||||||
|
<input
|
||||||
|
type="date"
|
||||||
|
name="result_date"
|
||||||
|
value={formData.result_date}
|
||||||
|
onChange={handleChange}
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="btn-primary"
|
||||||
|
disabled={submitting}
|
||||||
|
>
|
||||||
|
{submitting ? 'Saving...' : (isEdit ? 'Update Result' : 'Publish Result')}
|
||||||
|
</button>
|
||||||
|
<Link to={`/results?date=${formData.result_date}`} className="btn-secondary">Cancel</Link>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const Dashboard = () => {
|
||||||
|
const { logout } = React.useContext(AuthContext);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="dashboard-container">
|
||||||
|
<header className="dashboard-header">
|
||||||
|
<h1>Admin Dashboard</h1>
|
||||||
|
<button onClick={logout} className="btn-danger">Logout</button>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<nav className="dashboard-nav">
|
||||||
|
<Link to="/teams" className="nav-link">Teams</Link>
|
||||||
|
<Link to="/results" className="nav-link">Results</Link>
|
||||||
|
</nav>
|
||||||
|
|
||||||
|
<div className="dashboard-content">
|
||||||
|
<Routes>
|
||||||
|
<Route path="/teams" element={<TeamList />} />
|
||||||
|
<Route path="/teams/new" element={<TeamForm />} />
|
||||||
|
<Route path="/teams/edit/:id" element={<TeamForm isEdit={true} />} />
|
||||||
|
<Route path="/results" element={<ResultCalendar />} />
|
||||||
|
<Route path="/results/new" element={<ResultForm />} />
|
||||||
|
<Route path="/results/edit/:id" element={<ResultForm isEdit={true} />} />
|
||||||
|
<Route path="/" element={<Navigate to="/teams" />} />
|
||||||
|
</Routes>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Protected Route
|
||||||
|
const ProtectedRoute = ({ children }) => {
|
||||||
|
const { isAuthenticated } = React.useContext(AuthContext);
|
||||||
|
|
||||||
|
if (!isAuthenticated) {
|
||||||
|
return <Navigate to="/login" />;
|
||||||
|
}
|
||||||
|
|
||||||
|
return children;
|
||||||
|
};
|
||||||
|
|
||||||
|
// App
|
||||||
|
const App = () => {
|
||||||
return (
|
return (
|
||||||
<Router>
|
<Router>
|
||||||
|
<AuthProvider>
|
||||||
<Routes>
|
<Routes>
|
||||||
|
<Route path="/login" element={<Login />} />
|
||||||
|
<Route
|
||||||
|
path="/admin"
|
||||||
|
element={
|
||||||
|
<ProtectedRoute>
|
||||||
|
<Dashboard />
|
||||||
|
</ProtectedRoute>
|
||||||
|
}
|
||||||
|
/>
|
||||||
<Route path="/" element={<Home />} />
|
<Route path="/" element={<Home />} />
|
||||||
<Route path="/admin" element={<Admin/>}/>
|
<Route path="/res" element={<TeamResults />} />
|
||||||
<Route path="team" element={<TeamsResults/>}/>
|
|
||||||
|
|
||||||
|
|
||||||
{/* test */}
|
|
||||||
<Route path="/admin2" element={<AdminPanel />} />
|
|
||||||
<Route path="/user2" element={<SattaUserView/>}/>
|
|
||||||
</Routes>
|
</Routes>
|
||||||
</Router>
|
</AuthProvider>
|
||||||
|
</Router>
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
};
|
||||||
|
|
||||||
|
export default App;
|
||||||
@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
|
|||||||
import { PlusCircle, Trash2, Edit, BarChart2 } from 'lucide-react';
|
import { PlusCircle, Trash2, Edit, BarChart2 } from 'lucide-react';
|
||||||
// import dataService from '../services/dataService';
|
// import dataService from '../services/dataService';
|
||||||
import dataService from '../services/DataService';
|
import dataService from '../services/DataService';
|
||||||
|
import { useParams,useNavigate,useLocation } from 'react-router-dom';
|
||||||
|
|
||||||
const AdminPanel = () => {
|
const AdminPanel = () => {
|
||||||
const [teams, setTeams] = useState([]);
|
const [teams, setTeams] = useState([]);
|
||||||
|
|||||||
@ -1,92 +1,233 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import { BarChart2, Calendar } from 'lucide-react';
|
import { BarChart2, Calendar, RefreshCw } from 'lucide-react';
|
||||||
import { useEffect } from 'react';
|
import axios from 'axios';
|
||||||
const Home = () => {
|
|
||||||
const [teams, setTeams] = useState([
|
|
||||||
{ id: 1, name: 'BIKANER SUPER', time: '02:20 AM', results: { '2025-03-11': '04', '2025-03-12': '61' } },
|
|
||||||
{ id: 2, name: 'DESAWAR', time: '05:00 AM', results: { '2025-03-11': '79', '2025-03-12': '55' } },
|
|
||||||
{ id: 3, name: 'FARIDABAD', time: '06:00 PM', results: { '2025-03-11': '78', '2025-03-12': '98' } },
|
|
||||||
{ id: 4, name: 'GHAZIABAD', time: '09:30 PM', results: { '2025-03-11': '19', '2025-03-12': '23' } },
|
|
||||||
{ id: 5, name: 'GALI', time: '11:30 PM', results: { '2025-03-11': '72', '2025-03-12': 'XX' } },
|
|
||||||
]);
|
|
||||||
|
|
||||||
const [dates] = useState(['2025-03-11', '2025-03-12']);
|
const Home = () => {
|
||||||
|
const [teams, setTeams] = useState([]);
|
||||||
|
const [dates, setDates] = useState([]);
|
||||||
const [selectedTeam, setSelectedTeam] = useState(null);
|
const [selectedTeam, setSelectedTeam] = useState(null);
|
||||||
const [showChartView, setShowChartView] = useState(false);
|
const [showChartView, setShowChartView] = useState(false);
|
||||||
const [showCalendar, setShowCalendar] = useState(false);
|
const [showCalendar, setShowCalendar] = useState(false);
|
||||||
|
const [currentTime, setCurrentTime] = useState("");
|
||||||
|
const [loading, setLoading] = useState(true);
|
||||||
|
const [error, setError] = useState(null);
|
||||||
|
const [calendarData, setCalendarData] = useState([]);
|
||||||
|
const [currentMonth, setCurrentMonth] = useState(new Date());
|
||||||
|
|
||||||
|
// API URL
|
||||||
|
const API_URL = 'http://localhost:5500/api';
|
||||||
|
|
||||||
|
// Fetch teams data
|
||||||
|
useEffect(() => {
|
||||||
|
|
||||||
// Show chart for selected team
|
const fetchTeams = async () => {
|
||||||
const handleViewChart = (team) => {
|
try {
|
||||||
setSelectedTeam(team);
|
setLoading(true);
|
||||||
setShowChartView(true);
|
// Get all teams
|
||||||
setShowCalendar(false);
|
const teamsResponse = await axios.get(`${API_URL}/teams`);
|
||||||
};
|
alert("teamsResponse");
|
||||||
|
|
||||||
// Generate mock chart data for the selected team
|
// Get today's date and format it
|
||||||
const generateChartData = () => {
|
const today = new Date();
|
||||||
if (!selectedTeam) return [];
|
const todayFormatted = today.toISOString().split('T')[0];
|
||||||
|
// Get yesterday's date and format it
|
||||||
|
const yesterday = new Date();
|
||||||
|
yesterday.setDate(yesterday.getDate() - 1);
|
||||||
|
const yesterdayFormatted = yesterday.toISOString().split('T')[0];
|
||||||
|
|
||||||
// Generate some random data for demonstration
|
// Set dates for display
|
||||||
const mockData = [];
|
setDates([yesterdayFormatted, todayFormatted]);
|
||||||
const currentDate = new Date();
|
|
||||||
|
|
||||||
for (let i = 0; i < 30; i++) {
|
// Get today's results
|
||||||
const date = new Date(currentDate);
|
const todayResultsResponse = await axios.get(`${API_URL}/today`);
|
||||||
date.setDate(date.getDate() - i);
|
|
||||||
const dateStr = date.toISOString().split('T')[0];
|
|
||||||
|
|
||||||
mockData.unshift({
|
// Get yesterday's results for each team
|
||||||
date: dateStr,
|
const yesterdayResultsPromises = teamsResponse.data.map(team =>
|
||||||
result: Math.floor(Math.random() * 100).toString().padStart(2, '0')
|
axios.get(`${API_URL}/results?team=${team.name}&date=${yesterdayFormatted}`)
|
||||||
});
|
.then(response => response.data)
|
||||||
|
.catch(() => null) // If no result, return null
|
||||||
|
);
|
||||||
|
|
||||||
|
const yesterdayResults = await Promise.all(yesterdayResultsPromises);
|
||||||
|
|
||||||
|
// Combine team data with results
|
||||||
|
const teamsWithResults = teamsResponse.data.map((team, index) => {
|
||||||
|
const results = {};
|
||||||
|
|
||||||
|
// Add yesterday's result if available
|
||||||
|
if (yesterdayResults[index]) {
|
||||||
|
results[yesterdayFormatted] = yesterdayResults[index].result;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mockData;
|
// Add today's result if available
|
||||||
|
const todayResult = todayResultsResponse.data.find(r => r.team === team.name);
|
||||||
|
if (todayResult) {
|
||||||
|
results[todayFormatted] = todayResult.result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract time from team name or use default
|
||||||
|
let time = "XX:XX";
|
||||||
|
const timePart = team.name.match(/\d{2}:\d{2}\s*(?:AM|PM)/i);
|
||||||
|
if (timePart) {
|
||||||
|
time = timePart[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: team.id,
|
||||||
|
name: team.name,
|
||||||
|
time: time,
|
||||||
|
results: results
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
setTeams(teamsWithResults);
|
||||||
|
setLoading(false);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error fetching data:", err);
|
||||||
|
setError("Failed to load team data. Please try again later.");
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generate calendar view with results
|
fetchTeams();
|
||||||
const generateCalendarData = () => {
|
|
||||||
const calendarDays = [];
|
// Update current time every minute
|
||||||
|
const interval = setInterval(() => {
|
||||||
|
const now = new Date();
|
||||||
|
const formattedTime = now.toLocaleString("en-IN", { timeZone: "Asia/Kolkata" });
|
||||||
|
setCurrentTime(formattedTime);
|
||||||
|
}, 60000);
|
||||||
|
|
||||||
|
// Set initial time
|
||||||
|
const now = new Date();
|
||||||
|
const formattedTime = now.toLocaleString("en-IN", { timeZone: "Asia/Kolkata" });
|
||||||
|
setCurrentTime(formattedTime);
|
||||||
|
|
||||||
|
return () => clearInterval(interval);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
// Show chart for selected team
|
||||||
|
const handleViewChart = async (team) => {
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
// Get monthly results for the selected team
|
||||||
const currentDate = new Date();
|
const currentDate = new Date();
|
||||||
const firstDayOfMonth = new Date(currentDate.getFullYear(), currentDate.getMonth(), 1);
|
const month = currentDate.getMonth() + 1;
|
||||||
const lastDayOfMonth = new Date(currentDate.getFullYear(), currentDate.getMonth() + 1, 0);
|
const year = currentDate.getFullYear();
|
||||||
|
|
||||||
|
const response = await axios.post(`${API_URL}/results/monthly`, {
|
||||||
|
team: team.name,
|
||||||
|
month: `${year}-${month.toString().padStart(2, '0')}`
|
||||||
|
});
|
||||||
|
|
||||||
|
setSelectedTeam({
|
||||||
|
...team,
|
||||||
|
chartData: response.data
|
||||||
|
});
|
||||||
|
|
||||||
|
setShowChartView(true);
|
||||||
|
setShowCalendar(false);
|
||||||
|
setLoading(false);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error fetching chart data:", err);
|
||||||
|
setError("Failed to load chart data. Please try again later.");
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Load calendar data
|
||||||
|
const loadCalendarData = async (year, month) => {
|
||||||
|
try {
|
||||||
|
setLoading(true);
|
||||||
|
|
||||||
|
// Calculate first and last day of month
|
||||||
|
const firstDay = new Date(year, month, 1).toISOString().split('T')[0];
|
||||||
|
const lastDay = new Date(year, month + 1, 0).toISOString().split('T')[0];
|
||||||
|
|
||||||
|
// Get results for each day in the month
|
||||||
|
const dailyResultsPromises = [];
|
||||||
|
const currentDate = new Date(year, month, 1);
|
||||||
|
const lastDate = new Date(year, month + 1, 0);
|
||||||
|
|
||||||
|
while (currentDate <= lastDate) {
|
||||||
|
const dateString = currentDate.toISOString().split('T')[0];
|
||||||
|
dailyResultsPromises.push(
|
||||||
|
axios.get(`${API_URL}/results/daily?date=${dateString}`)
|
||||||
|
.then(response => ({
|
||||||
|
date: dateString,
|
||||||
|
results: response.data
|
||||||
|
}))
|
||||||
|
.catch(() => ({
|
||||||
|
date: dateString,
|
||||||
|
results: []
|
||||||
|
}))
|
||||||
|
);
|
||||||
|
currentDate.setDate(currentDate.getDate() + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const allResults = await Promise.all(dailyResultsPromises);
|
||||||
|
|
||||||
|
// Format calendar data
|
||||||
|
const calendarDays = [];
|
||||||
|
const firstDayOfMonth = new Date(year, month, 1);
|
||||||
|
const firstDayWeekday = firstDayOfMonth.getDay();
|
||||||
|
|
||||||
// Add empty cells for days before the first of the month
|
// Add empty cells for days before the first of the month
|
||||||
const firstDayWeekday = firstDayOfMonth.getDay();
|
|
||||||
for (let i = 0; i < firstDayWeekday; i++) {
|
for (let i = 0; i < firstDayWeekday; i++) {
|
||||||
calendarDays.push(null);
|
calendarDays.push(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add days of the month
|
// Add days with results
|
||||||
for (let i = 1; i <= lastDayOfMonth.getDate(); i++) {
|
for (let i = 1; i <= lastDate.getDate(); i++) {
|
||||||
const date = new Date(currentDate.getFullYear(), currentDate.getMonth(), i);
|
const dateObj = new Date(year, month, i);
|
||||||
const dateStr = date.toISOString().split('T')[0];
|
const dateStr = dateObj.toISOString().split('T')[0];
|
||||||
|
|
||||||
// Generate mock results for each team on this date
|
const dayData = allResults.find(r => r.date === dateStr);
|
||||||
const dayResults = {};
|
let teamResults = {};
|
||||||
teams.forEach(team => {
|
|
||||||
dayResults[team.id] = Math.floor(Math.random() * 100).toString().padStart(2, '0');
|
if (dayData && dayData.results.length > 0) {
|
||||||
|
dayData.results.forEach(result => {
|
||||||
|
teamResults[result.team] = result.result;
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
calendarDays.push({
|
calendarDays.push({
|
||||||
day: i,
|
day: i,
|
||||||
date: dateStr,
|
date: dateStr,
|
||||||
results: dayResults
|
results: teamResults
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return calendarDays;
|
setCalendarData(calendarDays);
|
||||||
|
setLoading(false);
|
||||||
|
} catch (err) {
|
||||||
|
console.error("Error loading calendar data:", err);
|
||||||
|
setError("Failed to load calendar data. Please try again later.");
|
||||||
|
setLoading(false);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const [currentTime, setCurrentTime] = useState("");
|
// Handle calendar view button click
|
||||||
|
const handleCalendarView = () => {
|
||||||
useEffect(() => {
|
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const formattedTime = now.toLocaleString("en-IN", { timeZone: "Asia/Kolkata" });
|
setCurrentMonth(now);
|
||||||
setCurrentTime(formattedTime);
|
loadCalendarData(now.getFullYear(), now.getMonth());
|
||||||
}, []);
|
setShowCalendar(true);
|
||||||
|
setShowChartView(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle month change in calendar
|
||||||
|
const handleMonthChange = (increment) => {
|
||||||
|
const newMonth = new Date(currentMonth);
|
||||||
|
newMonth.setMonth(newMonth.getMonth() + increment);
|
||||||
|
setCurrentMonth(newMonth);
|
||||||
|
loadCalendarData(newMonth.getFullYear(), newMonth.getMonth());
|
||||||
|
};
|
||||||
|
|
||||||
|
// Refresh data
|
||||||
|
const handleRefresh = () => {
|
||||||
|
window.location.reload();
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-gray-100 min-h-screen p-4">
|
<div className="bg-gray-100 min-h-screen p-4">
|
||||||
@ -97,29 +238,29 @@ const Home = () => {
|
|||||||
{/* Advertisement Banner */}
|
{/* Advertisement Banner */}
|
||||||
<div className="mt-4 flex justify-center items-center">
|
<div className="mt-4 flex justify-center items-center">
|
||||||
<img
|
<img
|
||||||
src="/path-to-your-advertisement-image.jpg"
|
src="/api/placeholder/800/120"
|
||||||
alt="Advertisement"
|
alt="Advertisement"
|
||||||
className="w-full max-w-4xl"
|
className="w-full max-w-4xl"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Informational Text */}
|
{/* Informational Text */}
|
||||||
<p className="mt-4 text-gray-700 text-sm p-1 w-[100%] lg:w-3/4 m-auto">
|
<p className="mt-4 text-gray-700 text-sm p-1 w-full lg:w-3/4 m-auto">
|
||||||
Delhi Diamond Satta Result And Monthly Satta Chart of March 2025 With Combined Chart of Gali, Desawar, Ghaziabad, Faridabad And Shri Ganesh from Satta King Fast, Satta King Result, Satta King Chart, Black Satta King and Satta King 786.
|
Delhi Diamond Satta Result And Monthly Satta Chart of March 2025 With Combined Chart of Gali, Desawar, Ghaziabad, Faridabad And Shri Ganesh from Satta King Fast, Satta King Result, Satta King Chart, Black Satta King and Satta King 786.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* Disclaimer */}
|
{/* Disclaimer */}
|
||||||
<p className="mt-2 text-blue-600 text-sm font-medium bg-white p-1 w-[100%] lg:w-3/4 m-auto">
|
<p className="mt-2 text-blue-600 text-sm font-medium bg-white p-1 w-full lg:w-3/4 m-auto">
|
||||||
Satta-King-Fast.com is the most popular gaming discussion forum for players to use freely and we are not in partnership with any gaming company.
|
Satta-King-Fast.com is the most popular gaming discussion forum for players to use freely and we are not in partnership with any gaming company.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* Warning Message */}
|
{/* Warning Message */}
|
||||||
<p className="mt-2 text-red-600 font-bold bg-white p-1 w-[100%] lg:w-3/4 m-auto">
|
<p className="mt-2 text-red-600 font-bold bg-white p-1 w-full lg:w-3/4 m-auto">
|
||||||
कृपया ध्यान दें, लीक गेम के नाम पर किसी को कोई पैसा न दें, ना पहले ना बाद में - धन्यवाद
|
कृपया ध्यान दें, लीक गेम के नाम पर किसी को कोई पैसा न दें, ना पहले ना बाद में - धन्यवाद
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
{/* Contact Link */}
|
{/* Contact Link */}
|
||||||
<p className="mt-2 text-green-600 font-medium bg-white p-1 w-[100%] lg:w-3/4 m-auto">
|
<p className="mt-2 text-green-600 font-medium bg-white p-1 w-full lg:w-3/4 m-auto">
|
||||||
हमसे संपर्क करने के लिए ➡ <a href="#" className="underline">यहाँ क्लिक करें</a>
|
हमसे संपर्क करने के लिए ➡ <a href="#" className="underline">यहाँ क्लिक करें</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -130,8 +271,14 @@ const Home = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="max-w-6xl mx-auto">
|
<div className="max-w-6xl mx-auto">
|
||||||
|
{error && (
|
||||||
|
<div className="bg-red-100 border border-red-400 text-red-700 px-4 py-3 rounded mb-4">
|
||||||
|
<p>{error}</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
<div className="bg-emerald-400 p-4 text-white text-center text-xl font-bold rounded-t-lg">
|
<div className="bg-emerald-400 p-4 text-white text-center text-xl font-bold rounded-t-lg">
|
||||||
Bikaner Super Satta Result of March 12, 2025 & March 11, 2025
|
{teams.length > 0 && teams[0].name} Satta Result of {dates.length > 1 && new Date(dates[1]).toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' })} & {dates.length > 0 && new Date(dates[0]).toLocaleDateString('en-US', { month: 'long', day: 'numeric', year: 'numeric' })}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Controls */}
|
{/* Controls */}
|
||||||
@ -141,19 +288,35 @@ const Home = () => {
|
|||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<button
|
<button
|
||||||
className="bg-blue-500 text-white px-4 py-2 rounded flex items-center gap-2"
|
className="bg-blue-500 text-white px-4 py-2 rounded flex items-center gap-2"
|
||||||
onClick={() => {
|
onClick={handleCalendarView}
|
||||||
setShowCalendar(true);
|
disabled={loading}
|
||||||
setShowChartView(false);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<Calendar size={16} />
|
<Calendar size={16} />
|
||||||
Calendar View
|
Calendar View
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
className="bg-green-500 text-white px-4 py-2 rounded flex items-center gap-2"
|
||||||
|
onClick={handleRefresh}
|
||||||
|
disabled={loading}
|
||||||
|
>
|
||||||
|
<RefreshCw size={16} />
|
||||||
|
Refresh
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Loading indicator */}
|
||||||
|
{loading && (
|
||||||
|
<div className="bg-white p-8 mb-4 rounded shadow flex justify-center items-center">
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<RefreshCw size={24} className="animate-spin text-blue-500" />
|
||||||
|
<span>Loading data...</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
{/* Chart View */}
|
{/* Chart View */}
|
||||||
{showChartView && selectedTeam && (
|
{!loading && showChartView && selectedTeam && (
|
||||||
<div className="bg-white p-4 mb-4 rounded shadow">
|
<div className="bg-white p-4 mb-4 rounded shadow">
|
||||||
<h2 className="text-lg font-semibold mb-4">Monthly Chart: {selectedTeam.name}</h2>
|
<h2 className="text-lg font-semibold mb-4">Monthly Chart: {selectedTeam.name}</h2>
|
||||||
<div className="overflow-x-auto">
|
<div className="overflow-x-auto">
|
||||||
@ -165,12 +328,17 @@ const Home = () => {
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{generateChartData().map((item, index) => (
|
{selectedTeam.chartData && selectedTeam.chartData.map((item, index) => (
|
||||||
<tr key={index} className={index % 2 === 0 ? 'bg-gray-50' : 'bg-white'}>
|
<tr key={index} className={index % 2 === 0 ? 'bg-gray-50' : 'bg-white'}>
|
||||||
<td className="border p-2">{new Date(item.date).toLocaleDateString()}</td>
|
<td className="border p-2">{new Date(item.result_date).toLocaleDateString()}</td>
|
||||||
<td className="border p-2 text-right font-bold">{item.result}</td>
|
<td className="border p-2 text-right font-bold">{item.result}</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
|
{(!selectedTeam.chartData || selectedTeam.chartData.length === 0) && (
|
||||||
|
<tr>
|
||||||
|
<td colSpan="2" className="border p-2 text-center">No chart data available</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
@ -186,12 +354,28 @@ const Home = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Calendar View */}
|
{/* Calendar View */}
|
||||||
{showCalendar && (
|
{!loading && showCalendar && (
|
||||||
<div className="bg-white p-4 mb-4 rounded shadow">
|
<div className="bg-white p-4 mb-4 rounded shadow">
|
||||||
<h2 className="text-lg font-semibold mb-4">
|
<div className="flex justify-between items-center mb-4">
|
||||||
Calendar View: {new Date().toLocaleDateString('en-US', { month: 'long', year: 'numeric' })}
|
<button
|
||||||
|
className="bg-gray-200 p-2 rounded"
|
||||||
|
onClick={() => handleMonthChange(-1)}
|
||||||
|
>
|
||||||
|
Previous Month
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<h2 className="text-lg font-semibold">
|
||||||
|
{currentMonth.toLocaleDateString('en-US', { month: 'long', year: 'numeric' })}
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
|
<button
|
||||||
|
className="bg-gray-200 p-2 rounded"
|
||||||
|
onClick={() => handleMonthChange(1)}
|
||||||
|
>
|
||||||
|
Next Month
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-7 gap-2 mb-2">
|
<div className="grid grid-cols-7 gap-2 mb-2">
|
||||||
{['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map(day => (
|
{['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'].map(day => (
|
||||||
<div key={day} className="text-center font-semibold">{day}</div>
|
<div key={day} className="text-center font-semibold">{day}</div>
|
||||||
@ -199,14 +383,18 @@ const Home = () => {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="grid grid-cols-7 gap-2">
|
<div className="grid grid-cols-7 gap-2">
|
||||||
{generateCalendarData().map((day, index) => (
|
{calendarData.map((day, index) => (
|
||||||
<div key={index} className={`border rounded p-2 min-h-16 ${day ? 'bg-white' : ''}`}>
|
<div key={index} className={`border rounded p-2 min-h-16 ${day ? 'bg-white' : ''}`}>
|
||||||
{day && (
|
{day && (
|
||||||
<>
|
<>
|
||||||
<div className="text-right text-sm text-gray-500">{day.day}</div>
|
<div className="text-right text-sm text-gray-500">{day.day}</div>
|
||||||
{teams.map(team => (
|
{teams.map(team => (
|
||||||
<div key={team.id} className="text-xs mt-1">
|
<div key={team.id} className="text-xs mt-1">
|
||||||
<span className="font-semibold">{team.name.split(' ')[0]}:</span> {day.results[team.id]}
|
{day.results[team.name] && (
|
||||||
|
<>
|
||||||
|
<span className="font-semibold">{team.name.split(' ')[0]}:</span> {day.results[team.name]}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</>
|
</>
|
||||||
@ -227,17 +415,17 @@ const Home = () => {
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Teams Table */}
|
{/* Teams Table */}
|
||||||
{!showCalendar && (
|
{!loading && !showCalendar && !showChartView && (
|
||||||
<div className="bg-white rounded-b-lg overflow-hidden">
|
<div className="bg-white rounded-b-lg overflow-hidden">
|
||||||
<table className="w-full border-collapse">
|
<table className="w-full border-collapse">
|
||||||
<thead>
|
<thead>
|
||||||
<tr className="bg-gray-800 text-white">
|
<tr className="bg-gray-800 text-white">
|
||||||
<th className="p-3 text-left">Games List</th>
|
<th className="p-3 text-left">Games List</th>
|
||||||
<th className="p-3 text-center">
|
<th className="p-3 text-center">
|
||||||
{new Date(dates[0]).toLocaleDateString('en-US', { weekday: 'short' })} {new Date(dates[0]).getDate()}th
|
{dates.length > 0 && new Date(dates[0]).toLocaleDateString('en-US', { weekday: 'short' })} {dates.length > 0 && new Date(dates[0]).getDate()}th
|
||||||
</th>
|
</th>
|
||||||
<th className="p-3 text-center">
|
<th className="p-3 text-center">
|
||||||
{new Date(dates[1]).toLocaleDateString('en-US', { weekday: 'short' })} {new Date(dates[1]).getDate()}th
|
{dates.length > 1 && new Date(dates[1]).toLocaleDateString('en-US', { weekday: 'short' })} {dates.length > 1 && new Date(dates[1]).getDate()}th
|
||||||
</th>
|
</th>
|
||||||
<th className="p-3 text-center">Chart</th>
|
<th className="p-3 text-center">Chart</th>
|
||||||
</tr>
|
</tr>
|
||||||
@ -248,10 +436,10 @@ const Home = () => {
|
|||||||
<td className="p-3">
|
<td className="p-3">
|
||||||
<div className="font-semibold">{team.name}</div>
|
<div className="font-semibold">{team.name}</div>
|
||||||
<div className="text-sm text-gray-500">at {team.time}</div>
|
<div className="text-sm text-gray-500">at {team.time}</div>
|
||||||
<div className="text-xs text-blue-500 underline mt-1">Record Chart</div>
|
<div className="text-xs text-blue-500 underline mt-1 cursor-pointer" onClick={() => handleViewChart(team)}>Record Chart</div>
|
||||||
</td>
|
</td>
|
||||||
<td className="p-3 text-center text-2xl font-bold">{team.results[dates[0]] || 'XX'}</td>
|
<td className="p-3 text-center text-2xl font-bold">{dates.length > 0 && team.results[dates[0]] || 'XX'}</td>
|
||||||
<td className="p-3 text-center text-2xl font-bold">{team.results[dates[1]] || 'XX'}</td>
|
<td className="p-3 text-center text-2xl font-bold">{dates.length > 1 && team.results[dates[1]] || 'XX'}</td>
|
||||||
<td className="p-3">
|
<td className="p-3">
|
||||||
<div className="flex justify-center">
|
<div className="flex justify-center">
|
||||||
<button
|
<button
|
||||||
@ -265,11 +453,16 @@ const Home = () => {
|
|||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
))}
|
||||||
|
{teams.length === 0 && (
|
||||||
|
<tr>
|
||||||
|
<td colSpan="4" className="p-4 text-center">No teams found</td>
|
||||||
|
</tr>
|
||||||
|
)}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<div className="bg-gray-700 text-white text-center p-3">
|
<div className="bg-gray-700 text-white text-center p-3">
|
||||||
<button className="hover:underline">Click here for all games results.</button>
|
<button className="hover:underline" onClick={handleCalendarView}>Click here for all games results.</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@ -1,20 +1,37 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
|
|
||||||
|
// Function to sanitize potential XSS threats in strings
|
||||||
|
const sanitizeString = (str) => {
|
||||||
|
const div = document.createElement("div");
|
||||||
|
div.textContent = str;
|
||||||
|
return div.innerHTML;
|
||||||
|
};
|
||||||
|
|
||||||
const TeamResults = () => {
|
const TeamResults = () => {
|
||||||
const [teams, setTeams] = useState([]);
|
const [teams, setTeams] = useState([]);
|
||||||
const [loading, setLoading] = useState(true);
|
const [loading, setLoading] = useState(true);
|
||||||
const [error, setError] = useState(null);
|
const [error, setError] = useState(null);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
const fetchData = async () => {
|
const fetchData = async () => {
|
||||||
try {
|
try {
|
||||||
const response = await fetch("http://localhost:5000/api/teams/");
|
const response = await fetch("http://localhost:5500/api/teams");
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
throw new Error(`HTTP error! Status: ${response.status}`);
|
throw new Error(`HTTP error! Status: ${response.status}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const data = await response.json(); // Parse JSON response
|
const data = await response.json();
|
||||||
setTeams(data); // Store the entire API response in state
|
|
||||||
|
// Ensure safe rendering of team names
|
||||||
|
const sanitizedData = data.map((team) => ({
|
||||||
|
...team,
|
||||||
|
name: sanitizeString(team.name),
|
||||||
|
announcement_time: team.announcement_time || "N/A", // Handle missing time
|
||||||
|
results: team.results || {} // Ensure results exist
|
||||||
|
}));
|
||||||
|
|
||||||
|
setTeams(sanitizedData);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error fetching data:", error);
|
console.error("Error fetching data:", error);
|
||||||
setError(error.message);
|
setError(error.message);
|
||||||
@ -23,12 +40,11 @@ const TeamResults = () => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
fetchData();
|
fetchData();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (loading) return <p>Loading...</p>;
|
if (loading) return <p>Loading...</p>;
|
||||||
if (error) return <p>Error: {error}</p>;
|
if (error) return <p className="text-red-500">Error: {error}</p>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="p-4">
|
<div className="p-4">
|
||||||
@ -37,9 +53,11 @@ const TeamResults = () => {
|
|||||||
{teams.map((team) => (
|
{teams.map((team) => (
|
||||||
<div key={team.id} className="border p-4 rounded-md shadow-md">
|
<div key={team.id} className="border p-4 rounded-md shadow-md">
|
||||||
<h3 className="text-lg font-semibold">{team.name}</h3>
|
<h3 className="text-lg font-semibold">{team.name}</h3>
|
||||||
<p className="text-sm text-gray-600">Time: {team.time}</p>
|
<p className="text-sm text-gray-600">Time: {team.announcement_time}</p>
|
||||||
|
|
||||||
<div className="mt-2">
|
<div className="mt-2">
|
||||||
<h4 className="font-semibold">Results:</h4>
|
<h4 className="font-semibold">Results:</h4>
|
||||||
|
{Object.keys(team.results).length > 0 ? (
|
||||||
<ul className="list-disc pl-4">
|
<ul className="list-disc pl-4">
|
||||||
{Object.entries(team.results).map(([date, result]) => (
|
{Object.entries(team.results).map(([date, result]) => (
|
||||||
<li key={date}>
|
<li key={date}>
|
||||||
@ -47,6 +65,9 @@ const TeamResults = () => {
|
|||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
) : (
|
||||||
|
<p className="text-gray-500">No results available</p>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
|||||||
@ -2,8 +2,8 @@
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { io } from 'socket.io-client';
|
import { io } from 'socket.io-client';
|
||||||
|
|
||||||
const API_URL = 'http://localhost:5000/api';
|
const API_URL = 'http://localhost:3000/api';
|
||||||
const socket = io('http://localhost:5000');
|
const socket = io('http://localhost:3000');
|
||||||
|
|
||||||
export const DataService = {
|
export const DataService = {
|
||||||
// Get all teams
|
// Get all teams
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user