This commit is contained in:
Tomas Dvorak
2026-03-13 19:11:12 +01:00
parent e08858ba48
commit 323cc5fca6
97 changed files with 1402 additions and 7091 deletions
+7
View File
@@ -3,6 +3,7 @@
# VCS
.git
.git_backup
.gitignore
# Node / frontend
@@ -12,6 +13,12 @@ frontend/dist
frontend/.cache
frontend/.next
frontend/coverage
app/node_modules
app/build
landing/node_modules
landing/dist
eshop/frontend/node_modules
eshop/frontend/build
# Root-level node_modules if any
node_modules
+1
View File
@@ -43,6 +43,7 @@ go.work
# Frontend build files
frontend/.next/
frontend/out/
frontend/build/
# Uploads directory
/uploads/
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

+102 -102
View File
@@ -14,7 +14,7 @@
"@react-navigation/bottom-tabs": "^6.6.1",
"@react-navigation/native": "^6.1.18",
"@react-navigation/native-stack": "^6.11.0",
"axios": "^1.6.8",
"axios": "^1.13.6",
"expo": "~51.0.8",
"expo-build-properties": "~0.12.5",
"expo-camera": "~15.0.13",
@@ -25,7 +25,7 @@
"react": "18.2.0",
"react-native": "0.74.5",
"react-native-animated-pagination-dot": "^0.4.0",
"react-native-device-info": "^15.0.1",
"react-native-device-info": "^15.0.2",
"react-native-gesture-handler": "~2.16.1",
"react-native-haptic-feedback": "^2.3.3",
"react-native-linear-gradient": "^2.8.3",
@@ -36,18 +36,17 @@
"react-native-svg": "15.2.0"
},
"devDependencies": {
"@babel/core": "^7.24.7",
"@babel/core": "^7.29.0",
"@types/react": "~18.2.79",
"@types/react-native": "0.73.0",
"typescript": "~5.3.3"
}
},
"node_modules/@babel/code-frame": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.27.1.tgz",
"integrity": "sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==",
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.0.tgz",
"integrity": "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==",
"dependencies": {
"@babel/helper-validator-identifier": "^7.27.1",
"@babel/helper-validator-identifier": "^7.28.5",
"js-tokens": "^4.0.0",
"picocolors": "^1.1.1"
},
@@ -56,27 +55,27 @@
}
},
"node_modules/@babel/compat-data": {
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.28.5.tgz",
"integrity": "sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==",
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz",
"integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/core": {
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.28.5.tgz",
"integrity": "sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==",
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz",
"integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==",
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5",
"@babel/helper-compilation-targets": "^7.27.2",
"@babel/helper-module-transforms": "^7.28.3",
"@babel/helpers": "^7.28.4",
"@babel/parser": "^7.28.5",
"@babel/template": "^7.27.2",
"@babel/traverse": "^7.28.5",
"@babel/types": "^7.28.5",
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
"@babel/helper-compilation-targets": "^7.28.6",
"@babel/helper-module-transforms": "^7.28.6",
"@babel/helpers": "^7.28.6",
"@babel/parser": "^7.29.0",
"@babel/template": "^7.28.6",
"@babel/traverse": "^7.29.0",
"@babel/types": "^7.29.0",
"@jridgewell/remapping": "^2.3.5",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
@@ -93,12 +92,12 @@
}
},
"node_modules/@babel/generator": {
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.28.5.tgz",
"integrity": "sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==",
"version": "7.29.1",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz",
"integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==",
"dependencies": {
"@babel/parser": "^7.28.5",
"@babel/types": "^7.28.5",
"@babel/parser": "^7.29.0",
"@babel/types": "^7.29.0",
"@jridgewell/gen-mapping": "^0.3.12",
"@jridgewell/trace-mapping": "^0.3.28",
"jsesc": "^3.0.2"
@@ -119,11 +118,11 @@
}
},
"node_modules/@babel/helper-compilation-targets": {
"version": "7.27.2",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.27.2.tgz",
"integrity": "sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==",
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz",
"integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==",
"dependencies": {
"@babel/compat-data": "^7.27.2",
"@babel/compat-data": "^7.28.6",
"@babel/helper-validator-option": "^7.27.1",
"browserslist": "^4.24.0",
"lru-cache": "^5.1.1",
@@ -216,25 +215,25 @@
}
},
"node_modules/@babel/helper-module-imports": {
"version": "7.27.1",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.27.1.tgz",
"integrity": "sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==",
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz",
"integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==",
"dependencies": {
"@babel/traverse": "^7.27.1",
"@babel/types": "^7.27.1"
"@babel/traverse": "^7.28.6",
"@babel/types": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-transforms": {
"version": "7.28.3",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.3.tgz",
"integrity": "sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==",
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz",
"integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==",
"dependencies": {
"@babel/helper-module-imports": "^7.27.1",
"@babel/helper-validator-identifier": "^7.27.1",
"@babel/traverse": "^7.28.3"
"@babel/helper-module-imports": "^7.28.6",
"@babel/helper-validator-identifier": "^7.28.5",
"@babel/traverse": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
@@ -344,12 +343,12 @@
}
},
"node_modules/@babel/helpers": {
"version": "7.28.4",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.4.tgz",
"integrity": "sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==",
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz",
"integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==",
"dependencies": {
"@babel/template": "^7.27.2",
"@babel/types": "^7.28.4"
"@babel/template": "^7.28.6",
"@babel/types": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
@@ -434,11 +433,11 @@
}
},
"node_modules/@babel/parser": {
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.5.tgz",
"integrity": "sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==",
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.0.tgz",
"integrity": "sha512-IyDgFV5GeDUVX4YdF/3CPULtVGSXXMLh1xVIgdCgxApktqnQV0r7/8Nqthg+8YLGaAtdyIlo2qIdZrbCv4+7ww==",
"dependencies": {
"@babel/types": "^7.28.5"
"@babel/types": "^7.29.0"
},
"bin": {
"parser": "bin/babel-parser.js"
@@ -2008,29 +2007,29 @@
}
},
"node_modules/@babel/template": {
"version": "7.27.2",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.2.tgz",
"integrity": "sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==",
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz",
"integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==",
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/parser": "^7.27.2",
"@babel/types": "^7.27.1"
"@babel/code-frame": "^7.28.6",
"@babel/parser": "^7.28.6",
"@babel/types": "^7.28.6"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.28.5.tgz",
"integrity": "sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==",
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz",
"integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==",
"dependencies": {
"@babel/code-frame": "^7.27.1",
"@babel/generator": "^7.28.5",
"@babel/code-frame": "^7.29.0",
"@babel/generator": "^7.29.0",
"@babel/helper-globals": "^7.28.0",
"@babel/parser": "^7.28.5",
"@babel/template": "^7.27.2",
"@babel/types": "^7.28.5",
"@babel/parser": "^7.29.0",
"@babel/template": "^7.28.6",
"@babel/types": "^7.29.0",
"debug": "^4.3.1"
},
"engines": {
@@ -2038,9 +2037,9 @@
}
},
"node_modules/@babel/types": {
"version": "7.28.5",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.5.tgz",
"integrity": "sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==",
"version": "7.29.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz",
"integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==",
"dependencies": {
"@babel/helper-string-parser": "^7.27.1",
"@babel/helper-validator-identifier": "^7.28.5"
@@ -4842,16 +4841,6 @@
"csstype": "^3.0.2"
}
},
"node_modules/@types/react-native": {
"version": "0.73.0",
"resolved": "https://registry.npmjs.org/@types/react-native/-/react-native-0.73.0.tgz",
"integrity": "sha512-6ZRPQrYM72qYKGWidEttRe6M5DZBEV5F+MHMHqd4TTYx0tfkcdrUFGdef6CCxY0jXU7wldvd/zA/b0A/kTeJmA==",
"deprecated": "This is a stub types definition. react-native provides its own type definitions, so you do not need this installed.",
"dev": true,
"dependencies": {
"react-native": "*"
}
},
"node_modules/@types/stack-utils": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
@@ -5208,12 +5197,12 @@
}
},
"node_modules/axios": {
"version": "1.13.2",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz",
"integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==",
"version": "1.13.6",
"resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz",
"integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==",
"dependencies": {
"follow-redirects": "^1.15.6",
"form-data": "^4.0.4",
"follow-redirects": "^1.15.11",
"form-data": "^4.0.5",
"proxy-from-env": "^1.1.0"
}
},
@@ -5573,12 +5562,23 @@
"node": "^16.14.0 || >=18.0.0"
}
},
"node_modules/cacache/node_modules/balanced-match": {
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
"integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
"engines": {
"node": "18 || 20 || >=22"
}
},
"node_modules/cacache/node_modules/brace-expansion": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
"integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
"version": "5.0.4",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz",
"integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==",
"dependencies": {
"balanced-match": "^1.0.0"
"balanced-match": "^4.0.2"
},
"engines": {
"node": "18 || 20 || >=22"
}
},
"node_modules/cacache/node_modules/glob": {
@@ -5606,11 +5606,11 @@
"integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="
},
"node_modules/cacache/node_modules/minimatch": {
"version": "9.0.5",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz",
"integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==",
"version": "9.0.7",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.7.tgz",
"integrity": "sha512-MOwgjc8tfrpn5QQEvjijjmDVtMw2oL88ugTevzxQnzRLm6l3fVEF2gzU0kYeYYKD8C66+IdGX6peJ4MyUlUnPg==",
"dependencies": {
"brace-expansion": "^2.0.1"
"brace-expansion": "^5.0.2"
},
"engines": {
"node": ">=16 || 14 >=14.17"
@@ -7163,9 +7163,9 @@
]
},
"node_modules/fast-xml-parser": {
"version": "4.5.3",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.3.tgz",
"integrity": "sha512-RKihhV+SHsIUGXObeVy9AXiBbFwkVk7Syp8XgwN5U3JV416+Gwp/GO9i0JYKmikykgz/UHRrrV4ROuZEo/T0ig==",
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.4.tgz",
"integrity": "sha512-jE8ugADnYOBsu1uaoayVl1tVKAMNOXyjwvv2U6udEA2ORBhDooJDWoGxTkhd4Qn4yh59JVVt/pKXtjPwx9OguQ==",
"funding": [
{
"type": "github",
@@ -7173,7 +7173,7 @@
}
],
"dependencies": {
"strnum": "^1.1.1"
"strnum": "^1.0.5"
},
"bin": {
"fxparser": "src/cli/cli.js"
@@ -10136,9 +10136,9 @@
}
},
"node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.3.tgz",
"integrity": "sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==",
"dependencies": {
"brace-expansion": "^1.1.7"
},
@@ -11573,9 +11573,9 @@
"peer": true
},
"node_modules/react-native-device-info": {
"version": "15.0.1",
"resolved": "https://registry.npmjs.org/react-native-device-info/-/react-native-device-info-15.0.1.tgz",
"integrity": "sha512-U5waZRXtT3l1SgZpZMlIvMKPTkFZPH8W7Ks6GrJhdH723aUIPxjVer7cRSij1mvQdOAAYFJV/9BDzlC8apG89A==",
"version": "15.0.2",
"resolved": "https://registry.npmjs.org/react-native-device-info/-/react-native-device-info-15.0.2.tgz",
"integrity": "sha512-dd71eXG2l3Cwp66IvKNadMTB8fhU3PEjyVddI97sYan+D4bgIAUmgGDhbSOFvHcGavksb2U17kiQYaDiK2WK2g==",
"peerDependencies": {
"react-native": "*"
}
+12 -4
View File
@@ -17,7 +17,7 @@
"@react-navigation/bottom-tabs": "^6.6.1",
"@react-navigation/native": "^6.1.18",
"@react-navigation/native-stack": "^6.11.0",
"axios": "^1.6.8",
"axios": "^1.13.6",
"expo": "~51.0.8",
"expo-build-properties": "~0.12.5",
"expo-camera": "~15.0.13",
@@ -28,7 +28,7 @@
"react": "18.2.0",
"react-native": "0.74.5",
"react-native-animated-pagination-dot": "^0.4.0",
"react-native-device-info": "^15.0.1",
"react-native-device-info": "^15.0.2",
"react-native-gesture-handler": "~2.16.1",
"react-native-haptic-feedback": "^2.3.3",
"react-native-linear-gradient": "^2.8.3",
@@ -39,9 +39,17 @@
"react-native-svg": "15.2.0"
},
"devDependencies": {
"@babel/core": "^7.24.7",
"@babel/core": "^7.29.0",
"@types/react": "~18.2.79",
"@types/react-native": "0.73.0",
"typescript": "~5.3.3"
},
"overrides": {
"fast-xml-parser": "4.5.4",
"glob@10": {
"minimatch": "9.0.7"
},
"glob@7": {
"minimatch": "3.1.3"
}
}
}
+1 -1
View File
@@ -11,7 +11,7 @@ import { isFanLogged, isAdminLogged } from './services/auth';
const AppContent = () => {
const { pinnedClub, isClubReady } = useClub();
const { themeReady, theme } = useClubTheme(pinnedClub);
const { themeReady, theme } = useClubTheme(pinnedClub ?? undefined);
useEffect(() => {
// Initialize push notifications when club is ready
+1 -1
View File
@@ -175,7 +175,7 @@ export const ModernInput: React.FC<ModernInputProps> = ({
{label && <Text style={{ fontSize: 14, fontWeight: '600', marginBottom: 8, color: '#374151' }}>{label}</Text>}
<View style={[
{ flexDirection: 'row', alignItems: 'center', borderWidth: 1, borderRadius: 12, paddingHorizontal: 16, paddingVertical: 12, backgroundColor: '#FFFFFF' },
error && { borderWidth: 2, borderColor: '#EF4444' },
Boolean(error) && { borderWidth: 2, borderColor: '#EF4444' },
!error && { borderColor: theme.primary + '30' }
]}>
{icon && <Text style={{ marginRight: 12, fontSize: 16 }}>{icon}</Text>}
+3 -3
View File
@@ -36,14 +36,14 @@ const TicketScreen: React.FC = () => {
return (
<ScrollView contentContainerStyle={styles.container}>
<Text style={styles.title}>{ticket.campaignTitle}</Text>
<Text style={styles.title}>{ticket.event}</Text>
<Text style={styles.sub}>QR průkaz pro vstup</Text>
<View style={styles.qrBox}>
<QRCode value={JSON.stringify(ticket)} size={240} backgroundColor="#fff" color="#000" />
</View>
<Text style={styles.code}>Kód: {ticket.barcode}</Text>
<Text style={styles.info}>Držitel: {ticket.holderName}</Text>
{ticket.matchDateTime && <Text style={styles.info}>Datum: {ticket.matchDateTime}</Text>}
<Text style={styles.info}>Držitel: {ticket.holder}</Text>
{ticket.date && <Text style={styles.info}>Datum: {ticket.date}</Text>}
{ticket.venue && <Text style={styles.info}>Místo: {ticket.venue}</Text>}
<TouchableOpacity style={styles.button} onPress={() => { /* TODO: add Wallet pass later */ }}>
<Text style={styles.buttonText}>Uložit / sdílet</Text>
+2 -2
View File
@@ -1,5 +1,5 @@
import AsyncStorage from '@react-native-async-storage/async-storage';
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
import axios, { AxiosInstance, AxiosResponse, InternalAxiosRequestConfig } from 'axios';
import Constants from 'expo-constants';
import * as Linking from 'expo-linking';
@@ -50,7 +50,7 @@ export async function getApi(): Promise<AxiosInstance> {
timeout: 15000,
});
apiInstance.interceptors.request.use((config: AxiosRequestConfig) => config);
apiInstance.interceptors.request.use((config: InternalAxiosRequestConfig) => config);
apiInstance.interceptors.response.use(
(resp: AxiosResponse) => resp,
(err) => Promise.reject(err)
+1 -1
View File
@@ -1 +1 @@
{"etag":"","fetched_at":"2026-03-13T16:17:10Z","last_modified":""}
{"etag":"","fetched_at":"2026-03-13T17:47:16Z","last_modified":""}
+1 -1
View File
@@ -1 +1 @@
{"etag":"","fetched_at":"2026-03-13T16:17:10Z","last_modified":""}
{"etag":"","fetched_at":"2026-03-13T17:47:16Z","last_modified":""}
+1 -1
View File
@@ -1 +1 @@
{"etag":"","fetched_at":"2026-03-13T16:17:10Z","last_modified":""}
{"etag":"","fetched_at":"2026-03-13T17:47:16Z","last_modified":""}
+1 -1
View File
@@ -1 +1 @@
{"lastUpdated":"2026-03-13T16:17:10Z"}
{"lastUpdated":"2026-03-13T17:47:16Z"}
+17 -17
View File
@@ -1,22 +1,7 @@
{
"baseURL": "http://localhost:8080/api/v1",
"duration_ms": 94,
"duration_ms": 29,
"endpoints": [
{
"path": "/articles?page=1\u0026page_size=10\u0026published=true",
"file": "articles.json",
"ok": true
},
{
"path": "/sponsors",
"file": "sponsors.json",
"ok": true
},
{
"path": "/events/upcoming",
"file": "events_upcoming.json",
"ok": true
},
{
"path": "/public/team-logo-overrides",
"file": "team_logo_overrides.json",
@@ -36,7 +21,22 @@
"path": "/seo",
"file": "seo.json",
"ok": true
},
{
"path": "/articles?page=1\u0026page_size=10\u0026published=true",
"file": "articles.json",
"ok": true
},
{
"path": "/sponsors",
"file": "sponsors.json",
"ok": true
},
{
"path": "/events/upcoming",
"file": "events_upcoming.json",
"ok": true
}
],
"lastUpdated": "2026-03-13T16:17:10Z"
"lastUpdated": "2026-03-13T17:47:16Z"
}
+1 -1
View File
@@ -1 +1 @@
{"etag":"","fetched_at":"2026-03-13T16:17:10Z","last_modified":""}
{"etag":"","fetched_at":"2026-03-13T17:47:16Z","last_modified":""}
+1 -1
View File
@@ -1 +1 @@
{"etag":"","fetched_at":"2026-03-13T16:17:10Z","last_modified":""}
{"etag":"","fetched_at":"2026-03-13T17:47:16Z","last_modified":""}
+1 -1
View File
@@ -1 +1 @@
{"etag":"","fetched_at":"2026-03-13T16:17:10Z","last_modified":""}
{"etag":"","fetched_at":"2026-03-13T17:47:16Z","last_modified":""}
+1 -1
View File
@@ -1 +1 @@
{"etag":"","fetched_at":"2026-03-13T16:17:10Z","last_modified":""}
{"etag":"","fetched_at":"2026-03-13T17:47:16Z","last_modified":""}
+1 -1
View File
@@ -1,4 +1,4 @@
{
"fetched_at": "2026-03-13T16:17:09Z",
"fetched_at": "2026-03-13T17:47:16Z",
"link": ""
}
-10
View File
@@ -1,10 +0,0 @@
{
"files": {
"main.js": "/static/js/main.590e0c36.js",
"index.html": "/index.html",
"main.590e0c36.js.map": "/static/js/main.590e0c36.js.map"
},
"entrypoints": [
"static/js/main.590e0c36.js"
]
}
+14 -1
View File
@@ -1 +1,14 @@
<!doctype html><html lang="cs"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#1a365d"/><title>MyClub E-shop</title><script defer="defer" src="/static/js/main.590e0c36.js"></script></head><body><noscript>Pro zobrazení e-shopu je potřeba povolit JavaScript.</noscript><div id="root"></div></body></html>
<!DOCTYPE html>
<html lang="cs">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#1a365d" />
<title>MyClub E-shop</title>
<script type="module" crossorigin src="/static/index-D1MwVPqi.js"></script>
</head>
<body>
<noscript>Pro zobrazení e-shopu je potřeba povolit JavaScript.</noscript>
<div id="root"></div>
</body>
</html>
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,91 +0,0 @@
/**
* @license React
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @license React
* use-sync-external-store-shim.production.js
*
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/**
* @remix-run/router v1.23.1
*
* Copyright (c) Remix Software Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
*/
/**
* React Router DOM v6.30.2
*
* Copyright (c) Remix Software Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
*/
/**
* React Router v6.30.2
*
* Copyright (c) Remix Software Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE.md file in the root directory of this source tree.
*
* @license MIT
*/
/** @license React v16.13.1
* react-is.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
File diff suppressed because one or more lines are too long
+34 -62
View File
@@ -11,21 +11,20 @@
"@chakra-ui/react": "^2.8.2",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@stripe/react-stripe-js": "^5.4.1",
"@stripe/stripe-js": "^8.5.3",
"@tanstack/react-query": "^4.36.1",
"@stripe/react-stripe-js": "^5.6.1",
"@stripe/stripe-js": "^8.9.0",
"@tanstack/react-query": "^4.43.0",
"axios": "^1.13.6",
"dompurify": "^3.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^5.5.0",
"react-router-dom": "^6.30.2",
"react-icons": "^5.6.0",
"react-router-dom": "^6.30.3",
"typescript": "^4.9.5"
},
"devDependencies": {
"@types/react": "^18.2.45",
"@types/react-dom": "^18.2.18",
"@types/react-router-dom": "^5.3.3",
"@vitejs/plugin-react": "^4.4.1",
"jsdom": "^26.1.0",
"vite": "^6.3.5",
@@ -1148,9 +1147,9 @@
}
},
"node_modules/@remix-run/router": {
"version": "1.23.1",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.1.tgz",
"integrity": "sha512-vDbaOzF7yT2Qs4vO6XV1MHcJv+3dgR1sT+l3B8xxOVhUC336prMvqrvsLL/9Dnw2xr6Qhz4J0dmS0llNAbnUmQ==",
"version": "1.23.2",
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.23.2.tgz",
"integrity": "sha512-Ic6m2U/rMjTkhERIa/0ZtXJP17QUi2CbWE7cqx4J58M8aA3QTfW+2UlQ4psvTX9IO1RfNVhK3pcpdjej7L+t2w==",
"engines": {
"node": ">=14.0.0"
}
@@ -1487,9 +1486,9 @@
]
},
"node_modules/@stripe/react-stripe-js": {
"version": "5.4.1",
"resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-5.4.1.tgz",
"integrity": "sha512-ipeYcAHa4EPmjwfv0lFE+YDVkOQ0TMKkFWamW+BqmnSkEln/hO8rmxGPPWcd9WjqABx6Ro8Xg4pAS7evCcR9cw==",
"version": "5.6.1",
"resolved": "https://registry.npmjs.org/@stripe/react-stripe-js/-/react-stripe-js-5.6.1.tgz",
"integrity": "sha512-5xBrjkGmFvKvpMod6VvpOaFaa67eRbmieKeFTePZyOr/sUXzm7A3YY91l330pS0usUst5PxTZDUZHWfOc0v1GA==",
"dependencies": {
"prop-types": "^15.7.2"
},
@@ -1500,29 +1499,29 @@
}
},
"node_modules/@stripe/stripe-js": {
"version": "8.5.3",
"resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-8.5.3.tgz",
"integrity": "sha512-UM0GHAxlTN7v0lCK2P6t0VOlvBIdApIQxhnM3yZ2kupQ4PpSrLsK/n/NyYKtw2NJGMaNRRD1IicWS7fSL2sFtA==",
"version": "8.9.0",
"resolved": "https://registry.npmjs.org/@stripe/stripe-js/-/stripe-js-8.9.0.tgz",
"integrity": "sha512-OJkXvUI5GAc56QdiSRimQDvWYEqn475J+oj8RzRtFTCPtkJNO2TWW619oDY+nn1ExR+2tCVTQuRQBbR4dRugww==",
"engines": {
"node": ">=12.16"
}
},
"node_modules/@tanstack/query-core": {
"version": "4.41.0",
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.41.0.tgz",
"integrity": "sha512-193R4Jp9hjvlij6LryxrB5Mpbffd2L9PeWh3KlIy/hJV4SkBOfiQZ+jc5qAZLDCrdbkA5FjGj+UoDYw6TcNnyA==",
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-4.43.0.tgz",
"integrity": "sha512-m1QeUUIpNXDYxmfuuWNFZLky0EwVmbE0hj8ulZ2nIGA1183raJgDCn0IKlxug80NotRqzodxAaoYTKHbE1/P/Q==",
"funding": {
"type": "github",
"url": "https://github.com/sponsors/tannerlinsley"
}
},
"node_modules/@tanstack/react-query": {
"version": "4.42.0",
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.42.0.tgz",
"integrity": "sha512-j0tiofkzE3CSrYKmVRaKuwGgvCE+P2OOEDlhmfjeZf5ufcuFHwYwwgw3j08n4WYPVZ+OpsHblcFYezhKA3jDwg==",
"version": "4.43.0",
"resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-4.43.0.tgz",
"integrity": "sha512-Lj8luFKHQL27oZbw5T8xdTbsfAPp2+bCtSCa2bAVvIwnvNfRP0hpB1GxfKFgCktat8lPcYBHAu8eMTXzz2sQtQ==",
"dependencies": {
"@tanstack/query-core": "4.41.0",
"use-sync-external-store": "^1.2.0"
"@tanstack/query-core": "4.43.0",
"use-sync-external-store": "^1.6.0"
},
"funding": {
"type": "github",
@@ -1605,12 +1604,6 @@
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
"dev": true
},
"node_modules/@types/history": {
"version": "4.7.11",
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz",
"integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==",
"dev": true
},
"node_modules/@types/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.21.tgz",
@@ -1665,27 +1658,6 @@
"@types/react": "^18.0.0"
}
},
"node_modules/@types/react-router": {
"version": "5.1.20",
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz",
"integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==",
"dev": true,
"dependencies": {
"@types/history": "^4.7.11",
"@types/react": "*"
}
},
"node_modules/@types/react-router-dom": {
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz",
"integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==",
"dev": true,
"dependencies": {
"@types/history": "^4.7.11",
"@types/react": "*",
"@types/react-router": "*"
}
},
"node_modules/@types/trusted-types": {
"version": "2.0.7",
"resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
@@ -3061,9 +3033,9 @@
}
},
"node_modules/react-icons": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.5.0.tgz",
"integrity": "sha512-MEFcXdkP3dLo8uumGI5xN3lDFNsRtrjbOEKDLD7yv76v4wpnEq2Lt2qeHaQOr34I/wPN3s3+N08WkQ+CW37Xiw==",
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.6.0.tgz",
"integrity": "sha512-RH93p5ki6LfOiIt0UtDyNg/cee+HLVR6cHHtW3wALfo+eOHTp8RnU2kRkI6E+H19zMIs03DyxUG/GfZMOGvmiA==",
"peerDependencies": {
"react": "*"
}
@@ -3119,11 +3091,11 @@
}
},
"node_modules/react-router": {
"version": "6.30.2",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.2.tgz",
"integrity": "sha512-H2Bm38Zu1bm8KUE5NVWRMzuIyAV8p/JrOaBJAwVmp37AXG72+CZJlEBw6pdn9i5TBgLMhNDgijS4ZlblpHyWTA==",
"version": "6.30.3",
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.30.3.tgz",
"integrity": "sha512-XRnlbKMTmktBkjCLE8/XcZFlnHvr2Ltdr1eJX4idL55/9BbORzyZEaIkBFDhFGCEWBBItsVrDxwx3gnisMitdw==",
"dependencies": {
"@remix-run/router": "1.23.1"
"@remix-run/router": "1.23.2"
},
"engines": {
"node": ">=14.0.0"
@@ -3133,12 +3105,12 @@
}
},
"node_modules/react-router-dom": {
"version": "6.30.2",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.2.tgz",
"integrity": "sha512-l2OwHn3UUnEVUqc6/1VMmR1cvZryZ3j3NzapC2eUXO1dB0sYp5mvwdjiXhpUbRb21eFow3qSxpP8Yv6oAU824Q==",
"version": "6.30.3",
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.30.3.tgz",
"integrity": "sha512-pxPcv1AczD4vso7G4Z3TKcvlxK7g7TNt3/FNGMhfqyntocvYKj+GCatfigGDjbLozC4baguJ0ReCigoDJXb0ag==",
"dependencies": {
"@remix-run/router": "1.23.1",
"react-router": "6.30.2"
"@remix-run/router": "1.23.2",
"react-router": "6.30.3"
},
"engines": {
"node": ">=14.0.0"
+5 -6
View File
@@ -13,21 +13,20 @@
"@chakra-ui/react": "^2.8.2",
"@emotion/react": "^11.11.1",
"@emotion/styled": "^11.11.0",
"@stripe/react-stripe-js": "^5.4.1",
"@stripe/stripe-js": "^8.5.3",
"@tanstack/react-query": "^4.36.1",
"@stripe/react-stripe-js": "^5.6.1",
"@stripe/stripe-js": "^8.9.0",
"@tanstack/react-query": "^4.43.0",
"axios": "^1.13.6",
"dompurify": "^3.3.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^5.5.0",
"react-router-dom": "^6.30.2",
"react-icons": "^5.6.0",
"react-router-dom": "^6.30.3",
"typescript": "^4.9.5"
},
"devDependencies": {
"@types/react": "^18.2.45",
"@types/react-dom": "^18.2.18",
"@types/react-router-dom": "^5.3.3",
"@vitejs/plugin-react": "^4.4.1",
"jsdom": "^26.1.0",
"vite": "^6.3.5",
-58
View File
@@ -1,58 +0,0 @@
{
"files": {
"main.css": "/static/css/main.e9950038.css",
"main.js": "/static/js/main.dd323bc8.js",
"runtime.js": "/static/js/runtime.0b5f0839.js",
"static/js/469.ec731235.chunk.js": "/static/js/469.ec731235.chunk.js",
"static/js/910.bec7c150.chunk.js": "/static/js/910.bec7c150.chunk.js",
"static/js/154.a93817c6.chunk.js": "/static/js/154.a93817c6.chunk.js",
"static/js/771.2b2378c2.chunk.js": "/static/js/771.2b2378c2.chunk.js",
"static/js/558.0464ebe3.chunk.js": "/static/js/558.0464ebe3.chunk.js",
"static/js/334.0d196877.chunk.js": "/static/js/334.0d196877.chunk.js",
"static/js/118.8a550f36.chunk.js": "/static/js/118.8a550f36.chunk.js",
"static/js/339.c1ec8d08.chunk.js": "/static/js/339.c1ec8d08.chunk.js",
"static/js/158.c7e50479.chunk.js": "/static/js/158.c7e50479.chunk.js",
"static/js/798.21001033.chunk.js": "/static/js/798.21001033.chunk.js",
"static/js/620.edc51951.chunk.js": "/static/js/620.edc51951.chunk.js",
"static/js/548.da462cb8.chunk.js": "/static/js/548.da462cb8.chunk.js",
"static/js/501.0b99fbb0.chunk.js": "/static/js/501.0b99fbb0.chunk.js",
"static/js/266.e18a46b8.chunk.js": "/static/js/266.e18a46b8.chunk.js",
"static/js/452.bad3d00e.chunk.js": "/static/js/452.bad3d00e.chunk.js",
"static/js/791.2cae987d.chunk.js": "/static/js/791.2cae987d.chunk.js",
"static/js/579.f8a21d69.chunk.js": "/static/js/579.f8a21d69.chunk.js",
"static/js/453.d9749a7d.chunk.js": "/static/js/453.d9749a7d.chunk.js",
"static/css/664.02d4d120.css": "/static/css/664.02d4d120.css",
"static/js/664.d9b6a63b.js": "/static/js/664.d9b6a63b.js",
"index.html": "/index.html",
"main.e9950038.css.map": "/static/css/main.e9950038.css.map",
"main.dd323bc8.js.map": "/static/js/main.dd323bc8.js.map",
"runtime.0b5f0839.js.map": "/static/js/runtime.0b5f0839.js.map",
"469.ec731235.chunk.js.map": "/static/js/469.ec731235.chunk.js.map",
"910.bec7c150.chunk.js.map": "/static/js/910.bec7c150.chunk.js.map",
"154.a93817c6.chunk.js.map": "/static/js/154.a93817c6.chunk.js.map",
"771.2b2378c2.chunk.js.map": "/static/js/771.2b2378c2.chunk.js.map",
"558.0464ebe3.chunk.js.map": "/static/js/558.0464ebe3.chunk.js.map",
"334.0d196877.chunk.js.map": "/static/js/334.0d196877.chunk.js.map",
"118.8a550f36.chunk.js.map": "/static/js/118.8a550f36.chunk.js.map",
"339.c1ec8d08.chunk.js.map": "/static/js/339.c1ec8d08.chunk.js.map",
"158.c7e50479.chunk.js.map": "/static/js/158.c7e50479.chunk.js.map",
"798.21001033.chunk.js.map": "/static/js/798.21001033.chunk.js.map",
"620.edc51951.chunk.js.map": "/static/js/620.edc51951.chunk.js.map",
"548.da462cb8.chunk.js.map": "/static/js/548.da462cb8.chunk.js.map",
"501.0b99fbb0.chunk.js.map": "/static/js/501.0b99fbb0.chunk.js.map",
"266.e18a46b8.chunk.js.map": "/static/js/266.e18a46b8.chunk.js.map",
"452.bad3d00e.chunk.js.map": "/static/js/452.bad3d00e.chunk.js.map",
"791.2cae987d.chunk.js.map": "/static/js/791.2cae987d.chunk.js.map",
"579.f8a21d69.chunk.js.map": "/static/js/579.f8a21d69.chunk.js.map",
"453.d9749a7d.chunk.js.map": "/static/js/453.d9749a7d.chunk.js.map",
"664.02d4d120.css.map": "/static/css/664.02d4d120.css.map",
"664.d9b6a63b.js.map": "/static/js/664.d9b6a63b.js.map"
},
"entrypoints": [
"static/js/runtime.0b5f0839.js",
"static/css/664.02d4d120.css",
"static/js/664.d9b6a63b.js",
"static/css/main.e9950038.css",
"static/js/main.dd323bc8.js"
]
}
+29 -1
View File
@@ -1 +1,29 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover"/><meta name="theme-color" content="#000000"/><meta name="color-scheme" content="light dark"/><meta name="description" content="Oficiální webové stránky fotbalového klubu - aktuality, zápasy, tabulky, hráči a fotogalerie"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com" crossorigin/><link rel="preconnect" href="https://www.youtube.com" crossorigin/><link rel="preconnect" href="https://i.ytimg.com" crossorigin/><link rel="preconnect" href="https://s.ytimg.com" crossorigin/><link rel="preconnect" href="https://www.google.com" crossorigin/><title>Fotbal Club</title><script defer="defer" src="/static/js/runtime.0b5f0839.js"></script><script defer="defer" src="/static/js/664.d9b6a63b.js"></script><script defer="defer" src="/static/js/main.dd323bc8.js"></script><link href="/static/css/664.02d4d120.css" rel="stylesheet"><link href="/static/css/main.e9950038.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
<meta name="theme-color" content="#000000" />
<meta name="color-scheme" content="light dark" />
<meta
name="description"
content="Oficiální webové stránky fotbalového klubu - aktuality, zápasy, tabulky, hráči a fotogalerie"
/>
<link rel="apple-touch-icon" href="/logo192.png" />
<link rel="manifest" href="/manifest.json" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link rel="preconnect" href="https://www.youtube.com" crossorigin />
<link rel="preconnect" href="https://i.ytimg.com" crossorigin />
<link rel="preconnect" href="https://s.ytimg.com" crossorigin />
<link rel="preconnect" href="https://www.google.com" crossorigin />
<title>Fotbal Club</title>
<script type="module" crossorigin src="/static/index-CLCx9azl.js"></script>
<link rel="stylesheet" crossorigin href="/static/index-BHzfWAR3.css">
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>
</html>
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

+26 -1
View File
@@ -1 +1,26 @@
{"short_name": "Fotbal Club", "name": "Fotbal Club - Oficiální aplikace", "description": "Oficiální webové stránky fotbalového klubu - aktuality, zápasy, tabulky, hráči a fotogalerie", "icons": [{"src": "favicon.ico", "sizes": "64x64 32x32 24x24 16x16", "type": "image/x-icon"}, {"src": "logo192.png", "type": "image/png", "sizes": "192x192"}, {"src": "logo512.png", "type": "image/png", "sizes": "512x512"}], "start_url": ".", "display": "standalone", "theme_color": "#000000", "background_color": "#ffffff"}
{
"short_name": "Fotbal Club",
"name": "Fotbal Club - Oficiální aplikace",
"description": "Oficiální webové stránky fotbalového klubu - aktuality, zápasy, tabulky, hráči a fotogalerie",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png?v=2",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png?v=2",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
+5 -5
View File
@@ -1,7 +1,7 @@
/* eslint-disable no-restricted-globals */
// Service Worker for PWA support and offline functionality
const CACHE_VERSION = 'v1.0.2';
const CACHE_VERSION = 'v1.0.3';
const CACHE_NAME = `fotbal-club-cache-${CACHE_VERSION}`;
// Rate limiting for background updates
@@ -14,8 +14,8 @@ const STATIC_ASSETS = [
'/index.html',
'/manifest.json',
'/favicon.ico',
'/logo192.png',
'/logo512.png',
'/logo192.png?v=2',
'/logo512.png?v=2',
'/robots.txt',
];
@@ -266,8 +266,8 @@ self.addEventListener('push', (event) => {
const title = data.title || 'Fotbal Club';
const options = {
body: data.body || 'Nová notifikace',
icon: '/logo192.png',
badge: '/logo192.png',
icon: '/logo192.png?v=2',
badge: '/logo192.png?v=2',
data: data.url || '/',
};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,2 +0,0 @@
"use strict";(self.webpackChunkfrontend=self.webpackChunkfrontend||[]).push([[118],{58118:(e,t,r)=>{r.r(t),r.d(t,{default:()=>m});var o=r(65043),s=r(22107),n=r(98662),i=r(25011),a=r(10202),l=r(28846),c=r(39081),h=r(1009),u=r(70579);class d extends o.Component{constructor(e){super(e),this.resetTimeout=null,this.scheduleAutoReset=()=>{this.resetTimeout&&clearTimeout(this.resetTimeout),this.resetTimeout=setTimeout(()=>{this.handleReset()},3e3)},this.handleReset=()=>{this.resetTimeout&&(clearTimeout(this.resetTimeout),this.resetTimeout=null),this.cleanupDOMElements(),this.setState({hasError:!1,error:null,errorInfo:null}),this.props.onReset&&this.props.onReset()},this.cleanupDOMElements=()=>{try{document.querySelectorAll(".elementor-overlay").forEach(e=>{try{e.remove()}catch(t){console.warn("Failed to remove overlay:",t)}});const c=document.querySelector(".myuibrix-viewport-wrapper");if(c&&c.parentElement)try{const l=c.parentElement;if(l.hasAttribute("data-myuibrix-restore"))Array.from(c.children).forEach(e=>{try{l.appendChild(e)}catch(t){console.warn("Failed to move child:",t)}}),c.remove(),l.removeAttribute("data-myuibrix-restore");else{try{c.classList.remove("myuibrix-viewport-wrapper")}catch(e){}try{c.removeAttribute("data-myuibrix-wrapped")}catch(t){}try{c.style.width=""}catch(r){}try{c.style.maxWidth=""}catch(o){}try{c.style.transition=""}catch(s){}try{c.style.margin=""}catch(n){}try{c.style.transform=""}catch(i){}try{c.style.transformOrigin=""}catch(a){}}}catch(l){console.warn("Failed to cleanup viewport wrapper:",l)}document.body.style.paddingTop="0",document.body.style.backgroundColor="",document.body.style.userSelect=""}catch(l){console.error("Error during DOM cleanup:",l)}},this.state={hasError:!1,error:null,errorInfo:null,errorCount:0}}static getDerivedStateFromError(e){return{hasError:!0,error:e}}componentDidCatch(e,t){console.error("MyUIbrix Error Boundary caught an error:",e,t),this.setState(e=>({errorInfo:t,errorCount:e.errorCount+1})),(e.message.includes("removeChild")||e.message.includes("insertBefore")||e.message.includes("replaceChild")||"DOMException"===e.name)&&(console.warn("DOM manipulation error detected - will auto-reset in 3 seconds"),this.scheduleAutoReset())}componentWillUnmount(){this.resetTimeout&&clearTimeout(this.resetTimeout)}render(){if(this.state.hasError&&this.state.error){const e=this.state.error.message.includes("removeChild")||this.state.error.message.includes("insertBefore")||this.state.error.message.includes("replaceChild")||"DOMException"===this.state.error.name;return(0,u.jsx)(s.a,{position:"fixed",top:"0",left:"0",right:"0",bottom:"0",bg:"rgba(0, 0, 0, 0.85)",backdropFilter:"blur(8px)",display:"flex",alignItems:"center",justifyContent:"center",zIndex:99999,children:(0,u.jsxs)(a.T,{spacing:6,bg:"white",p:8,borderRadius:"2xl",boxShadow:"0 20px 60px rgba(0,0,0,0.5)",maxW:"600px",w:"90%",children:[(0,u.jsx)(i.I,{as:h.eHT,boxSize:16,color:"orange.500"}),(0,u.jsxs)(a.T,{spacing:2,children:[(0,u.jsx)(l.D,{size:"lg",color:"gray.800",children:e?"Chyba p\u0159i manipulaci s prvky":"Chyba editoru"}),(0,u.jsx)(c.E,{color:"gray.600",textAlign:"center",children:e?"Nastala chyba p\u0159i p\u0159esouv\xe1n\xed nebo upravov\xe1n\xed prvk\u016f. Editor se automaticky obnov\xed za 3 sekundy.":"V editoru nastala neo\u010dek\xe1van\xe1 chyba. Klikn\u011bte na tla\u010d\xedtko pro obnoven\xed."})]}),!1,(0,u.jsxs)(a.T,{spacing:3,w:"100%",children:[(0,u.jsx)(n.$,{leftIcon:(0,u.jsx)(h.jTZ,{}),colorScheme:"blue",size:"lg",w:"100%",onClick:this.handleReset,children:"Obnovit editor"}),this.state.errorCount>3&&(0,u.jsxs)(c.E,{fontSize:"sm",color:"orange.600",textAlign:"center",children:["\u26a0\ufe0f Opakovan\xe9 chyby (",this.state.errorCount,"x). Zva\u017ete obnoven\xed str\xe1nky."]}),this.state.errorCount>3&&(0,u.jsx)(n.$,{size:"sm",variant:"ghost",colorScheme:"gray",onClick:()=>window.location.reload(),children:"Obnovit celou str\xe1nku"})]})]})})}return this.props.children}}const m=d}}]);
//# sourceMappingURL=118.8a550f36.chunk.js.map
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,2 +0,0 @@
"use strict";(self.webpackChunkfrontend=self.webpackChunkfrontend||[]).push([[453],{46453:(e,t,n)=>{n.r(t),n.d(t,{getCLS:()=>y,getFCP:()=>g,getFID:()=>C,getLCP:()=>P,getTTFB:()=>D});var i,r,a,o,u=function(e,t){return{name:e,value:void 0===t?-1:t,delta:0,entries:[],id:"v2-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12)}},c=function(e,t){try{if(PerformanceObserver.supportedEntryTypes.includes(e)){if("first-input"===e&&!("PerformanceEventTiming"in self))return;var n=new PerformanceObserver(function(e){return e.getEntries().map(t)});return n.observe({type:e,buffered:!0}),n}}catch(e){}},f=function(e,t){var n=function n(i){"pagehide"!==i.type&&"hidden"!==document.visibilityState||(e(i),t&&(removeEventListener("visibilitychange",n,!0),removeEventListener("pagehide",n,!0)))};addEventListener("visibilitychange",n,!0),addEventListener("pagehide",n,!0)},s=function(e){addEventListener("pageshow",function(t){t.persisted&&e(t)},!0)},m=function(e,t,n){var i;return function(r){t.value>=0&&(r||n)&&(t.delta=t.value-(i||0),(t.delta||void 0===i)&&(i=t.value,e(t)))}},v=-1,d=function(){return"hidden"===document.visibilityState?0:1/0},p=function(){f(function(e){var t=e.timeStamp;v=t},!0)},l=function(){return v<0&&(v=d(),p(),s(function(){setTimeout(function(){v=d(),p()},0)})),{get firstHiddenTime(){return v}}},g=function(e,t){var n,i=l(),r=u("FCP"),a=function(e){"first-contentful-paint"===e.name&&(f&&f.disconnect(),e.startTime<i.firstHiddenTime&&(r.value=e.startTime,r.entries.push(e),n(!0)))},o=window.performance&&performance.getEntriesByName&&performance.getEntriesByName("first-contentful-paint")[0],f=o?null:c("paint",a);(o||f)&&(n=m(e,r,t),o&&a(o),s(function(i){r=u("FCP"),n=m(e,r,t),requestAnimationFrame(function(){requestAnimationFrame(function(){r.value=performance.now()-i.timeStamp,n(!0)})})}))},h=!1,T=-1,y=function(e,t){h||(g(function(e){T=e.value}),h=!0);var n,i=function(t){T>-1&&e(t)},r=u("CLS",0),a=0,o=[],v=function(e){if(!e.hadRecentInput){var t=o[0],i=o[o.length-1];a&&e.startTime-i.startTime<1e3&&e.startTime-t.startTime<5e3?(a+=e.value,o.push(e)):(a=e.value,o=[e]),a>r.value&&(r.value=a,r.entries=o,n())}},d=c("layout-shift",v);d&&(n=m(i,r,t),f(function(){d.takeRecords().map(v),n(!0)}),s(function(){a=0,T=-1,r=u("CLS",0),n=m(i,r,t)}))},E={passive:!0,capture:!0},w=new Date,L=function(e,t){i||(i=t,r=e,a=new Date,F(removeEventListener),S())},S=function(){if(r>=0&&r<a-w){var e={entryType:"first-input",name:i.type,target:i.target,cancelable:i.cancelable,startTime:i.timeStamp,processingStart:i.timeStamp+r};o.forEach(function(t){t(e)}),o=[]}},b=function(e){if(e.cancelable){var t=(e.timeStamp>1e12?new Date:performance.now())-e.timeStamp;"pointerdown"==e.type?function(e,t){var n=function(){L(e,t),r()},i=function(){r()},r=function(){removeEventListener("pointerup",n,E),removeEventListener("pointercancel",i,E)};addEventListener("pointerup",n,E),addEventListener("pointercancel",i,E)}(t,e):L(t,e)}},F=function(e){["mousedown","keydown","touchstart","pointerdown"].forEach(function(t){return e(t,b,E)})},C=function(e,t){var n,a=l(),v=u("FID"),d=function(e){e.startTime<a.firstHiddenTime&&(v.value=e.processingStart-e.startTime,v.entries.push(e),n(!0))},p=c("first-input",d);n=m(e,v,t),p&&f(function(){p.takeRecords().map(d),p.disconnect()},!0),p&&s(function(){var a;v=u("FID"),n=m(e,v,t),o=[],r=-1,i=null,F(addEventListener),a=d,o.push(a),S()})},k={},P=function(e,t){var n,i=l(),r=u("LCP"),a=function(e){var t=e.startTime;t<i.firstHiddenTime&&(r.value=t,r.entries.push(e),n())},o=c("largest-contentful-paint",a);if(o){n=m(e,r,t);var v=function(){k[r.id]||(o.takeRecords().map(a),o.disconnect(),k[r.id]=!0,n(!0))};["keydown","click"].forEach(function(e){addEventListener(e,v,{once:!0,capture:!0})}),f(v,!0),s(function(i){r=u("LCP"),n=m(e,r,t),requestAnimationFrame(function(){requestAnimationFrame(function(){r.value=performance.now()-i.timeStamp,k[r.id]=!0,n(!0)})})})}},D=function(e){var t,n=u("TTFB");t=function(){try{var t=performance.getEntriesByType("navigation")[0]||function(){var e=performance.timing,t={entryType:"navigation",startTime:0};for(var n in e)"navigationStart"!==n&&"toJSON"!==n&&(t[n]=Math.max(e[n]-e.navigationStart,0));return t}();if(n.value=n.delta=t.responseStart,n.value<0||n.value>performance.now())return;n.entries=[t],e(n)}catch(e){}},"complete"===document.readyState?setTimeout(t,0):addEventListener("load",function(){return setTimeout(t,0)})}}}]);
//# sourceMappingURL=453.d9749a7d.chunk.js.map
File diff suppressed because one or more lines are too long
@@ -1,2 +0,0 @@
"use strict";(self.webpackChunkfrontend=self.webpackChunkfrontend||[]).push([[469],{69469:(e,r,t)=>{t.r(r),t.d(r,{default:()=>c});var a=t(89379),n=(t(65043),t(22107)),i=t(7189),o=t(25189),l=t(70579);const c=e=>{let{banners:r,placement:t,containerStyle:c}=e;const s=(r||[]).filter(e=>e.placement===t&&!1!==e.is_active);if(0===s.length)return null;const d=(0,a.A)((0,a.A)({},(()=>{const e={margin:"24px 0",display:"flex",justifyContent:"center",alignItems:"center",gap:"16px",flexWrap:"wrap"};switch(t){case"homepage_top":return(0,a.A)((0,a.A)({},e),{},{width:"100vw",position:"relative",left:"50%",right:"50%",marginLeft:"-50vw",marginRight:"-50vw",backgroundColor:"rgba(0, 0, 0, 0.02)",padding:"16px",borderTop:"1px solid rgba(0, 0, 0, 0.05)",borderBottom:"1px solid rgba(0, 0, 0, 0.05)"});case"homepage_footer":return(0,a.A)((0,a.A)({},e),{},{width:"100vw",position:"relative",left:"50%",right:"50%",marginLeft:"-50vw",marginRight:"-50vw",backgroundColor:"rgba(0, 0, 0, 0.02)",padding:"24px 16px",borderTop:"1px solid rgba(0, 0, 0, 0.05)"});case"homepage_under_table":return(0,a.A)((0,a.A)({},e),{},{margin:"12px 0 0",justifyContent:"center"});default:return e}})()),c);return(0,l.jsx)(n.a,{as:"section",className:(()=>{switch(t){case"homepage_top":return"banner-top";case"homepage_middle":return"banner-middle";case"homepage_footer":return"banner-footer";case"article_inline":return"banner-article";case"homepage_under_table":return"banner-under-table";default:return"banner"}})(),sx:d,children:s.map(e=>(0,l.jsx)(i.N,{href:e.url||e.click_url||"#",isExternal:!(!e.url&&!e.click_url),target:e.url||e.click_url?"_blank":void 0,rel:e.url||e.click_url?"noopener noreferrer":void 0,display:"inline-block",_hover:{opacity:.9,transform:"translateY(-2px)"},transition:"all 0.2s",children:(0,l.jsx)("img",{src:(0,o.uq)(e.image||e.image_url||"")||e.image||e.image_url||"",alt:e.name,style:{maxWidth:"100%",width:e.width?"".concat(e.width,"px"):"auto",height:e.height?"".concat(e.height,"px"):"auto",objectFit:"contain",borderRadius:"4px",boxShadow:"none"},loading:"lazy"})},e.id))})}}}]);
//# sourceMappingURL=469.ec731235.chunk.js.map
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,2 +0,0 @@
"use strict";(self.webpackChunkfrontend=self.webpackChunkfrontend||[]).push([[771],{69771:(e,l,s)=>{s.r(l),s.d(l,{default:()=>x});s(65043);var a=s(22107),n=s(44093),i=s(76659),t=s(10202),d=s(28846),r=s(39081),c=s(72526),o=s(71093),u=s(35349),p=s(70579);const x=e=>{let{featuredOnly:l=!0,maxPolls:s=1,title:x="Hlasov\xe1n\xed"}=e;const h=(0,n.dU)("gray.50","gray.900"),{data:g,isLoading:y}=(0,c.I)({queryKey:["polls",{featured:l}],queryFn:()=>(0,o.Ps)(l?{featured:!0}:void 0),staleTime:12e4}),f=(null===g||void 0===g?void 0:g.slice(0,s))||[],{data:j,isLoading:m}=(0,c.I)({queryKey:["polls-details",f.map(e=>e.id)],queryFn:async()=>{const e=f.map(e=>(0,o.gU)(e.id));return await Promise.all(e)},enabled:f.length>0});return y||m?(0,p.jsx)(a.a,{bg:h,py:12,px:4,children:(0,p.jsxs)(t.T,{spacing:4,children:[(0,p.jsx)(i.y,{size:"lg"}),(0,p.jsx)(r.E,{children:"Na\u010d\xedt\xe1n\xed ankety..."})]})}):j&&0!==j.length?(0,p.jsx)(a.a,{bg:h,py:12,px:4,children:(0,p.jsxs)(t.T,{spacing:8,maxW:"4xl",mx:"auto",children:[(0,p.jsx)(d.D,{size:"lg",textAlign:"center",children:x}),(0,p.jsx)(t.T,{spacing:6,w:"full",children:j.map(e=>(0,p.jsx)(a.a,{w:"full",maxW:"600px",children:(0,p.jsx)(u.A,{poll:e.poll,hasVoted:e.has_voted,isActive:e.is_active,canShowResults:e.can_show_results})},e.poll.id))})]})}):null}}}]);
//# sourceMappingURL=771.2b2378c2.chunk.js.map
@@ -1 +0,0 @@
{"version":3,"file":"static/js/771.2b2378c2.chunk.js","mappings":"6PAqBA,MAiEA,EAjEgDA,IAIzC,IAJ0C,aAC/CC,GAAe,EAAI,SACnBC,EAAW,EAAC,MACZC,EAAQ,mBACTH,EACC,MAAMI,GAAYC,EAAAA,EAAAA,IAAkB,UAAW,aAGvCC,KAAMC,EAAK,UAAEC,IAAcC,EAAAA,EAAAA,GAAS,CAC1CC,SAAU,CAAC,QAAS,CAAEC,SAAUV,IAChCW,QAASA,KAAMC,EAAAA,EAAAA,IAASZ,EAAe,CAAEU,UAAU,QAASG,GAC5DC,UAAW,OAIPC,GAAsB,OAALT,QAAK,IAALA,OAAK,EAALA,EAAOU,MAAM,EAAGf,KAAa,IAE5CI,KAAMY,EAAWV,UAAWW,IAAmBV,EAAAA,EAAAA,GAAS,CAC9DC,SAAU,CAAC,gBAAiBM,EAAeI,IAAKC,GAAMA,EAAEC,KACxDV,QAASW,UACP,MAAMC,EAAWR,EAAeI,IAAKK,IAASC,EAAAA,EAAAA,IAAQD,EAAKH,KAC3D,aAAaK,QAAQC,IAAIJ,IAE3BK,QAASb,EAAec,OAAS,IAGnC,OAAItB,GAAaW,GAEbY,EAAAA,EAAAA,KAACC,EAAAA,EAAG,CAACC,GAAI7B,EAAW8B,GAAI,GAAIC,GAAI,EAAEC,UAChCC,EAAAA,EAAAA,MAACC,EAAAA,EAAM,CAACC,QAAS,EAAEH,SAAA,EACjBL,EAAAA,EAAAA,KAACS,EAAAA,EAAO,CAACC,KAAK,QACdV,EAAAA,EAAAA,KAACW,EAAAA,EAAI,CAAAN,SAAC,0CAMTlB,GAAkC,IAArBA,EAAUY,QAK1BC,EAAAA,EAAAA,KAACC,EAAAA,EAAG,CAACC,GAAI7B,EAAW8B,GAAI,GAAIC,GAAI,EAAEC,UAChCC,EAAAA,EAAAA,MAACC,EAAAA,EAAM,CAACC,QAAS,EAAGI,KAAK,MAAMC,GAAG,OAAMR,SAAA,EACtCL,EAAAA,EAAAA,KAACc,EAAAA,EAAO,CAACJ,KAAK,KAAKK,UAAU,SAAQV,SAClCjC,KAGH4B,EAAAA,EAAAA,KAACO,EAAAA,EAAM,CAACC,QAAS,EAAGQ,EAAE,OAAMX,SACzBlB,EAAUE,IAAK4B,IACdjB,EAAAA,EAAAA,KAACC,EAAAA,EAAG,CAA4Be,EAAE,OAAOJ,KAAK,QAAOP,UACnDL,EAAAA,EAAAA,KAACkB,EAAAA,EAAQ,CACPxB,KAAMuB,EAAavB,KACnByB,SAAUF,EAAaG,UACvBC,SAAUJ,EAAaK,UACvBC,eAAgBN,EAAaO,oBALvBP,EAAavB,KAAKH,YAZ7B,K","sources":["components/home/PollsWidget.tsx"],"sourcesContent":["import React from 'react';\nimport {\n Box,\n VStack,\n Heading,\n Text,\n Spinner,\n Alert,\n AlertIcon,\n useColorModeValue,\n} from '@chakra-ui/react';\nimport { useQuery } from '@tanstack/react-query';\nimport { getPolls, getPoll } from '../../services/polls';\nimport PollCard from '../polls/PollCard';\n\ninterface PollsWidgetProps {\n featuredOnly?: boolean;\n maxPolls?: number;\n title?: string;\n}\n\nconst PollsWidget: React.FC<PollsWidgetProps> = ({\n featuredOnly = true,\n maxPolls = 1,\n title = 'Hlasování',\n}) => {\n const bgSection = useColorModeValue('gray.50', 'gray.900');\n\n // Fetch polls list\n const { data: polls, isLoading } = useQuery({\n queryKey: ['polls', { featured: featuredOnly }],\n queryFn: () => getPolls(featuredOnly ? { featured: true } : undefined),\n staleTime: 2 * 60 * 1000, // 2 minutes\n });\n\n // Get full poll data for each featured poll\n const pollsToDisplay = polls?.slice(0, maxPolls) || [];\n\n const { data: pollsData, isLoading: isLoadingPolls } = useQuery({\n queryKey: ['polls-details', pollsToDisplay.map((p) => p.id)],\n queryFn: async () => {\n const promises = pollsToDisplay.map((poll) => getPoll(poll.id));\n return await Promise.all(promises);\n },\n enabled: pollsToDisplay.length > 0,\n });\n\n if (isLoading || isLoadingPolls) {\n return (\n <Box bg={bgSection} py={12} px={4}>\n <VStack spacing={4}>\n <Spinner size=\"lg\" />\n <Text>Načítání ankety...</Text>\n </VStack>\n </Box>\n );\n }\n\n if (!pollsData || pollsData.length === 0) {\n return null; // Don't show widget if no polls\n }\n\n return (\n <Box bg={bgSection} py={12} px={4}>\n <VStack spacing={8} maxW=\"4xl\" mx=\"auto\">\n <Heading size=\"lg\" textAlign=\"center\">\n {title}\n </Heading>\n\n <VStack spacing={6} w=\"full\">\n {pollsData.map((pollResponse) => (\n <Box key={pollResponse.poll.id} w=\"full\" maxW=\"600px\">\n <PollCard\n poll={pollResponse.poll}\n hasVoted={pollResponse.has_voted}\n isActive={pollResponse.is_active}\n canShowResults={pollResponse.can_show_results}\n />\n </Box>\n ))}\n </VStack>\n </VStack>\n </Box>\n );\n};\n\nexport default PollsWidget;\n"],"names":["_ref","featuredOnly","maxPolls","title","bgSection","useColorModeValue","data","polls","isLoading","useQuery","queryKey","featured","queryFn","getPolls","undefined","staleTime","pollsToDisplay","slice","pollsData","isLoadingPolls","map","p","id","async","promises","poll","getPoll","Promise","all","enabled","length","_jsx","Box","bg","py","px","children","_jsxs","VStack","spacing","Spinner","size","Text","maxW","mx","Heading","textAlign","w","pollResponse","PollCard","hasVoted","has_voted","isActive","is_active","canShowResults","can_show_results"],"sourceRoot":""}
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,2 +0,0 @@
"use strict";(self.webpackChunkfrontend=self.webpackChunkfrontend||[]).push([[798],{78798:(e,s,n)=>{n.r(s),n.d(s,{default:()=>o});n(65043);var a=n(74117),l=n(22107),i=n(98662),r=n(98939),c=n(10202),d=n(39081),t=n(70579);const o=()=>{const{t:e,i18n:s}=(0,a.Bd)();return(0,t.jsx)(r.m,{maxW:"container.md",py:8,children:(0,t.jsx)(l.a,{p:4,borderWidth:1,borderRadius:"md",children:(0,t.jsxs)(c.T,{spacing:4,align:"start",children:[(0,t.jsx)(d.E,{fontSize:"2xl",fontWeight:"bold",children:"i18n Test Page"}),(0,t.jsxs)(d.E,{children:["Current language: ",(0,t.jsx)("strong",{children:s.language})]}),(0,t.jsxs)(d.E,{children:["Is ready: ",s.isInitialized?"Yes":"No"]}),(0,t.jsxs)(d.E,{children:["Loaded languages: ",s.languages.join(", ")]}),(0,t.jsxs)(l.a,{borderWidth:1,p:3,borderRadius:"md",w:"full",children:[(0,t.jsx)(d.E,{fontWeight:"bold",children:"Translation tests:"}),(0,t.jsxs)(d.E,{children:["Welcome: ",e("common.welcome_message")]}),(0,t.jsxs)(d.E,{children:["Subtitle: ",e("common.welcome_subtitle")]}),(0,t.jsxs)(d.E,{children:["Home: ",e("nav.home")]}),(0,t.jsxs)(d.E,{children:["Matches: ",e("nav.matches")]}),(0,t.jsxs)(d.E,{children:["Gallery: ",e("nav.gallery")]}),(0,t.jsxs)(d.E,{children:["Save: ",e("action.save")]}),(0,t.jsxs)(d.E,{children:["Loading: ",e("message.loading")]})]}),(0,t.jsxs)(i.$,{onClick:()=>{const e="cs"===s.language?"en":"cs";s.changeLanguage(e)},colorScheme:"blue",children:["Switch to ","cs"===s.language?"English":"\u010ce\u0161tina"]})]})})})}}}]);
//# sourceMappingURL=798.21001033.chunk.js.map
@@ -1 +0,0 @@
{"version":3,"file":"static/js/798.21001033.chunk.js","mappings":"4NAIA,MAqCA,EArC+BA,KAC7B,MAAM,EAAEC,EAAC,KAAEC,IAASC,EAAAA,EAAAA,MAOpB,OACEC,EAAAA,EAAAA,KAACC,EAAAA,EAAS,CAACC,KAAK,eAAeC,GAAI,EAAEC,UACnCJ,EAAAA,EAAAA,KAACK,EAAAA,EAAG,CAACC,EAAG,EAAGC,YAAa,EAAGC,aAAa,KAAIJ,UAC1CK,EAAAA,EAAAA,MAACC,EAAAA,EAAM,CAACC,QAAS,EAAGC,MAAM,QAAOR,SAAA,EAC/BJ,EAAAA,EAAAA,KAACa,EAAAA,EAAI,CAACC,SAAS,MAAMC,WAAW,OAAMX,SAAC,oBACvCK,EAAAA,EAAAA,MAACI,EAAAA,EAAI,CAAAT,SAAA,CAAC,sBAAkBJ,EAAAA,EAAAA,KAAA,UAAAI,SAASN,EAAKkB,eACtCP,EAAAA,EAAAA,MAACI,EAAAA,EAAI,CAAAT,SAAA,CAAC,aAAWN,EAAKmB,cAAgB,MAAQ,SAC9CR,EAAAA,EAAAA,MAACI,EAAAA,EAAI,CAAAT,SAAA,CAAC,qBAAmBN,EAAKoB,UAAUC,KAAK,UAE7CV,EAAAA,EAAAA,MAACJ,EAAAA,EAAG,CAACE,YAAa,EAAGD,EAAG,EAAGE,aAAa,KAAKY,EAAE,OAAMhB,SAAA,EACnDJ,EAAAA,EAAAA,KAACa,EAAAA,EAAI,CAACE,WAAW,OAAMX,SAAC,wBACxBK,EAAAA,EAAAA,MAACI,EAAAA,EAAI,CAAAT,SAAA,CAAC,YAAUP,EAAE,8BAClBY,EAAAA,EAAAA,MAACI,EAAAA,EAAI,CAAAT,SAAA,CAAC,aAAWP,EAAE,+BACnBY,EAAAA,EAAAA,MAACI,EAAAA,EAAI,CAAAT,SAAA,CAAC,SAAOP,EAAE,gBACfY,EAAAA,EAAAA,MAACI,EAAAA,EAAI,CAAAT,SAAA,CAAC,YAAUP,EAAE,mBAClBY,EAAAA,EAAAA,MAACI,EAAAA,EAAI,CAAAT,SAAA,CAAC,YAAUP,EAAE,mBAClBY,EAAAA,EAAAA,MAACI,EAAAA,EAAI,CAAAT,SAAA,CAAC,SAAOP,EAAE,mBACfY,EAAAA,EAAAA,MAACI,EAAAA,EAAI,CAAAT,SAAA,CAAC,YAAUP,EAAE,0BAGpBY,EAAAA,EAAAA,MAACY,EAAAA,EAAM,CAACC,QAzBOC,KACrB,MAAMC,EAA4B,OAAlB1B,EAAKkB,SAAoB,KAAO,KAChDlB,EAAK2B,eAAeD,IAuBmBE,YAAY,OAAMtB,SAAA,CAAC,aACrB,OAAlBN,EAAKkB,SAAoB,UAAY,8B","sources":["pages/I18nTestPage.tsx"],"sourcesContent":["import React from 'react';\nimport { useTranslation } from 'react-i18next';\nimport { Box, Text, Button, VStack, Container } from '@chakra-ui/react';\n\nconst I18nTestPage: React.FC = () => {\n const { t, i18n } = useTranslation();\n\n const toggleLanguage = () => {\n const newLang = i18n.language === 'cs' ? 'en' : 'cs';\n i18n.changeLanguage(newLang);\n };\n\n return (\n <Container maxW=\"container.md\" py={8}>\n <Box p={4} borderWidth={1} borderRadius=\"md\">\n <VStack spacing={4} align=\"start\">\n <Text fontSize=\"2xl\" fontWeight=\"bold\">i18n Test Page</Text>\n <Text>Current language: <strong>{i18n.language}</strong></Text>\n <Text>Is ready: {i18n.isInitialized ? 'Yes' : 'No'}</Text>\n <Text>Loaded languages: {i18n.languages.join(', ')}</Text>\n \n <Box borderWidth={1} p={3} borderRadius=\"md\" w=\"full\">\n <Text fontWeight=\"bold\">Translation tests:</Text>\n <Text>Welcome: {t('common.welcome_message')}</Text>\n <Text>Subtitle: {t('common.welcome_subtitle')}</Text>\n <Text>Home: {t('nav.home')}</Text>\n <Text>Matches: {t('nav.matches')}</Text>\n <Text>Gallery: {t('nav.gallery')}</Text>\n <Text>Save: {t('action.save')}</Text>\n <Text>Loading: {t('message.loading')}</Text>\n </Box>\n \n <Button onClick={toggleLanguage} colorScheme=\"blue\">\n Switch to {i18n.language === 'cs' ? 'English' : 'Čeština'}\n </Button>\n </VStack>\n </Box>\n </Container>\n );\n};\n\nexport default I18nTestPage;\n"],"names":["I18nTestPage","t","i18n","useTranslation","_jsx","Container","maxW","py","children","Box","p","borderWidth","borderRadius","_jsxs","VStack","spacing","align","Text","fontSize","fontWeight","language","isInitialized","languages","join","w","Button","onClick","toggleLanguage","newLang","changeLanguage","colorScheme"],"sourceRoot":""}
@@ -1,2 +0,0 @@
"use strict";(self.webpackChunkfrontend=self.webpackChunkfrontend||[]).push([[910],{15910:(e,i,r)=>{r.r(i),r.d(i,{default:()=>z});r(65043);var t=r(87139),a=r(22107),o=r(98662),s=r(44093),n=r(33572),l=r(99032),d=r(96148),c=r(10202),p=r(28846),g=r(39081),h=r(72526),u=r(34636),x=r(70118),m=r(35475),b=r(78801),f=r(25189),j=r(75088),v=r(35087),w=r(12255),y=r(70579);const _=e=>{var i;let{a:r}=e;const o=(0,s.dU)("white","gray.800"),l=(0,s.dU)("gray.200","whiteAlpha.300"),h=((0,b.N)(),r.slug?"/news/".concat(r.slug):"/articles/".concat(r.id)),u=((0,s.dU)("gray.100","whiteAlpha.200"),(null===r||void 0===r||null===(i=r.category)||void 0===i?void 0:i.name)||"");return(0,y.jsxs)(a.a,{as:m.N_,to:h,minW:{base:"85%",md:"60%",lg:"33%"},scrollSnapAlign:"start",bg:o,borderRadius:"xl",overflow:"hidden",boxShadow:"lg",borderWidth:"1px",borderColor:l,_hover:{transform:"translateY(-4px)",boxShadow:"2xl"},transition:"all 0.3s cubic-bezier(0.4, 0, 0.2, 1)",position:"relative",children:[(0,y.jsxs)(a.a,{position:"relative",overflow:"hidden",children:[(0,y.jsx)(n._,{src:(0,f.uq)(r.image_url)||"/stadium-placeholder.jpg",alt:r.title,w:"100%",h:{base:"200px",md:"240px"},objectFit:"cover",transition:"transform 0.3s ease",_groupHover:{transform:"scale(1.05)"}}),u&&(0,y.jsx)(t.E,{position:"absolute",top:3,left:3,colorScheme:"blue",fontSize:"xs",px:3,py:1,borderRadius:"full",textTransform:"uppercase",fontWeight:"bold",children:u})]}),(0,y.jsxs)(c.T,{align:"stretch",spacing:3,p:5,children:[(0,y.jsx)(p.D,{size:"md",noOfLines:2,lineHeight:"1.3",children:r.title}),r.content&&(0,y.jsx)(g.E,{fontSize:"sm",color:"gray.600",noOfLines:3,lineHeight:"1.5",children:r.content.replace(/<[^>]*>/g,"").trim()}),(0,y.jsxs)(d.z,{spacing:3,pt:2,borderTopWidth:"1px",borderColor:l,flexWrap:"wrap",children:[(r.read_time||r.estimated_read_minutes)&&(0,y.jsxs)(d.z,{spacing:1,children:[(0,y.jsx)(j.A,{size:14,color:"gray"}),(0,y.jsxs)(g.E,{fontSize:"xs",color:"gray.500",children:[r.read_time||r.estimated_read_minutes," min"]})]}),void 0!==r.view_count&&r.view_count>0&&(0,y.jsxs)(d.z,{spacing:1,children:[(0,y.jsx)(v.A,{size:14,color:"gray"}),(0,y.jsx)(g.E,{fontSize:"xs",color:"gray.500",children:r.view_count})]}),r.published_at&&(0,y.jsx)(g.E,{fontSize:"xs",color:"gray.500",children:new Date(r.published_at).toLocaleDateString("cs-CZ")})]})]}),(0,y.jsx)(w.A,{article:r,targetUrl:"undefined"!==typeof window?new URL(h,window.location.origin).toString():void 0,placement:"inline",position:"bottom-right",size:"sm"})]})},z=()=>{(0,b.N)();const{data:e,isLoading:i}=(0,h.I)({queryKey:["articles",{page:1,page_size:12,published:!0}],queryFn:()=>(0,u.GE)({page:1,page_size:12,published:!0})}),{data:r}=(0,h.I)({queryKey:["articles","featured",{page:1,page_size:100}],queryFn:()=>(0,u.A0)({page:1,page_size:100})}),t=(null===e||void 0===e?void 0:e.data)||[],s=new Set(((null===r||void 0===r?void 0:r.data)||[]).map(e=>e.slug?"s:".concat(e.slug):"i:".concat(e.id))),n=t.filter(e=>!s.has(e.slug?"s:".concat(e.slug):"i:".concat(e.id)));return(0,y.jsx)(a.a,{children:(0,y.jsxs)(x.A,{title:"Novinky",rightAction:(0,y.jsx)(o.$,{as:m.N_,to:"/blog",variant:"link",color:"brand.primary",children:"V\xedce"}),children:[i&&Array.from({length:4}).map((e,i)=>(0,y.jsx)(l.E,{minW:{base:"85%",md:"60%",lg:"33%"},h:{base:"260px",md:"300px"},borderRadius:"xl"},i)),!i&&n.map(e=>(0,y.jsx)(_,{a:e},e.id))]})})}}}]);
//# sourceMappingURL=910.bec7c150.chunk.js.map
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,2 +0,0 @@
(()=>{"use strict";var e={},t={};function r(o){var n=t[o];if(void 0!==n)return n.exports;var a=t[o]={id:o,loaded:!1,exports:{}};return e[o].call(a.exports,a,a.exports,r),a.loaded=!0,a.exports}r.m=e,(()=>{var e=[];r.O=(t,o,n,a)=>{if(!o){var i=1/0;for(l=0;l<e.length;l++){o=e[l][0],n=e[l][1],a=e[l][2];for(var d=!0,c=0;c<o.length;c++)(!1&a||i>=a)&&Object.keys(r.O).every(e=>r.O[e](o[c]))?o.splice(c--,1):(d=!1,a<i&&(i=a));if(d){e.splice(l--,1);var f=n();void 0!==f&&(t=f)}}return t}a=a||0;for(var l=e.length;l>0&&e[l-1][2]>a;l--)e[l]=e[l-1];e[l]=[o,n,a]}})(),r.n=e=>{var t=e&&e.__esModule?()=>e.default:()=>e;return r.d(t,{a:t}),t},(()=>{var e,t=Object.getPrototypeOf?e=>Object.getPrototypeOf(e):e=>e.__proto__;r.t=function(o,n){if(1&n&&(o=this(o)),8&n)return o;if("object"===typeof o&&o){if(4&n&&o.__esModule)return o;if(16&n&&"function"===typeof o.then)return o}var a=Object.create(null);r.r(a);var i={};e=e||[null,t({}),t([]),t(t)];for(var d=2&n&&o;("object"==typeof d||"function"==typeof d)&&!~e.indexOf(d);d=t(d))Object.getOwnPropertyNames(d).forEach(e=>i[e]=()=>o[e]);return i.default=()=>o,r.d(a,i),a}})(),r.d=(e,t)=>{for(var o in t)r.o(t,o)&&!r.o(e,o)&&Object.defineProperty(e,o,{enumerable:!0,get:t[o]})},r.f={},r.e=e=>Promise.all(Object.keys(r.f).reduce((t,o)=>(r.f[o](e,t),t),[])),r.u=e=>"static/js/"+e+"."+{118:"8a550f36",154:"a93817c6",158:"c7e50479",266:"e18a46b8",334:"0d196877",339:"c1ec8d08",452:"bad3d00e",453:"d9749a7d",469:"ec731235",501:"0b99fbb0",548:"da462cb8",558:"0464ebe3",579:"f8a21d69",620:"edc51951",771:"2b2378c2",791:"2cae987d",798:"21001033",910:"bec7c150"}[e]+".chunk.js",r.miniCssF=e=>{},r.g=function(){if("object"===typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"===typeof window)return window}}(),r.o=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),(()=>{var e={},t="frontend:";r.l=(o,n,a,i)=>{if(e[o])e[o].push(n);else{var d,c;if(void 0!==a)for(var f=document.getElementsByTagName("script"),l=0;l<f.length;l++){var u=f[l];if(u.getAttribute("src")==o||u.getAttribute("data-webpack")==t+a){d=u;break}}d||(c=!0,(d=document.createElement("script")).charset="utf-8",d.timeout=120,r.nc&&d.setAttribute("nonce",r.nc),d.setAttribute("data-webpack",t+a),d.src=o),e[o]=[n];var s=(t,r)=>{d.onerror=d.onload=null,clearTimeout(p);var n=e[o];if(delete e[o],d.parentNode&&d.parentNode.removeChild(d),n&&n.forEach(e=>e(r)),t)return t(r)},p=setTimeout(s.bind(null,void 0,{type:"timeout",target:d}),12e4);d.onerror=s.bind(null,d.onerror),d.onload=s.bind(null,d.onload),c&&document.head.appendChild(d)}}})(),r.r=e=>{"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.nmd=e=>(e.paths=[],e.children||(e.children=[]),e),r.p="/",(()=>{var e={121:0};r.f.j=(t,o)=>{var n=r.o(e,t)?e[t]:void 0;if(0!==n)if(n)o.push(n[2]);else if(121!=t){var a=new Promise((r,o)=>n=e[t]=[r,o]);o.push(n[2]=a);var i=r.p+r.u(t),d=new Error;r.l(i,o=>{if(r.o(e,t)&&(0!==(n=e[t])&&(e[t]=void 0),n)){var a=o&&("load"===o.type?"missing":o.type),i=o&&o.target&&o.target.src;d.message="Loading chunk "+t+" failed.\n("+a+": "+i+")",d.name="ChunkLoadError",d.type=a,d.request=i,n[1](d)}},"chunk-"+t,t)}else e[t]=0},r.O.j=t=>0===e[t];var t=(t,o)=>{var n,a,i=o[0],d=o[1],c=o[2],f=0;if(i.some(t=>0!==e[t])){for(n in d)r.o(d,n)&&(r.m[n]=d[n]);if(c)var l=c(r)}for(t&&t(o);f<i.length;f++)a=i[f],r.o(e,a)&&e[a]&&e[a][0](),e[a]=0;return r.O(l)},o=self.webpackChunkfrontend=self.webpackChunkfrontend||[];o.forEach(t.bind(null,0)),o.push=t.bind(null,o.push.bind(o))})(),r.nc=void 0})();
//# sourceMappingURL=runtime.0b5f0839.js.map
File diff suppressed because one or more lines are too long
+470 -1053
View File
File diff suppressed because it is too large Load Diff
+23 -20
View File
@@ -10,6 +10,7 @@
"test": "vitest run"
},
"dependencies": {
"@hello-pangea/dnd": "^18.0.1",
"@chakra-ui/icons": "^2.1.1",
"@chakra-ui/react": "^2.8.2",
"@emotion/react": "^11.11.1",
@@ -17,7 +18,7 @@
"@hookform/resolvers": "^3.3.4",
"@lobehub/icons": "^1.10.1",
"@monaco-editor/react": "^4.6.0",
"@tanstack/react-query": "^4.36.1",
"@tanstack/react-query": "^4.43.0",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
@@ -29,56 +30,58 @@
"@types/react-dom": "^18.2.18",
"@types/react-frame-component": "^4.1.6",
"axios": "^1.13.6",
"chart.js": "^4.4.1",
"chart.js": "^4.5.1",
"date-fns": "^4.1.0",
"dompurify": "^3.3.0",
"framer-motion": "^10.16.4",
"i18next": "^23.7.16",
"i18next-browser-languagedetector": "^7.2.0",
"i18next-http-backend": "^2.4.2",
"i18next": "^23.16.8",
"i18next-browser-languagedetector": "^7.2.2",
"i18next-http-backend": "^2.7.3",
"lucide-react": "^0.379.0",
"maplibre-gl": "^5.9.0",
"maplibre-gl": "^5.20.1",
"monaco-editor": "^0.49.0",
"popmotion": "^11.0.5",
"qrcode": "^1.5.4",
"quill": "^2.0.3",
"react": "^18.2.0",
"react-beautiful-dnd": "^13.1.1",
"react-chartjs-2": "^5.2.0",
"react-datepicker": "^8.7.0",
"react-chartjs-2": "^5.3.1",
"react-datepicker": "^8.10.0",
"react-dom": "^18.2.0",
"react-frame-component": "^5.2.7",
"react-helmet-async": "^2.0.5",
"react-hook-form": "^7.48.2",
"react-hook-form": "^7.71.2",
"react-i18next": "^13.5.0",
"react-icons": "^4.12.0",
"react-icons": "^5.6.0",
"react-image-crop": "^11.0.10",
"react-markdown": "^10.1.0",
"react-quill": "^2.0.0",
"react-router-dom": "^6.30.2",
"react-router-dom": "^6.30.3",
"react-simple-maps": "^3.0.0",
"react-syntax-highlighter": "^15.6.6",
"tinymce": "^8.2.2",
"react-syntax-highlighter": "^16.1.1",
"tinymce": "^8.3.2",
"typescript": "^4.9.5",
"web-vitals": "^2.1.4",
"yup": "^1.3.3"
"yup": "^1.7.1"
},
"devDependencies": {
"@types/chart.js": "^2.9.41",
"@types/dompurify": "^3.0.5",
"@types/geojson": "^7946.0.8",
"@types/maplibre-gl": "^1.13.2",
"@types/react-beautiful-dnd": "^13.1.8",
"@types/react-chartjs-2": "^2.0.2",
"@types/react-image-crop": "^8.1.6",
"@types/react-syntax-highlighter": "^15.5.13",
"@vitejs/plugin-react": "^4.4.1",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint": "^9.39.1",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-react-hooks": "^7.0.1",
"jsdom": "^26.1.0",
"vite": "^6.3.5",
"vitest": "^3.1.1"
},
"overrides": {
"flatted": "3.4.1",
"glob@7": {
"minimatch": "3.1.3"
}
},
"browserslist": {
"production": [
">0.2%",
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 9.4 KiB

+26 -1
View File
@@ -1 +1,26 @@
{"short_name": "Fotbal Club", "name": "Fotbal Club - Oficiální aplikace", "description": "Oficiální webové stránky fotbalového klubu - aktuality, zápasy, tabulky, hráči a fotogalerie", "icons": [{"src": "favicon.ico", "sizes": "64x64 32x32 24x24 16x16", "type": "image/x-icon"}, {"src": "logo192.png", "type": "image/png", "sizes": "192x192"}, {"src": "logo512.png", "type": "image/png", "sizes": "512x512"}], "start_url": ".", "display": "standalone", "theme_color": "#000000", "background_color": "#ffffff"}
{
"short_name": "Fotbal Club",
"name": "Fotbal Club - Oficiální aplikace",
"description": "Oficiální webové stránky fotbalového klubu - aktuality, zápasy, tabulky, hráči a fotogalerie",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png?v=2",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png?v=2",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
+5 -5
View File
@@ -1,7 +1,7 @@
/* eslint-disable no-restricted-globals */
// Service Worker for PWA support and offline functionality
const CACHE_VERSION = 'v1.0.2';
const CACHE_VERSION = 'v1.0.3';
const CACHE_NAME = `fotbal-club-cache-${CACHE_VERSION}`;
// Rate limiting for background updates
@@ -14,8 +14,8 @@ const STATIC_ASSETS = [
'/index.html',
'/manifest.json',
'/favicon.ico',
'/logo192.png',
'/logo512.png',
'/logo192.png?v=2',
'/logo512.png?v=2',
'/robots.txt',
];
@@ -266,8 +266,8 @@ self.addEventListener('push', (event) => {
const title = data.title || 'Fotbal Club';
const options = {
body: data.body || 'Nová notifikace',
icon: '/logo192.png',
badge: '/logo192.png',
icon: '/logo192.png?v=2',
badge: '/logo192.png?v=2',
data: data.url || '/',
};
+28 -4
View File
@@ -1,9 +1,33 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { vi } from 'vitest';
import { HelmetProvider } from 'react-helmet-async';
import App from './App';
test('renders learn react link', () => {
render(<App />);
const linkElement = screen.getByText(/learn react/i);
expect(linkElement).toBeInTheDocument();
vi.mock('./hooks/useUmami', () => ({
useUmami: () => ({ isEnabled: false, isLoaded: false, trackEvent: vi.fn() }),
}));
vi.mock('./hooks/usePublicSettings', () => ({
usePublicSettings: () => ({ data: null }),
}));
vi.mock('./utils/auth', () => ({
isAuthenticated: () => false,
checkAdminExists: async () => false,
getToken: () => null,
clearToken: vi.fn(),
setToken: vi.fn(),
}));
test('renders the app shell', () => {
window.history.pushState({}, 'Test 404', '/test-not-found');
render(
<HelmetProvider>
<App />
</HelmetProvider>
);
expect(screen.getByText(/stránka nenalezena/i)).toBeInTheDocument();
});
+9
View File
@@ -13,6 +13,7 @@ interface UseFacrApiReturn {
searchResults: SearchResponse['results'] | [];
searchLoading: boolean;
searchError: Error | null;
clearSearchResults: () => void;
// Get club details by ID and type
getClub: (clubId: string, clubType?: 'football' | 'futsal') => Promise<ClubInfo>;
@@ -64,6 +65,7 @@ export const useFacrApi = (): UseFacrApiReturn => {
async (query: string): Promise<SearchResponse> => {
setSearchLoading(true);
setSearchError(null);
setSearchResults([]);
try {
const response = await handleApiCall(() => facrApi.searchClubs(query));
setSearchResults(response.results || []);
@@ -107,11 +109,18 @@ export const useFacrApi = (): UseFacrApiReturn => {
facrApi.clearCache();
}, []);
const clearSearchResults = useCallback(() => {
setSearchResults([]);
setSearchError(null);
setSearchLoading(false);
}, []);
return {
searchClubs,
searchResults,
searchLoading,
searchError,
clearSearchResults,
getClub,
getClubTable,
getClubCompetitions,
+24 -6
View File
@@ -1,4 +1,4 @@
import { useEffect, useState, useMemo, startTransition } from 'react';
import { useEffect, useState, useMemo, useRef, startTransition } from 'react';
import { Box, Button, FormControl, FormLabel, Input, VStack, Heading, useToast, SimpleGrid, Divider, Text, useColorModeValue, InputGroup, InputRightElement, List, ListItem, Spinner, HStack, Image, Checkbox, Tooltip, Alert, AlertIcon, Select, FormHelperText, Badge, Link } from '@chakra-ui/react';
import { InfoOutlineIcon } from '@chakra-ui/icons';
import './styles/MagazineHome.css';
@@ -62,9 +62,11 @@ const SetupPage: React.FC = () => {
const [clubUrl, setClubUrl] = useState('');
const [clubLink, setClubLink] = useState('');
const [clubQuery, setClubQuery] = useState('');
const [selectedClubSearchLabel, setSelectedClubSearchLabel] = useState('');
const { data: publicSettings } = usePublicSettings();
const isManualClubDataMode = (publicSettings?.club_data_mode || '').toLowerCase() === 'manual';
const { searchClubs, searchResults, searchLoading } = useFacrApi();
const { searchClubs, searchResults, searchLoading, clearSearchResults } = useFacrApi();
const suppressNextClubSearchRef = useRef(false);
const resolveLogoUrl = (u?: string | null) => {
if (!u) return undefined;
@@ -216,11 +218,16 @@ const SetupPage: React.FC = () => {
useEffect(() => {
const q = clubQuery.trim();
if (!q) return;
if (selectedClubSearchLabel.trim() && q === selectedClubSearchLabel.trim()) return;
if (suppressNextClubSearchRef.current) {
suppressNextClubSearchRef.current = false;
return;
}
const t = setTimeout(() => {
searchClubs(q).catch(() => {});
}, 300);
return () => clearTimeout(t);
}, [clubQuery, searchClubs]);
}, [clubQuery, searchClubs, selectedClubSearchLabel]);
useEffect(() => {
if (isDomainHost && !showAdvancedApi) {
@@ -332,12 +339,15 @@ const SetupPage: React.FC = () => {
};
const handleSelectClub = async (item: SearchResult) => {
suppressNextClubSearchRef.current = true;
setSelectedClubSearchLabel(item.name || '');
clearSearchResults();
const clubIdValue = item.club_id || '';
setClubId(clubIdValue);
setClubType(item.club_type || 'football');
setClubName(item.name || '');
setClubUrl(item.url || '');
setClubQuery(item.name || '');
setClubQuery('');
// Try to fetch both logo and club name from logoapi first
let logoUrl = '';
@@ -827,12 +837,20 @@ const SetupPage: React.FC = () => {
<FormControl>
<FormLabel>Hledat klub (FAČR)</FormLabel>
<InputGroup>
<Input value={clubQuery} onChange={(e) => setClubQuery(e.target.value)} placeholder="Hledejte podle názvu klubu" />
<Input
value={clubQuery}
onChange={(e) => {
suppressNextClubSearchRef.current = false;
setSelectedClubSearchLabel('');
setClubQuery(e.target.value);
}}
placeholder="Hledejte podle názvu klubu"
/>
<InputRightElement>
{searchLoading ? <Spinner size="sm" /> : null}
</InputRightElement>
</InputGroup>
{clubQuery && searchResults?.length > 0 && (
{clubQuery.trim() && clubQuery.trim() !== selectedClubSearchLabel && searchResults?.length > 0 && (
<Box mt={2} borderWidth="1px" borderRadius="md" maxH="240px" overflowY="auto">
<List spacing={0}>
{searchResults.filter((r) => r.name && r.name.trim() !== '').slice(0, 8).map((r) => (
@@ -47,7 +47,7 @@ import {
Collapse,
Icon,
} from '@chakra-ui/react';
import { DragDropContext, Droppable, Draggable, DropResult } from 'react-beautiful-dnd';
import { DragDropContext, Droppable, Draggable, DropResult } from '@hello-pangea/dnd';
import AdminLayout from '../../layouts/AdminLayout';
import {
AddIcon,
+7 -14
View File
@@ -2,24 +2,17 @@ import axios, { AxiosInstance, AxiosResponse, InternalAxiosRequestConfig } from
import { reportError } from './errorReporter';
import { getToken } from '../utils/auth';
import { logAction } from './actionLog';
import { resolveApiBaseUrl } from '../utils/apiBaseUrl';
function readStored(key: string): string | null {
try { return localStorage.getItem(key); } catch { return null; }
try {
return localStorage.getItem(key);
} catch {
return null;
}
}
const storedApi = typeof window !== 'undefined' ? (readStored('fc_api_base_url') || readStored('api_base_url')) : null;
const envApiUrl = process.env.REACT_APP_API_URL || process.env.REACT_APP_API_BASE_URL;
let API_URL = storedApi || envApiUrl || '/api/v1';
try {
const maybe = new URL(API_URL, typeof window !== 'undefined' ? window.location.origin : undefined);
if (!/\/api\//.test(maybe.pathname)) {
maybe.pathname = maybe.pathname.replace(/\/$/, '') + '/api/v1';
API_URL = maybe.toString();
} else {
API_URL = maybe.toString();
}
} catch {}
const API_URL = resolveApiBaseUrl();
export const api: AxiosInstance = axios.create({
baseURL: API_URL,
+33
View File
@@ -0,0 +1,33 @@
function readStoredApiBase(key: string): string | null {
try {
return localStorage.getItem(key);
} catch {
return null;
}
}
export function normalizeApiBaseUrl(input?: string | null): string {
const fallbackOrigin = typeof window !== 'undefined' ? window.location.origin : 'http://localhost';
const candidate = (input || '').trim() || '/api/v1';
try {
const resolved = new URL(candidate, fallbackOrigin);
if (!/\/api\//.test(resolved.pathname)) {
resolved.pathname = resolved.pathname.replace(/\/$/, '') + '/api/v1';
}
return resolved.toString();
} catch {
const trimmed = candidate.replace(/\/$/, '');
return /\/api\//.test(trimmed) ? trimmed : `${trimmed}/api/v1`;
}
}
export function resolveApiBaseUrl(): string {
const storedApi =
typeof window !== 'undefined'
? readStoredApiBase('fc_api_base_url') || readStoredApiBase('api_base_url')
: null;
const envApiUrl = process.env.REACT_APP_API_URL || process.env.REACT_APP_API_BASE_URL;
return normalizeApiBaseUrl(storedApi || envApiUrl || '/api/v1');
}
+4 -3
View File
@@ -1,5 +1,7 @@
// Use a single canonical key for the auth token across the app
// Many modules expect 'auth_token' (see usages in services and build artifacts).
import { resolveApiBaseUrl } from './apiBaseUrl';
const TOKEN_KEY = 'auth_token';
const HAS_ADMIN_KEY = 'fotbal_club_has_admin';
@@ -43,9 +45,8 @@ export const setHasAdmin = (value: boolean): void => {
export const checkAdminExists = async (): Promise<boolean> => {
try {
// Use shared API base URL which is normalized to '/api/v1'
const { API_URL } = await import('../services/api');
const response = await fetch(`${API_URL}/auth/admin/exists`, {
const apiUrl = resolveApiBaseUrl();
const response = await fetch(`${apiUrl}/auth/admin/exists`, {
headers: { 'Accept': 'application/json' },
});
if (response.ok) {
+1 -1
View File
@@ -78,7 +78,7 @@ export function parseGoogleMapsUrl(url: string): MapCoordinates | null {
}
// Try to extract from pathname (/@lat,lng,zoom format)
const pathMatch = urlObj.pathname.match(/@(-?\d+\.\d+),(-?\d+\.\d+),(\d+)z/);
const pathMatch = urlObj.pathname.match(/@(-?\d+\.\d+),(-?\d+\.\d+),(\d+)(?:[mz])/);
if (pathMatch) {
const latitude = parseFloat(pathMatch[1]);
const longitude = parseFloat(pathMatch[2]);
+68 -11
View File
@@ -253,6 +253,29 @@ const recordCircuitBreakerSuccess = (): void => {
}
};
const LOGO_API_HOSTS = new Set([
'logoapi.sportcreative.eu',
'www.logoapi.sportcreative.eu',
]);
const normalizeLogoApiUrl = (raw?: string | null): string | null => {
const value = String(raw || '').trim();
if (!value) return null;
try {
const fallbackOrigin = typeof window !== 'undefined'
? window.location.origin
: 'https://logoapi.sportcreative.eu';
const parsed = new URL(value, fallbackOrigin);
if (LOGO_API_HOSTS.has(parsed.hostname)) {
parsed.protocol = 'https:';
}
return parsed.toString();
} catch {
return value;
}
};
/**
* Fetch logo from logoapi.sportcreative.eu with optimization and circuit breaker
*/
@@ -267,8 +290,16 @@ export const fetchLogoFromLogoAPI = async (teamId: string, teamName?: string): P
// Check cache first
const cached = await getCachedLogo(teamId);
if (cached?.url && !cached.url.startsWith('blob:')) {
const normalizedCachedUrl = normalizeLogoApiUrl(cached.url);
await updateLastUsed(teamId);
return cached.url;
if (normalizedCachedUrl && normalizedCachedUrl !== cached.url) {
await saveCachedLogo({
...cached,
url: normalizedCachedUrl,
lastUsed: Date.now(),
});
}
return normalizedCachedUrl;
}
// Fetch from logoapi with timeout
@@ -289,7 +320,7 @@ export const fetchLogoFromLogoAPI = async (teamId: string, teamName?: string): P
}
const data = await res.json();
const url = data.logo_url_svg || data.logo_url_png || data.logo_url;
const url = normalizeLogoApiUrl(data.logo_url_svg || data.logo_url_png || data.logo_url);
if (!url) {
recordCircuitBreakerFailure();
@@ -319,19 +350,38 @@ export const fetchLogoFromLogoAPI = async (teamId: string, teamName?: string): P
*/
export const fetchClubNameAndLogoFromAPI = async (teamId: string): Promise<{ clubName?: string; logoUrl?: string } | null> => {
try {
const cached = await getCachedLogo(teamId);
const cachedLogoUrl = cached?.url && !cached.url.startsWith('blob:')
? normalizeLogoApiUrl(cached.url)
: null;
// Fetch from logoapi
const res = await fetch(`https://logoapi.sportcreative.eu/logos/${teamId}/json`, {
method: 'GET',
headers: { 'Accept': 'application/json' },
});
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 5000);
let res: Response;
try {
res = await fetch(`https://logoapi.sportcreative.eu/logos/${teamId}/json`, {
method: 'GET',
headers: { 'Accept': 'application/json' },
signal: controller.signal,
});
} finally {
clearTimeout(timeoutId);
}
if (!res.ok) return null;
if (!res.ok) {
recordCircuitBreakerFailure();
return cachedLogoUrl ? { logoUrl: cachedLogoUrl } : null;
}
const data = await res.json();
const logoUrl = data.logo_url_svg || data.logo_url_png || data.logo_url;
const logoUrl = normalizeLogoApiUrl(data.logo_url_svg || data.logo_url_png || data.logo_url);
const clubName = data.club_name;
if (!logoUrl && !clubName) return null;
if (!logoUrl && !clubName) {
recordCircuitBreakerFailure();
return cachedLogoUrl ? { logoUrl: cachedLogoUrl } : null;
}
// Cache the logo if available
if (logoUrl) {
@@ -343,14 +393,21 @@ export const fetchClubNameAndLogoFromAPI = async (teamId: string): Promise<{ clu
lastUsed: Date.now(),
});
}
recordCircuitBreakerSuccess();
return {
clubName: clubName || undefined,
logoUrl: logoUrl || undefined,
logoUrl: logoUrl || cachedLogoUrl || undefined,
};
} catch (e) {
recordCircuitBreakerFailure();
console.warn(`Failed to fetch club info for team ${teamId}:`, e);
return null;
const cached = await getCachedLogo(teamId).catch(() => null);
const cachedLogoUrl = cached?.url && !cached.url.startsWith('blob:')
? normalizeLogoApiUrl(cached.url)
: null;
return cachedLogoUrl ? { logoUrl: cachedLogoUrl } : null;
}
};
+2 -5510
View File
File diff suppressed because it is too large Load Diff
+2 -9
View File
@@ -1,11 +1,4 @@
{
"devDependencies": {
"@types/geojson": "^7946.0.16"
},
"dependencies": {
"@openapi-mcp/server": "^0.0.1",
"quill-image-resize-module-v2": "^3.0.0",
"react-markdown": "^10.1.0",
"typescript": "^5.9.3"
}
"name": "fotbal-club-root",
"private": true
}