code reformat
This commit is contained in:
Generated
+80
-99
@@ -1344,38 +1344,38 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@fortawesome/fontawesome-common-types": {
|
"@fortawesome/fontawesome-common-types": {
|
||||||
"version": "0.2.28",
|
"version": "0.2.32",
|
||||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.28.tgz",
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.32.tgz",
|
||||||
"integrity": "sha512-gtis2/5yLdfI6n0ia0jH7NJs5i/Z/8M/ZbQL6jXQhCthEOe5Cr5NcQPhgTvFxNOtURE03/ZqUcEskdn2M+QaBg=="
|
"integrity": "sha512-ux2EDjKMpcdHBVLi/eWZynnPxs0BtFVXJkgHIxXRl+9ZFaHPvYamAfCzeeQFqHRjuJtX90wVnMRaMQAAlctz3w=="
|
||||||
},
|
},
|
||||||
"@fortawesome/fontawesome-svg-core": {
|
"@fortawesome/fontawesome-svg-core": {
|
||||||
"version": "1.2.28",
|
"version": "1.2.32",
|
||||||
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.28.tgz",
|
"resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.32.tgz",
|
||||||
"integrity": "sha512-4LeaNHWvrneoU0i8b5RTOJHKx7E+y7jYejplR7uSVB34+mp3Veg7cbKk7NBCLiI4TyoWS1wh9ZdoyLJR8wSAdg==",
|
"integrity": "sha512-XjqyeLCsR/c/usUpdWcOdVtWFVjPbDFBTQkn2fQRrWhhUoxriQohO2RWDxLyUM8XpD+Zzg5xwJ8gqTYGDLeGaQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@fortawesome/fontawesome-common-types": "^0.2.28"
|
"@fortawesome/fontawesome-common-types": "^0.2.32"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@fortawesome/free-brands-svg-icons": {
|
"@fortawesome/free-brands-svg-icons": {
|
||||||
"version": "5.13.0",
|
"version": "5.15.1",
|
||||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-5.15.1.tgz",
|
||||||
"integrity": "sha512-/6xXiJFCMEQxqxXbL0FPJpwq5Cv6MRrjsbJEmH/t5vOvB4dILDpnY0f7zZSlA8+TG7jwlt12miF/yZpZkykucA==",
|
"integrity": "sha512-pkTZIWn7iuliCCgV+huDfZmZb2UjslalXGDA2PcqOVUYJmYL11y6ooFiMJkJvUZu+xgAc1gZgQe+Px12mZF0CA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@fortawesome/fontawesome-common-types": "^0.2.28"
|
"@fortawesome/fontawesome-common-types": "^0.2.32"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@fortawesome/free-solid-svg-icons": {
|
"@fortawesome/free-solid-svg-icons": {
|
||||||
"version": "5.13.0",
|
"version": "5.15.1",
|
||||||
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.13.0.tgz",
|
"resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.1.tgz",
|
||||||
"integrity": "sha512-IHUgDJdomv6YtG4p3zl1B5wWf9ffinHIvebqQOmV3U+3SLw4fC+LUCCgwfETkbTtjy5/Qws2VoVf6z/ETQpFpg==",
|
"integrity": "sha512-EFMuKtzRMNbvjab/SvJBaOOpaqJfdSap/Nl6hst7CgrJxwfORR1drdTV6q1Ib/JVzq4xObdTDcT6sqTaXMqfdg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@fortawesome/fontawesome-common-types": "^0.2.28"
|
"@fortawesome/fontawesome-common-types": "^0.2.32"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@fortawesome/react-fontawesome": {
|
"@fortawesome/react-fontawesome": {
|
||||||
"version": "0.1.10",
|
"version": "0.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.10.tgz",
|
"resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.11.tgz",
|
||||||
"integrity": "sha512-UGdpJiLBIqR/8xcLrCarf2pChqQFKjDTD02C7ZS/odpOVVl2YuHYRCLEOQ0GpfOk6jtYhmouSFOFoC8qNCe5cg==",
|
"integrity": "sha512-sClfojasRifQKI0OPqTy8Ln8iIhnxR/Pv/hukBhWnBz9kQRmqi6JSH3nghlhAY7SUeIIM7B5/D2G8WjX0iepVg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"prop-types": "^15.7.2"
|
"prop-types": "^15.7.2"
|
||||||
}
|
}
|
||||||
@@ -1775,59 +1775,59 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@sentry/browser": {
|
"@sentry/browser": {
|
||||||
"version": "5.12.1",
|
"version": "5.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.12.1.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/browser/-/browser-5.26.0.tgz",
|
||||||
"integrity": "sha512-Zl7VdppUxctyaoqMSEhnDJp2rrupx8n8N2n3PSooH74yhB2Z91nt84mouczprBsw3JU1iggGyUw9seRFzDI1hw==",
|
"integrity": "sha512-52kNVpy10Zd3gJRGFkhnOQvr80WJg7+XBqjMOE0//Akh4PfvEK3IqmAjVqysz6aHdruwTTivKF4ZoAxL/pA7Rg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@sentry/core": "5.12.0",
|
"@sentry/core": "5.26.0",
|
||||||
"@sentry/types": "5.12.0",
|
"@sentry/types": "5.26.0",
|
||||||
"@sentry/utils": "5.12.0",
|
"@sentry/utils": "5.26.0",
|
||||||
"tslib": "^1.9.3"
|
"tslib": "^1.9.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@sentry/core": {
|
"@sentry/core": {
|
||||||
"version": "5.12.0",
|
"version": "5.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-5.26.0.tgz",
|
||||||
"integrity": "sha512-wY4rsoX71QsGpcs9tF+OxKgDPKzIFMRvFiSRcJoPMfhFsTilQ/CBMn/c3bDtWQd9Bnr/ReQIL6NbnIjUsPHA4Q==",
|
"integrity": "sha512-Ubrw7K52orTVsaxpz8Su40FPXugKipoQC+zPrXcH+JIMB+o18kutF81Ae4WzuUqLfP7YB91eAlRrP608zw0EXA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@sentry/hub": "5.12.0",
|
"@sentry/hub": "5.26.0",
|
||||||
"@sentry/minimal": "5.12.0",
|
"@sentry/minimal": "5.26.0",
|
||||||
"@sentry/types": "5.12.0",
|
"@sentry/types": "5.26.0",
|
||||||
"@sentry/utils": "5.12.0",
|
"@sentry/utils": "5.26.0",
|
||||||
"tslib": "^1.9.3"
|
"tslib": "^1.9.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@sentry/hub": {
|
"@sentry/hub": {
|
||||||
"version": "5.12.0",
|
"version": "5.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/hub/-/hub-5.26.0.tgz",
|
||||||
"integrity": "sha512-3k7yE8BEVJsKx8mR4LcI4IN0O8pngmq44OcJ/fRUUBAPqsT38jsJdP2CaWhdlM1jiNUzUDB1ktBv6/lY+VgcoQ==",
|
"integrity": "sha512-lAYeWvvhGYS6eQ5d0VEojw0juxGc3v4aAu8VLvMKWcZ1jXD13Bhc46u9Nvf4qAY6BAQsJDQcpEZLpzJu1bk1Qw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@sentry/types": "5.12.0",
|
"@sentry/types": "5.26.0",
|
||||||
"@sentry/utils": "5.12.0",
|
"@sentry/utils": "5.26.0",
|
||||||
"tslib": "^1.9.3"
|
"tslib": "^1.9.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@sentry/minimal": {
|
"@sentry/minimal": {
|
||||||
"version": "5.12.0",
|
"version": "5.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/minimal/-/minimal-5.26.0.tgz",
|
||||||
"integrity": "sha512-fk73meyz4k4jCg9yzbma+WkggsfEIQWI2e2TWfYsRGcrV3RnlSrXyM4D91/A8Bjx10SNezHPUFHjasjlHXOkyA==",
|
"integrity": "sha512-mdFo3FYaI1W3KEd8EHATYx8mDOZIxeoUhcBLlH7Iej6rKvdM7p8GoECrmHPU1l6sCCPtBuz66QT5YeXc7WILsA==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@sentry/hub": "5.12.0",
|
"@sentry/hub": "5.26.0",
|
||||||
"@sentry/types": "5.12.0",
|
"@sentry/types": "5.26.0",
|
||||||
"tslib": "^1.9.3"
|
"tslib": "^1.9.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@sentry/types": {
|
"@sentry/types": {
|
||||||
"version": "5.12.0",
|
"version": "5.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/types/-/types-5.26.0.tgz",
|
||||||
"integrity": "sha512-aZbBouBLrKB8wXlztriIagZNmsB+wegk1Jkl6eprqRW/w24Sl/47tiwH8c5S4jYTxdAiJk+SAR10AAuYmIN3zg=="
|
"integrity": "sha512-ugpa1ePOhK55pjsyutAsa2tiJVQEyGYCaOXzaheg/3+EvhMdoW+owiZ8wupfvPhtZFIU3+FPOVz0d5k9K5d1rw=="
|
||||||
},
|
},
|
||||||
"@sentry/utils": {
|
"@sentry/utils": {
|
||||||
"version": "5.12.0",
|
"version": "5.26.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/utils/-/utils-5.26.0.tgz",
|
||||||
"integrity": "sha512-fYUadGLbfTCbs4OG5hKCOtv2jrNE4/8LHNABy9DwNJ/t5DVtGqWAZBnxsC+FG6a3nVqCpxjFI9AHlYsJ2wsf7Q==",
|
"integrity": "sha512-F2gnHIAWbjiowcAgxz3VpKxY/NQ39NTujEd/NPnRTWlRynLFg3bAV+UvZFXljhYJeN3b/zRlScNDcpCWTrtZGw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@sentry/types": "5.12.0",
|
"@sentry/types": "5.26.0",
|
||||||
"tslib": "^1.9.3"
|
"tslib": "^1.9.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -2020,9 +2020,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/history": {
|
"@types/history": {
|
||||||
"version": "4.7.6",
|
"version": "4.7.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.8.tgz",
|
||||||
"integrity": "sha512-GRTZLeLJ8ia00ZH8mxMO8t0aC9M1N9bN461Z2eaRurJo6Fpa+utgCwLzI4jQHcrdzuzp5WPN9jRwpsCQ1VhJ5w==",
|
"integrity": "sha512-S78QIYirQcUoo6UJZx9CSP0O2ix9IaeAXwQi26Rhr/+mg7qqPy8TzaxHSUut7eGjL8WmLccT7/MXf304WjqHcA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/hoist-non-react-statics": {
|
"@types/hoist-non-react-statics": {
|
||||||
@@ -2073,9 +2073,9 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/node": {
|
"@types/node": {
|
||||||
"version": "14.0.13",
|
"version": "14.11.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.0.13.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-14.11.8.tgz",
|
||||||
"integrity": "sha512-rouEWBImiRaSJsVA+ITTFM6ZxibuAlTuNOCyxVbwreu6k6+ujs7DfnU9o+PShFhET78pMBl3eH+AGSI5eOTkPA==",
|
"integrity": "sha512-KPcKqKm5UKDkaYPTuXSx8wEP7vE9GnuaXIZKijwRYcePpZFDVuy2a57LarFKiORbHOuTOOwYzxVxcUzsh2P2Pw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/parse-json": {
|
"@types/parse-json": {
|
||||||
@@ -2097,13 +2097,13 @@
|
|||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"@types/react": {
|
"@types/react": {
|
||||||
"version": "16.9.36",
|
"version": "16.9.52",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.36.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-16.9.52.tgz",
|
||||||
"integrity": "sha512-mGgUb/Rk/vGx4NCvquRuSH0GHBQKb1OqpGS9cT9lFxlTLHZgkksgI60TuIxubmn7JuCb+sENHhQciqa0npm0AQ==",
|
"integrity": "sha512-EHRjmnxiNivwhGdMh9sz1Yw9AUxTSZFxKqdBWAAzyZx3sufWwx6ogqHYh/WB1m/I4ZpjkoZLExF5QTy2ekVi/Q==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/prop-types": "*",
|
"@types/prop-types": "*",
|
||||||
"csstype": "^2.2.0"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/react-dom": {
|
"@types/react-dom": {
|
||||||
@@ -2128,9 +2128,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/react-router": {
|
"@types/react-router": {
|
||||||
"version": "5.1.7",
|
"version": "5.1.8",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.8.tgz",
|
||||||
"integrity": "sha512-2ouP76VQafKjtuc0ShpwUebhHwJo0G6rhahW9Pb8au3tQTjYXd2jta4wv6U2tGLR/I42yuG00+UXjNYY0dTzbg==",
|
"integrity": "sha512-HzOyJb+wFmyEhyfp4D4NYrumi+LQgQL/68HvJO+q6XtuHSDvw6Aqov7sCAhjbNq3bUPgPqbdvjXC5HeB2oEAPg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/history": "*",
|
"@types/history": "*",
|
||||||
@@ -2138,9 +2138,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"@types/react-router-dom": {
|
"@types/react-router-dom": {
|
||||||
"version": "5.1.5",
|
"version": "5.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.1.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.1.6.tgz",
|
||||||
"integrity": "sha512-ArBM4B1g3BWLGbaGvwBGO75GNFbLDUthrDojV2vHLih/Tq8M+tgvY1DSwkuNrPSwdp/GUL93WSEpTZs8nVyJLw==",
|
"integrity": "sha512-gjrxYqxz37zWEdMVvQtWPFMFj1dRDb4TGOcgyOfSXTrEXdF92L00WE3C471O3TV/RF1oskcStkXsOU0Ete4s/g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"requires": {
|
"requires": {
|
||||||
"@types/history": "*",
|
"@types/history": "*",
|
||||||
@@ -4934,9 +4934,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"csstype": {
|
"csstype": {
|
||||||
"version": "2.6.10",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.10.tgz",
|
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.3.tgz",
|
||||||
"integrity": "sha512-D34BqZU4cIlMCY93rZHbrq9pjTAQJ3U8S8rfBqjwHxkGPThWFjzZDQpgMJY0QViLxth6ZKYiwFBo14RdN44U/w=="
|
"integrity": "sha512-jPl+wbWPOWJ7SXsWyqGRk3lGecbar0Cb0OvZF/r/ZU011R4YqiRehgkQ9p4eQfo9DSDLqLL3wHwfxeJiuIsNag==",
|
||||||
|
"dev": true
|
||||||
},
|
},
|
||||||
"currently-unhandled": {
|
"currently-unhandled": {
|
||||||
"version": "0.4.1",
|
"version": "0.4.1",
|
||||||
@@ -5327,15 +5328,6 @@
|
|||||||
"utila": "~0.4"
|
"utila": "~0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dom-helpers": {
|
|
||||||
"version": "5.1.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.1.4.tgz",
|
|
||||||
"integrity": "sha512-TjMyeVUvNEnOnhzs6uAn9Ya47GmMo3qq7m+Lr/3ON0Rs5kHvb8I+SQYjLUSYn7qhEm0QjW0yrBkvz9yOrwwz1A==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/runtime": "^7.8.7",
|
|
||||||
"csstype": "^2.6.7"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"dom-serializer": {
|
"dom-serializer": {
|
||||||
"version": "0.2.2",
|
"version": "0.2.2",
|
||||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz",
|
||||||
@@ -9770,9 +9762,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"lodash": {
|
"lodash": {
|
||||||
"version": "4.17.15",
|
"version": "4.17.20",
|
||||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz",
|
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
|
||||||
"integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==",
|
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"lodash._reinterpolate": {
|
"lodash._reinterpolate": {
|
||||||
@@ -12680,9 +12672,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react": {
|
"react": {
|
||||||
"version": "16.13.1",
|
"version": "16.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz",
|
||||||
"integrity": "sha512-YMZQQq32xHLX0bz5Mnibv1/LHb3Sqzngu7xstSM+vrkE5Kzr9xE0yMByK5kMoTK30YVJE61WfbxIFFvfeDKT1w==",
|
"integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"loose-envify": "^1.1.0",
|
"loose-envify": "^1.1.0",
|
||||||
"object-assign": "^4.1.1",
|
"object-assign": "^4.1.1",
|
||||||
@@ -12999,9 +12991,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-dom": {
|
"react-dom": {
|
||||||
"version": "16.13.1",
|
"version": "16.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz",
|
||||||
"integrity": "sha512-81PIMmVLnCNLO/fFOQxdQkvEq/+Hfpv24XNJfpyZhTRfO0QcmQIF/PgCa1zCOj2w1hrn12MFLyaJ/G0+Mxtfag==",
|
"integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"loose-envify": "^1.1.0",
|
"loose-envify": "^1.1.0",
|
||||||
"object-assign": "^4.1.1",
|
"object-assign": "^4.1.1",
|
||||||
@@ -13030,9 +13022,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-redux": {
|
"react-redux": {
|
||||||
"version": "7.2.0",
|
"version": "7.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.1.tgz",
|
||||||
"integrity": "sha512-EvCAZYGfOLqwV7gh849xy9/pt55rJXPwmYvI4lilPM5rUT/1NxuuN59ipdBksRVSvz0KInbPnp4IfoXJXCqiDA==",
|
"integrity": "sha512-T+VfD/bvgGTUA74iW9d2i5THrDQWbweXP0AVNI8tNd1Rk5ch1rnMiJkDD67ejw7YBKM4+REvcvqRuWJb7BLuEg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"@babel/runtime": "^7.5.5",
|
"@babel/runtime": "^7.5.5",
|
||||||
"hoist-non-react-statics": "^3.3.0",
|
"hoist-non-react-statics": "^3.3.0",
|
||||||
@@ -13156,17 +13148,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-transition-group": {
|
|
||||||
"version": "4.4.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz",
|
|
||||||
"integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==",
|
|
||||||
"requires": {
|
|
||||||
"@babel/runtime": "^7.5.5",
|
|
||||||
"dom-helpers": "^5.0.1",
|
|
||||||
"loose-envify": "^1.4.0",
|
|
||||||
"prop-types": "^15.6.2"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"read-pkg": {
|
"read-pkg": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
|
||||||
|
|||||||
+11
-12
@@ -3,26 +3,25 @@
|
|||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fortawesome/fontawesome-svg-core": "1.2.28",
|
"@fortawesome/fontawesome-svg-core": "1.2.32",
|
||||||
"@fortawesome/free-brands-svg-icons": "5.13.0",
|
"@fortawesome/free-brands-svg-icons": "5.15.1",
|
||||||
"@fortawesome/free-solid-svg-icons": "5.13.0",
|
"@fortawesome/free-solid-svg-icons": "5.15.1",
|
||||||
"@fortawesome/react-fontawesome": "0.1.10",
|
"@fortawesome/react-fontawesome": "0.1.11",
|
||||||
"@sentry/browser": "^5.7.1",
|
"@sentry/browser": "5.26.0",
|
||||||
"bbcode-to-react": "0.2.9",
|
"bbcode-to-react": "0.2.9",
|
||||||
"react": "16.14.0",
|
"react": "16.14.0",
|
||||||
"react-dom": "16.14.0",
|
"react-dom": "16.14.0",
|
||||||
"react-loader-spinner": "3.1.14",
|
"react-loader-spinner": "3.1.14",
|
||||||
"react-redux": "7.2.0",
|
"redux": "4.0.5",
|
||||||
"react-router-dom": "5.2.0",
|
"react-redux": "7.2.1",
|
||||||
"react-transition-group": "4.4.1",
|
"react-router-dom": "5.2.0"
|
||||||
"redux": "4.0.5"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "14.0.13",
|
"@types/node": "14.11.8",
|
||||||
"@types/react": "16.9.36",
|
"@types/react": "16.9.52",
|
||||||
"@types/react-dom": "16.9.8",
|
"@types/react-dom": "16.9.8",
|
||||||
"@types/react-redux": "7.1.9",
|
"@types/react-redux": "7.1.9",
|
||||||
"@types/react-router-dom": "5.1.5",
|
"@types/react-router-dom": "5.1.6",
|
||||||
"@types/react-transition-group": "4.4.0",
|
"@types/react-transition-group": "4.4.0",
|
||||||
"node-sass": "4.14.1",
|
"node-sass": "4.14.1",
|
||||||
"redux-devtools-extension": "2.13.8",
|
"redux-devtools-extension": "2.13.8",
|
||||||
|
|||||||
+5
-2
@@ -2,7 +2,7 @@ const baseUrl = process.env.NODE_ENV === "development" ? 'http://localhost:8080/
|
|||||||
|
|
||||||
async function request<T>(url: string, method: string, body?: string | FormData): Promise<T> {
|
async function request<T>(url: string, method: string, body?: string | FormData): Promise<T> {
|
||||||
let bUrl = baseUrl;
|
let bUrl = baseUrl;
|
||||||
if(baseUrl.endsWith('/')) bUrl = bUrl.slice(0, baseUrl.length-1);
|
if(baseUrl.endsWith('/')) bUrl = bUrl.slice(0, baseUrl.length - 1);
|
||||||
if(url.startsWith('/')) url = url.slice(1, baseUrl.length);
|
if(url.startsWith('/')) url = url.slice(1, baseUrl.length);
|
||||||
|
|
||||||
const res = await fetch(`${bUrl}/${url}`, {
|
const res = await fetch(`${bUrl}/${url}`, {
|
||||||
@@ -13,7 +13,7 @@ async function request<T>(url: string, method: string, body?: string | FormData)
|
|||||||
let json: ApiResponse<T>;
|
let json: ApiResponse<T>;
|
||||||
try {
|
try {
|
||||||
json = await res.json();
|
json = await res.json();
|
||||||
} catch (e) {
|
} catch(e) {
|
||||||
json = { error: false };
|
json = { error: false };
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,12 +29,15 @@ async function request<T>(url: string, method: string, body?: string | FormData)
|
|||||||
function get<T>(url: string, data?: object): Promise<T> {
|
function get<T>(url: string, data?: object): Promise<T> {
|
||||||
return request<T>(url, 'GET', JSON.stringify(data));
|
return request<T>(url, 'GET', JSON.stringify(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
function post<T>(url: string, data?: object | FormData): Promise<T> {
|
function post<T>(url: string, data?: object | FormData): Promise<T> {
|
||||||
return request(url, 'POST', data instanceof FormData ? data : JSON.stringify(data));
|
return request(url, 'POST', data instanceof FormData ? data : JSON.stringify(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
function put<T>(url: string, data?: object): Promise<T> {
|
function put<T>(url: string, data?: object): Promise<T> {
|
||||||
return request<T>(url, 'PUT', JSON.stringify(data));
|
return request<T>(url, 'PUT', JSON.stringify(data));
|
||||||
}
|
}
|
||||||
|
|
||||||
function del<T>(url: string, data?: object): Promise<T> {
|
function del<T>(url: string, data?: object): Promise<T> {
|
||||||
return request<T>(url, 'DELETE', JSON.stringify(data));
|
return request<T>(url, 'DELETE', JSON.stringify(data));
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-3
@@ -1,6 +1,15 @@
|
|||||||
import {post} from "./api";
|
import { post } from "./api";
|
||||||
|
|
||||||
export const restore = (token: string, new_password: string) => post<string>('auth/restore', { token, new_password });
|
export const restore = (token: string, new_password: string) => post<string>('auth/restore', { token, new_password });
|
||||||
export const registerUser = (login: string, password: string, email: string, recaptcha: string) => post<UserType>('auth/register', { login, password, email, recaptcha });
|
export const registerUser = (login: string, password: string, email: string, recaptcha: string) => post<UserType>('auth/register', {
|
||||||
export const login = (login: string, password: string, recaptcha: string) => post<UserType>('auth/login', { login, password, recaptcha });
|
login,
|
||||||
|
password,
|
||||||
|
email,
|
||||||
|
recaptcha
|
||||||
|
});
|
||||||
|
export const login = (login: string, password: string, recaptcha: string) => post<UserType>('auth/login', {
|
||||||
|
login,
|
||||||
|
password,
|
||||||
|
recaptcha
|
||||||
|
});
|
||||||
export const userLogout = () => post<string>('auth/logout');
|
export const userLogout = () => post<string>('auth/logout');
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {get} from "./api";
|
import { get } from "./api";
|
||||||
|
|
||||||
export const fetchChar = (id: number) => get<CharacterType>(`characters/${id}`);
|
export const fetchChar = (id: number) => get<CharacterType>(`characters/${id}`);
|
||||||
export const fetchCharNovels = (id: number) => get<NovelType[]>(`characters/${id}/novels`);
|
export const fetchCharNovels = (id: number) => get<NovelType[]>(`characters/${id}/novels`);
|
||||||
|
|||||||
+1
-1
@@ -1,4 +1,4 @@
|
|||||||
import {del, get, put} from './api';
|
import { del, get, put } from './api';
|
||||||
|
|
||||||
export const fetchNews = () => get<PostType[]>('news');
|
export const fetchNews = () => get<PostType[]>('news');
|
||||||
|
|
||||||
|
|||||||
+6
-3
@@ -1,4 +1,4 @@
|
|||||||
import { get, post, put, del } from "./api";
|
import { del, get, post, put } from "./api";
|
||||||
|
|
||||||
|
|
||||||
export const fetchNovels = (orderBy?: string) => get<NovelType[]>(orderBy ? `novels?sort=${orderBy}` : 'novels');
|
export const fetchNovels = (orderBy?: string) => get<NovelType[]>(orderBy ? `novels?sort=${orderBy}` : 'novels');
|
||||||
@@ -11,10 +11,13 @@ export const fetchNovelCharacters = (id: number) => get<CharacterType[]>(`novels
|
|||||||
|
|
||||||
export const fetchNovelGenres = (id: number) => get<GenreType[]>(`novels/${id}/genres`);
|
export const fetchNovelGenres = (id: number) => get<GenreType[]>(`novels/${id}/genres`);
|
||||||
|
|
||||||
export const fetchNovelComments = (id: number, offset=0, count=5) => get<CommentsResponse>(`novels/${id}/comments?offset=${offset}&count=${count}`);
|
export const fetchNovelComments = (id: number, offset = 0, count = 5) => get<CommentsResponse>(`novels/${id}/comments?offset=${offset}&count=${count}`);
|
||||||
export const postNovelComment = (id: number, text: string) => post<CommentType>(`novels/${id}/comments`, { text });
|
export const postNovelComment = (id: number, text: string) => post<CommentType>(`novels/${id}/comments`, { text });
|
||||||
|
|
||||||
export const fetchUserNovel = (userId: number, novelId: number) => get<UserNovelType>(`users/${userId}/novels/${novelId}`);
|
export const fetchUserNovel = (userId: number, novelId: number) => get<UserNovelType>(`users/${userId}/novels/${novelId}`);
|
||||||
export const createUserNovel = (userId: number, novelId: number, status='planned') => post<UserNovelType>(`users/${userId}/novels`, { novel_id: Number(novelId), status });
|
export const createUserNovel = (userId: number, novelId: number, status = 'planned') => post<UserNovelType>(`users/${userId}/novels`, {
|
||||||
|
novel_id: Number(novelId),
|
||||||
|
status
|
||||||
|
});
|
||||||
export const updateUserNovel = (userId: number, novelId: number, data: { mark?: number; status?: string }) => put<UserNovelType>(`users/${userId}/novels/${novelId}`, data);
|
export const updateUserNovel = (userId: number, novelId: number, data: { mark?: number; status?: string }) => put<UserNovelType>(`users/${userId}/novels/${novelId}`, data);
|
||||||
export const deleteUserNovel = (userId: number, novelId: number) => del(`users/${userId}/novels/${novelId}`);
|
export const deleteUserNovel = (userId: number, novelId: number) => del(`users/${userId}/novels/${novelId}`);
|
||||||
|
|||||||
+9
-3
@@ -1,4 +1,4 @@
|
|||||||
import {get, post, put} from "./api";
|
import { get, post, put } from "./api";
|
||||||
|
|
||||||
export const fetchUsers = () => get<UserType[]>('users');
|
export const fetchUsers = () => get<UserType[]>('users');
|
||||||
|
|
||||||
@@ -12,8 +12,14 @@ export const activateAccount = (token: string) => post<string>('auth/activate',
|
|||||||
export const generateActivateLink = () => post<string>('auth/activateToken');
|
export const generateActivateLink = () => post<string>('auth/activateToken');
|
||||||
|
|
||||||
export const fetchUserSettings = () => get<UserSettingsType>('users/me/settings');
|
export const fetchUserSettings = () => get<UserSettingsType>('users/me/settings');
|
||||||
export const updateUserGeneralSettings = (use_gravatar: boolean, avatar: string) => post<UserType>('users/me/settings', { use_gravatar, avatar });
|
export const updateUserGeneralSettings = (use_gravatar: boolean, avatar: string) => post<UserType>('users/me/settings', {
|
||||||
|
use_gravatar,
|
||||||
|
avatar
|
||||||
|
});
|
||||||
export const updateUserAppearanceSettings = (theme: string) => post<UserType>('users/me/settings', { theme });
|
export const updateUserAppearanceSettings = (theme: string) => post<UserType>('users/me/settings', { theme });
|
||||||
export const uploadAvatar = (avatar: FormData) => post<string>('users/me/avatar', avatar);
|
export const uploadAvatar = (avatar: FormData) => post<string>('users/me/avatar', avatar);
|
||||||
|
|
||||||
export const generateRestoreLink = (email: string, recaptcha: string) => post('auth/restoreToken', { email, recaptcha });
|
export const generateRestoreLink = (email: string, recaptcha: string) => post('auth/restoreToken', {
|
||||||
|
email,
|
||||||
|
recaptcha
|
||||||
|
});
|
||||||
|
|||||||
+4
-4
@@ -8,16 +8,16 @@ export default function classNames(...classNames: ClassName[]) {
|
|||||||
let result: string[] = [];
|
let result: string[] = [];
|
||||||
|
|
||||||
classNames.forEach((item: ClassName): void => {
|
classNames.forEach((item: ClassName): void => {
|
||||||
if (!item) {
|
if(!item) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (typeof item) {
|
switch(typeof item) {
|
||||||
case 'string':
|
case 'string':
|
||||||
result.push(item);
|
result.push(item);
|
||||||
break;
|
break;
|
||||||
case 'object':
|
case 'object':
|
||||||
Object.keys(item).forEach((key: string) => {
|
Object.keys(item).forEach((key: string) => {
|
||||||
if (item[key]) {
|
if(item[key]) {
|
||||||
result.push(key);
|
result.push(key);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -28,4 +28,4 @@ export default function classNames(...classNames: ClassName[]) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
return result.join(' ');
|
return result.join(' ');
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-3
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
import {BrowserRouter} from "react-router-dom";
|
import { BrowserRouter } from "react-router-dom";
|
||||||
import {Provider} from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import store from "./store/store";
|
import store from "./store/store";
|
||||||
import * as Sentry from '@sentry/browser';
|
import * as Sentry from '@sentry/browser';
|
||||||
import App from './pages/App/App';
|
import App from './pages/App/App';
|
||||||
@@ -13,7 +13,7 @@ if(process.env.NODE_ENV === 'production')
|
|||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
<BrowserRouter>
|
<BrowserRouter>
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<App />
|
<App/>
|
||||||
</Provider>
|
</Provider>
|
||||||
</BrowserRouter>,
|
</BrowserRouter>,
|
||||||
document.getElementById('root'));
|
document.getElementById('root'));
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {activateAccount} from "../api/users";
|
import { activateAccount } from "../api/users";
|
||||||
import {connect} from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import errors from "../api/errors";
|
import errors from "../api/errors";
|
||||||
import Loading from "../ui/Loading";
|
import Loading from "../ui/Loading";
|
||||||
import {addNotification} from "../store/ducks/notifications";
|
import { addNotification } from "../store/ducks/notifications";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
history: { push: (path: string) => void }
|
history: { push: (path: string) => void }
|
||||||
@@ -35,7 +35,10 @@ class ActivateAccount extends React.Component<Props, State> {
|
|||||||
if(msg) {
|
if(msg) {
|
||||||
this.setState({ msg, error: true });
|
this.setState({ msg, error: true });
|
||||||
} else {
|
} else {
|
||||||
this.setState({ msg: 'Во время активации произошла ошибка! Сообщите об этом разработчику!', error: true });
|
this.setState({
|
||||||
|
msg: 'Во время активации произошла ошибка! Сообщите об этом разработчику!',
|
||||||
|
error: true
|
||||||
|
});
|
||||||
console.error(err.text);
|
console.error(err.text);
|
||||||
}
|
}
|
||||||
if(err.code === 5) {
|
if(err.code === 5) {
|
||||||
@@ -55,7 +58,8 @@ class ActivateAccount extends React.Component<Props, State> {
|
|||||||
const { msg, error } = this.state;
|
const { msg, error } = this.state;
|
||||||
if(msg.length === 0) return <Loading/>;
|
if(msg.length === 0) return <Loading/>;
|
||||||
return (
|
return (
|
||||||
<div className={'Error'} style={{ background: error ? 'var(--error-bg-color)' : 'var(--success-bg-color)' }}>{msg}</div>
|
<div className={'Error'}
|
||||||
|
style={{ background: error ? 'var(--error-bg-color)' : 'var(--success-bg-color)' }}>{msg}</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import {connect} from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import NotFoundError from "../NotFoundError";
|
import NotFoundError from "../NotFoundError";
|
||||||
import {hasAccessToAdminPanel} from "../../utils";
|
import { hasAccessToAdminPanel } from "../../utils";
|
||||||
import './AdminPanel.sass';
|
import './AdminPanel.sass';
|
||||||
import {Link} from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import AdminPanelUsers from "./Users/AdminPanelUsers";
|
import AdminPanelUsers from "./Users/AdminPanelUsers";
|
||||||
import AdminPanelNovels from "./Novels/AdminPanelNovels";
|
import AdminPanelNovels from "./Novels/AdminPanelNovels";
|
||||||
import ModifyUser from "./Users/ModifyUser";
|
import ModifyUser from "./Users/ModifyUser";
|
||||||
@@ -23,12 +23,18 @@ class AdminPanel extends React.Component<Props, State> {
|
|||||||
const { user, match: { path }, location: { pathname } } = this.props;
|
const { user, match: { path }, location: { pathname } } = this.props;
|
||||||
if(!user || !user.group) return <NotFoundError/>;
|
if(!user || !user.group) return <NotFoundError/>;
|
||||||
if(!hasAccessToAdminPanel(user)) return <NotFoundError/>;
|
if(!hasAccessToAdminPanel(user)) return <NotFoundError/>;
|
||||||
const subPath = pathname.slice(path.length+1);
|
const subPath = pathname.slice(path.length + 1);
|
||||||
let component;
|
let component;
|
||||||
switch(subPath) {
|
switch(subPath) {
|
||||||
case 'users': component = <AdminPanelUsers path={`${path}/${subPath}`}/>; break;
|
case 'users':
|
||||||
case 'novels': component = <AdminPanelNovels/>; break;
|
component = <AdminPanelUsers path={`${path}/${subPath}`}/>;
|
||||||
case 'news': component = <APNews path={`${path}/${subPath}`}/>; break;
|
break;
|
||||||
|
case 'novels':
|
||||||
|
component = <AdminPanelNovels/>;
|
||||||
|
break;
|
||||||
|
case 'news':
|
||||||
|
component = <APNews path={`${path}/${subPath}`}/>;
|
||||||
|
break;
|
||||||
default: {
|
default: {
|
||||||
const users = /users\/(\d+)/;
|
const users = /users\/(\d+)/;
|
||||||
const news = /news\/(\d+)/;
|
const news = /news\/(\d+)/;
|
||||||
@@ -43,7 +49,8 @@ class AdminPanel extends React.Component<Props, State> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={'AdminPanel'}>
|
<div className={'AdminPanel'}>
|
||||||
<div className="AdminPanel__Title">Админ панель <span style={{ color: 'var(--error-bg-color)' }}>(в разработке)</span></div>
|
<div className="AdminPanel__Title">Админ панель <span style={{ color: 'var(--error-bg-color)' }}>(в разработке)</span>
|
||||||
|
</div>
|
||||||
<div className="AdminPanel__Router">
|
<div className="AdminPanel__Router">
|
||||||
<Link to={path}>Главная</Link>
|
<Link to={path}>Главная</Link>
|
||||||
<Link to={`${path}/users`}>Пользователи</Link>
|
<Link to={`${path}/users`}>Пользователи</Link>
|
||||||
@@ -60,4 +67,4 @@ export default connect(
|
|||||||
(state: StoreState) => ({
|
(state: StoreState) => ({
|
||||||
user: state.currentUser
|
user: state.currentUser
|
||||||
})
|
})
|
||||||
)(AdminPanel);
|
)(AdminPanel);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, {ChangeEvent, FormEvent} from "react";
|
import React, { ChangeEvent, FormEvent } from "react";
|
||||||
import Group from "../../../ui/Group/Group";
|
import Group from "../../../ui/Group/Group";
|
||||||
import NotFoundError from "../../NotFoundError";
|
import NotFoundError from "../../NotFoundError";
|
||||||
import {deletePost, fetchPost, updatePost} from "../../../api/news";
|
import { deletePost, fetchPost, updatePost } from "../../../api/news";
|
||||||
import './APNews.sass';
|
import './APNews.sass';
|
||||||
import '../../../ui/TextField/TextField.sass'
|
import '../../../ui/TextField/TextField.sass'
|
||||||
import Input from "../../../ui/Input/Input";
|
import Input from "../../../ui/Input/Input";
|
||||||
@@ -10,11 +10,11 @@ import BBEditor from "../../../ui/BBEditor/BBEditor";
|
|||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import parser from 'bbcode-to-react';
|
import parser from 'bbcode-to-react';
|
||||||
import Title from "../../../ui/Title/Title";
|
import Title from "../../../ui/Title/Title";
|
||||||
import {connect} from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import ConfirmPopout from "../../../ui/ConfirmPopout/ConfirmPopout";
|
import ConfirmPopout from "../../../ui/ConfirmPopout/ConfirmPopout";
|
||||||
import NotificationMessage from "../../../ui/Notifications/NotificationMessage";
|
import NotificationMessage from "../../../ui/Notifications/NotificationMessage";
|
||||||
import {setModal} from "../../../store/ducks/modal";
|
import { setModal } from "../../../store/ducks/modal";
|
||||||
import {addNotification} from "../../../store/ducks/notifications";
|
import { addNotification } from "../../../store/ducks/notifications";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
postId: number
|
postId: number
|
||||||
@@ -31,13 +31,12 @@ type State = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class APModifyPost extends React.Component<Props, State> {
|
class APModifyPost extends React.Component<Props, State> {
|
||||||
private shortPost = React.createRef<HTMLTextAreaElement>();
|
|
||||||
private fullPost = React.createRef<HTMLTextAreaElement>();
|
|
||||||
|
|
||||||
state: State = {
|
state: State = {
|
||||||
post: null, title: '',
|
post: null, title: '',
|
||||||
previewShort: '', previewFull: ''
|
previewShort: '', previewFull: ''
|
||||||
}
|
}
|
||||||
|
private shortPost = React.createRef<HTMLTextAreaElement>();
|
||||||
|
private fullPost = React.createRef<HTMLTextAreaElement>();
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
const { postId } = this.props;
|
const { postId } = this.props;
|
||||||
@@ -46,7 +45,7 @@ class APModifyPost extends React.Component<Props, State> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
savePost = async (event: FormEvent) => {
|
savePost = async(event: FormEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
|
||||||
const post = this.state.post;
|
const post = this.state.post;
|
||||||
@@ -115,7 +114,7 @@ class APModifyPost extends React.Component<Props, State> {
|
|||||||
|
|
||||||
<div className={'APPost__Short'}>
|
<div className={'APPost__Short'}>
|
||||||
<Title>Короткая новость</Title>
|
<Title>Короткая новость</Title>
|
||||||
<BBEditor inputRef={this.shortPost} placeholder={'Короткая новость'} />
|
<BBEditor inputRef={this.shortPost} placeholder={'Короткая новость'}/>
|
||||||
{previewShort.length > 0 && (<>
|
{previewShort.length > 0 && (<>
|
||||||
<Title>Предпросмотр</Title>
|
<Title>Предпросмотр</Title>
|
||||||
<div className={'APPost__Short_Preview TextField'}>{previewShort}</div>
|
<div className={'APPost__Short_Preview TextField'}>{previewShort}</div>
|
||||||
@@ -125,7 +124,7 @@ class APModifyPost extends React.Component<Props, State> {
|
|||||||
|
|
||||||
<div className={'APPost__Full'}>
|
<div className={'APPost__Full'}>
|
||||||
<Title>Полная новость</Title>
|
<Title>Полная новость</Title>
|
||||||
<BBEditor inputRef={this.fullPost} placeholder={'Полная новость'} />
|
<BBEditor inputRef={this.fullPost} placeholder={'Полная новость'}/>
|
||||||
{previewFull.length > 0 && (<>
|
{previewFull.length > 0 && (<>
|
||||||
<Title>Предпросмотр</Title>
|
<Title>Предпросмотр</Title>
|
||||||
<div className={'APPost__Full_Preview TextField'}>{previewFull}</div>
|
<div className={'APPost__Full_Preview TextField'}>{previewFull}</div>
|
||||||
@@ -135,7 +134,8 @@ class APModifyPost extends React.Component<Props, State> {
|
|||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Button style={{ marginRight: '1rem' }}>Сохранить</Button>
|
<Button style={{ marginRight: '1rem' }}>Сохранить</Button>
|
||||||
<Button type={"button"} style={{ color: 'var(--error-bg-color)'}} onClick={this.deletePost}>Удалить</Button>
|
<Button type={"button"} style={{ color: 'var(--error-bg-color)' }}
|
||||||
|
onClick={this.deletePost}>Удалить</Button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</Group>
|
</Group>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {fetchNews} from "../../../api/news";
|
import { fetchNews } from "../../../api/news";
|
||||||
import Group from "../../../ui/Group/Group";
|
import Group from "../../../ui/Group/Group";
|
||||||
import {Link} from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import Button from "../../../ui/Button/Button";
|
import Button from "../../../ui/Button/Button";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -41,4 +41,4 @@ class APNews extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default APNews;
|
export default APNews;
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {connect} from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
type Props = {
|
type Props = {};
|
||||||
|
|
||||||
};
|
type State = {};
|
||||||
|
|
||||||
type State = {
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
class AdminPanelNovels extends React.Component<Props, State> {
|
class AdminPanelNovels extends React.Component<Props, State> {
|
||||||
render() {
|
render() {
|
||||||
@@ -21,4 +17,4 @@ export default connect(
|
|||||||
(state: StoreState) => ({
|
(state: StoreState) => ({
|
||||||
user: state.currentUser
|
user: state.currentUser
|
||||||
})
|
})
|
||||||
)(AdminPanelNovels);
|
)(AdminPanelNovels);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {connect} from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import {fetchUsers} from "../../../api/users";
|
import { fetchUsers } from "../../../api/users";
|
||||||
import {Link} from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
path: string
|
path: string
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import React, {ChangeEvent, FormEvent} from "react";
|
import React, { ChangeEvent, FormEvent } from "react";
|
||||||
import {connect} from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import {fetchUser, updateUser} from "../../../api/users";
|
import { fetchUser, updateUser } from "../../../api/users";
|
||||||
import Loading from "../../../ui/Loading";
|
import Loading from "../../../ui/Loading";
|
||||||
import './APUser.sass';
|
import './APUser.sass';
|
||||||
import NotificationMessage from "../../../ui/Notifications/NotificationMessage";
|
import NotificationMessage from "../../../ui/Notifications/NotificationMessage";
|
||||||
import Button from "../../../ui/Button/Button";
|
import Button from "../../../ui/Button/Button";
|
||||||
import {addNotification} from "../../../store/ducks/notifications";
|
import { addNotification } from "../../../store/ducks/notifications";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
userId: number
|
userId: number
|
||||||
@@ -65,12 +65,17 @@ class ModifyUser extends React.Component<Props, State> {
|
|||||||
<div className={'APUser__Modify'}>
|
<div className={'APUser__Modify'}>
|
||||||
<div className={'APUser__Modify_Title'}>{username}</div>
|
<div className={'APUser__Modify_Title'}>{username}</div>
|
||||||
<form className={'APUser__Modify_Form'} onSubmit={this.onSubmit}>
|
<form className={'APUser__Modify_Form'} onSubmit={this.onSubmit}>
|
||||||
<label>Имя пользователя: <input type="text" onChange={this.onChange} name={'username'} value={user.username}/></label>
|
<label>Имя пользователя: <input type="text" onChange={this.onChange} name={'username'}
|
||||||
<label>Email: <input type='email' onChange={this.onChange} name={'email'} value={user.email}/></label>
|
value={user.username}/></label>
|
||||||
<label>Аватар: <input type='text' onChange={this.onChange} name={'avatar'} value={user.avatar}/></label>
|
<label>Email: <input type='email' onChange={this.onChange} name={'email'}
|
||||||
|
value={user.email}/></label>
|
||||||
|
<label>Аватар: <input type='text' onChange={this.onChange} name={'avatar'}
|
||||||
|
value={user.avatar}/></label>
|
||||||
|
|
||||||
<label>Суперюзер: <input type='checkbox' onChange={this.onChange} name={'is_superuser'} checked={user.is_superuser}/></label>
|
<label>Суперюзер: <input type='checkbox' onChange={this.onChange} name={'is_superuser'}
|
||||||
<label>Активирован: <input type='checkbox' onChange={this.onChange} name={'is_activated'} checked={user.is_activated}/></label>
|
checked={user.is_superuser}/></label>
|
||||||
|
<label>Активирован: <input type='checkbox' onChange={this.onChange} name={'is_activated'}
|
||||||
|
checked={user.is_activated}/></label>
|
||||||
|
|
||||||
<div style={{ textAlign: "right" }}>
|
<div style={{ textAlign: "right" }}>
|
||||||
<Button>Сохранить!</Button>
|
<Button>Сохранить!</Button>
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import {Switch, Route} from "react-router-dom";
|
import { Route, Switch } from "react-router-dom";
|
||||||
import './App.sass';
|
import './App.sass';
|
||||||
import Navbar from "../Navbar/Navbar";
|
import Navbar from "../Navbar/Navbar";
|
||||||
import Novel from "../Novel/Novel";
|
import Novel from "../Novel/Novel";
|
||||||
import User from "../User/User";
|
import User from "../User/User";
|
||||||
import Main from "../Main/Main"
|
import Main from "../Main/Main"
|
||||||
import NotFoundError from "../NotFoundError";
|
import NotFoundError from "../NotFoundError";
|
||||||
import {fetchCurrentUser, fetchUserSettings} from "../../api/users";
|
import { fetchCurrentUser, fetchUserSettings } from "../../api/users";
|
||||||
import {connect} from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import Character from "../Character/Character";
|
import Character from "../Character/Character";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import parser from 'bbcode-to-react';
|
import parser from 'bbcode-to-react';
|
||||||
@@ -23,10 +23,10 @@ import AdminPanel from "../AdminPanel/AdminPanel";
|
|||||||
import PasswordRestoreGenerate from "../PasswordRestore/PasswordRestoreGenerate";
|
import PasswordRestoreGenerate from "../PasswordRestore/PasswordRestoreGenerate";
|
||||||
import PasswordRestore from "../PasswordRestore/PasswordRestore";
|
import PasswordRestore from "../PasswordRestore/PasswordRestore";
|
||||||
import Users from "../Users/Users";
|
import Users from "../Users/Users";
|
||||||
import {getVersion, version} from "../../api/api";
|
import { getVersion, version } from "../../api/api";
|
||||||
import Settings from "../User/Settings/Settings";
|
import Settings from "../User/Settings/Settings";
|
||||||
import {setUser} from "../../store/ducks/currentUser";
|
import { setUser } from "../../store/ducks/currentUser";
|
||||||
import {setSettings} from "../../store/ducks/userSettings";
|
import { setSettings } from "../../store/ducks/userSettings";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
notifications: React.ReactNode[]
|
notifications: React.ReactNode[]
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {fetchChar, fetchCharNovels} from "../../api/characters";
|
import { fetchChar, fetchCharNovels } from "../../api/characters";
|
||||||
import './Character.sass'
|
import './Character.sass'
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import parser from 'bbcode-to-react';
|
import parser from 'bbcode-to-react';
|
||||||
@@ -50,11 +50,11 @@ class Character extends React.Component<Props, State> {
|
|||||||
</div>
|
</div>
|
||||||
{novels.length > 0 &&
|
{novels.length > 0 &&
|
||||||
<div className="Character__Novels">
|
<div className="Character__Novels">
|
||||||
{novels.map(novel => <NovelItem {...novel} key={novel.id} viewType='grid' />)}
|
{novels.map(novel => <NovelItem {...novel} key={novel.id} viewType='grid'/>)}
|
||||||
</div>}
|
</div>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Character;
|
export default Character;
|
||||||
|
|||||||
@@ -1,47 +1,47 @@
|
|||||||
@import '../../Constants'
|
@import '../../Constants'
|
||||||
|
|
||||||
.Comments
|
.Comments
|
||||||
margin-top: 1rem
|
margin-top: 1rem
|
||||||
padding: $primaryPadding
|
padding: $primaryPadding
|
||||||
background-color: var(--sec-bg-color)
|
background-color: var(--sec-bg-color)
|
||||||
border-radius: $borderRadius
|
border-radius: $borderRadius
|
||||||
|
|
||||||
form
|
form
|
||||||
width: 100%
|
width: 100%
|
||||||
margin-bottom: .5rem
|
margin-bottom: .5rem
|
||||||
|
|
||||||
.Comments_BBCodes
|
.Comments_BBCodes
|
||||||
font-size: 1.3rem
|
font-size: 1.3rem
|
||||||
margin-bottom: .2rem
|
margin-bottom: .2rem
|
||||||
|
|
||||||
svg
|
svg
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
|
|
||||||
svg:first-child
|
svg:first-child
|
||||||
padding-right: .5rem
|
padding-right: .5rem
|
||||||
|
|
||||||
svg:last-child
|
svg:last-child
|
||||||
padding-left: .5rem
|
padding-left: .5rem
|
||||||
|
|
||||||
svg:not(:first-child):not(:last-child)
|
svg:not(:first-child):not(:last-child)
|
||||||
padding: 0 .5rem
|
padding: 0 .5rem
|
||||||
|
|
||||||
.Comments_TextArea
|
.Comments_TextArea
|
||||||
width: 100%
|
width: 100%
|
||||||
color: var(--main-color)
|
color: var(--main-color)
|
||||||
background-color: var(--block-color)
|
background-color: var(--block-color)
|
||||||
font-size: 1rem
|
font-size: 1rem
|
||||||
padding: .25rem
|
padding: .25rem
|
||||||
border: none
|
border: none
|
||||||
border-radius: .2rem
|
border-radius: .2rem
|
||||||
box-sizing: border-box
|
box-sizing: border-box
|
||||||
min-height: 4rem
|
min-height: 4rem
|
||||||
resize: none
|
resize: none
|
||||||
margin-bottom: .5rem
|
margin-bottom: .5rem
|
||||||
|
|
||||||
.Comments_Submit
|
.Comments_Submit
|
||||||
background-color: var(--block-color) !important
|
background-color: var(--block-color) !important
|
||||||
border-radius: .2rem
|
border-radius: .2rem
|
||||||
border: none
|
border: none
|
||||||
font-size: 1rem
|
font-size: 1rem
|
||||||
padding: .5rem
|
padding: .5rem
|
||||||
|
|||||||
@@ -1,14 +1,21 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { faBold, faExclamationTriangle, faItalic, faStrikethrough, faUnderline, faTint } from "@fortawesome/free-solid-svg-icons";
|
import {
|
||||||
|
faBold,
|
||||||
|
faExclamationTriangle,
|
||||||
|
faItalic,
|
||||||
|
faStrikethrough,
|
||||||
|
faTint,
|
||||||
|
faUnderline
|
||||||
|
} from "@fortawesome/free-solid-svg-icons";
|
||||||
import Comment from '../../ui/Comment/Comment';
|
import Comment from '../../ui/Comment/Comment';
|
||||||
import './Comments.sass';
|
import './Comments.sass';
|
||||||
import Loading from "../../ui/Loading";
|
import Loading from "../../ui/Loading";
|
||||||
import {fetchUser} from "../../api/users";
|
import { fetchUser } from "../../api/users";
|
||||||
import {connect} from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import NotificationMessage from "../../ui/Notifications/NotificationMessage";
|
import NotificationMessage from "../../ui/Notifications/NotificationMessage";
|
||||||
import Button from "../../ui/Button/Button";
|
import Button from "../../ui/Button/Button";
|
||||||
import {addNotification} from "../../store/ducks/notifications";
|
import { addNotification } from "../../store/ducks/notifications";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
comments: CommentType[]
|
comments: CommentType[]
|
||||||
@@ -86,40 +93,43 @@ class Comments extends React.Component<Props, State> {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="Comments">
|
<div className="Comments">
|
||||||
{user.authorized &&
|
{user.authorized &&
|
||||||
<form onSubmit={this.sendComment}>
|
<form onSubmit={this.sendComment}>
|
||||||
<div className="Comments_BBCodes">
|
<div className="Comments_BBCodes">
|
||||||
<FontAwesomeIcon onClick={event => this.addTagToComment(event, 'b')} icon={faBold}/>
|
<FontAwesomeIcon onClick={event => this.addTagToComment(event, 'b')} icon={faBold}/>
|
||||||
<FontAwesomeIcon onClick={event => this.addTagToComment(event, 'i')} icon={faItalic}/>
|
<FontAwesomeIcon onClick={event => this.addTagToComment(event, 'i')} icon={faItalic}/>
|
||||||
<FontAwesomeIcon onClick={event => this.addTagToComment(event, 'u')} icon={faUnderline}/>
|
<FontAwesomeIcon onClick={event => this.addTagToComment(event, 'u')} icon={faUnderline}/>
|
||||||
<FontAwesomeIcon onClick={event => this.addTagToComment(event, 's')} icon={faStrikethrough}/>
|
<FontAwesomeIcon onClick={event => this.addTagToComment(event, 's')} icon={faStrikethrough}/>
|
||||||
<FontAwesomeIcon onClick={event => this.addTagToComment(event, 'spoiler')} icon={faExclamationTriangle}/>
|
<FontAwesomeIcon onClick={event => this.addTagToComment(event, 'spoiler')}
|
||||||
<FontAwesomeIcon onClick={event => this.addTagToComment(event, 'color', 'white')} icon={faTint}/>
|
icon={faExclamationTriangle}/>
|
||||||
</div>
|
<FontAwesomeIcon onClick={event => this.addTagToComment(event, 'color', 'white')}
|
||||||
<textarea
|
icon={faTint}/>
|
||||||
className={'Comments_TextArea'}
|
|
||||||
placeholder={'Текст комментария'}
|
|
||||||
value={commentText}
|
|
||||||
onChange={(event) => this.setState({ commentText: event.target.value })}
|
|
||||||
ref={ref => this.input = ref}
|
|
||||||
/>
|
|
||||||
<div style={{ display: "flex", justifyContent: "space-between" }}>
|
|
||||||
<div style={{ display: "flex", alignItems: "center" }}>
|
|
||||||
<Button type="submit" className={'Comments_Submit'}>Написать</Button>
|
|
||||||
<div style={{ marginLeft: '.5rem', color: '#bb3333' }}>Комментарии в разработке!</div>
|
|
||||||
</div>
|
</div>
|
||||||
{hasMore && <Button onClick={loadMore}>Загрузить ещё</Button>}
|
<textarea
|
||||||
</div>
|
className={'Comments_TextArea'}
|
||||||
</form>}
|
placeholder={'Текст комментария'}
|
||||||
{!comments && (
|
value={commentText}
|
||||||
<Loading/>
|
onChange={(event) => this.setState({ commentText: event.target.value })}
|
||||||
)}
|
ref={ref => this.input = ref}
|
||||||
{comments && comments.length > 0 ? (
|
/>
|
||||||
comments.map(comment => <Comment text={comment.text} key={comment.id} user={users.get(comment.user_id)} />)
|
<div style={{ display: "flex", justifyContent: "space-between" }}>
|
||||||
) : (
|
<div style={{ display: "flex", alignItems: "center" }}>
|
||||||
'Никто не оставил комментарий к этой новелле... :c'
|
<Button type="submit" className={'Comments_Submit'}>Написать</Button>
|
||||||
)}
|
<div style={{ marginLeft: '.5rem', color: '#bb3333' }}>Комментарии в разработке!</div>
|
||||||
</div>
|
</div>
|
||||||
|
{hasMore && <Button onClick={loadMore}>Загрузить ещё</Button>}
|
||||||
|
</div>
|
||||||
|
</form>}
|
||||||
|
{!comments && (
|
||||||
|
<Loading/>
|
||||||
|
)}
|
||||||
|
{comments && comments.length > 0 ? (
|
||||||
|
comments.map(comment => <Comment text={comment.text} key={comment.id}
|
||||||
|
user={users.get(comment.user_id)}/>)
|
||||||
|
) : (
|
||||||
|
'Никто не оставил комментарий к этой новелле... :c'
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import './Footer.sass';
|
import './Footer.sass';
|
||||||
import {Link} from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import { faDiscord, faVk, faTelegramPlane } from '@fortawesome/free-brands-svg-icons';
|
import { faDiscord, faTelegramPlane, faVk } from '@fortawesome/free-brands-svg-icons';
|
||||||
|
|
||||||
const Footer: React.FC = () => {
|
const Footer: React.FC = () => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {fetchNews} from "../../api/news";
|
import { fetchNews } from "../../api/news";
|
||||||
import Loading from "../../ui/Loading";
|
import Loading from "../../ui/Loading";
|
||||||
import {Link} from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import NewsPost from "../../ui/NewsPost/NewsPost";
|
import NewsPost from "../../ui/NewsPost/NewsPost";
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
@@ -40,4 +40,4 @@ class News extends React.Component<{}, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default News;
|
export default News;
|
||||||
|
|||||||
@@ -42,5 +42,6 @@
|
|||||||
|
|
||||||
p
|
p
|
||||||
margin: 0 .2rem
|
margin: 0 .2rem
|
||||||
|
|
||||||
*
|
*
|
||||||
margin: 0
|
margin: 0
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
import React, {FormEvent, ChangeEvent} from "react";
|
import React, { ChangeEvent, FormEvent } from "react";
|
||||||
import Modal from "../../ui/Modal/Modal";
|
import Modal from "../../ui/Modal/Modal";
|
||||||
import {login} from "../../api/auth";
|
import { login } from "../../api/auth";
|
||||||
import {connect} from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import './LoginModal.sass'
|
import './LoginModal.sass'
|
||||||
import {Link} from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import errors from "../../api/errors";
|
import errors from "../../api/errors";
|
||||||
import NotificationMessage from "../../ui/Notifications/NotificationMessage";
|
import NotificationMessage from "../../ui/Notifications/NotificationMessage";
|
||||||
import Recaptcha from '../../ui/Recaptcha/Recaptcha'
|
import Recaptcha from '../../ui/Recaptcha/Recaptcha'
|
||||||
import Button from "../../ui/Button/Button";
|
import Button from "../../ui/Button/Button";
|
||||||
import RegisterModal from "./RegisterModal";
|
import RegisterModal from "./RegisterModal";
|
||||||
import Input from "../../ui/Input/Input";
|
import Input from "../../ui/Input/Input";
|
||||||
import {setUser} from "../../store/ducks/currentUser";
|
import { setUser } from "../../store/ducks/currentUser";
|
||||||
import {addNotification} from "../../store/ducks/notifications";
|
import { addNotification } from "../../store/ducks/notifications";
|
||||||
import {hideModal, setModal} from "../../store/ducks/modal";
|
import { hideModal, setModal } from "../../store/ducks/modal";
|
||||||
import {fetchUserSettings} from "../../api/users";
|
import { fetchUserSettings } from "../../api/users";
|
||||||
import {setSettings} from "../../store/ducks/userSettings";
|
import { setSettings } from "../../store/ducks/userSettings";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
setUser: SetUser
|
setUser: SetUser
|
||||||
|
|||||||
@@ -45,5 +45,6 @@
|
|||||||
|
|
||||||
p
|
p
|
||||||
margin: 0 .2rem
|
margin: 0 .2rem
|
||||||
|
|
||||||
*
|
*
|
||||||
margin: 0
|
margin: 0
|
||||||
|
|||||||
@@ -2,13 +2,13 @@ import React from "react";
|
|||||||
import Modal from "../../ui/Modal/Modal";
|
import Modal from "../../ui/Modal/Modal";
|
||||||
import Recaptcha from '../../ui/Recaptcha/Recaptcha'
|
import Recaptcha from '../../ui/Recaptcha/Recaptcha'
|
||||||
import './RegisterModal.sass'
|
import './RegisterModal.sass'
|
||||||
import {registerUser} from "../../api/auth";
|
import { registerUser } from "../../api/auth";
|
||||||
import {connect} from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import NotificationMessage from "../../ui/Notifications/NotificationMessage";
|
import NotificationMessage from "../../ui/Notifications/NotificationMessage";
|
||||||
import Button from "../../ui/Button/Button";
|
import Button from "../../ui/Button/Button";
|
||||||
import Input from "../../ui/Input/Input";
|
import Input from "../../ui/Input/Input";
|
||||||
import {addNotification} from "../../store/ducks/notifications";
|
import { addNotification } from "../../store/ducks/notifications";
|
||||||
import {setModal} from "../../store/ducks/modal";
|
import { setModal } from "../../store/ducks/modal";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
addNotification: (notification: React.ReactNode) => void
|
addNotification: (notification: React.ReactNode) => void
|
||||||
@@ -25,10 +25,10 @@ type State = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class RegisterModal extends React.Component<Props, State> {
|
class RegisterModal extends React.Component<Props, State> {
|
||||||
private recaptcha: any;
|
|
||||||
state = {
|
state = {
|
||||||
error: '', login: '', password1: '', password2: '', email: '', recaptcha: ''
|
error: '', login: '', password1: '', password2: '', email: '', recaptcha: ''
|
||||||
};
|
};
|
||||||
|
private recaptcha: any;
|
||||||
|
|
||||||
handlePassword1Change = (event: any) => this.setState({ password1: event.target.value });
|
handlePassword1Change = (event: any) => this.setState({ password1: event.target.value });
|
||||||
handlePassword2Change = (event: any) => this.setState({ password2: event.target.value });
|
handlePassword2Change = (event: any) => this.setState({ password2: event.target.value });
|
||||||
@@ -55,7 +55,8 @@ class RegisterModal extends React.Component<Props, State> {
|
|||||||
const notification = (
|
const notification = (
|
||||||
<NotificationMessage level={"success"}>
|
<NotificationMessage level={"success"}>
|
||||||
Аккаунт успешно создан!
|
Аккаунт успешно создан!
|
||||||
Проверьте почту <strong>{email}</strong>. На неё была отправлена ссылка для подтверждения аккаунта.
|
Проверьте почту <strong>{email}</strong>. На неё была отправлена ссылка для подтверждения
|
||||||
|
аккаунта.
|
||||||
</NotificationMessage>
|
</NotificationMessage>
|
||||||
);
|
);
|
||||||
const { addNotification, setModal } = this.props;
|
const { addNotification, setModal } = this.props;
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ $hoverColor: #f22
|
|||||||
&__Dropdown
|
&__Dropdown
|
||||||
cursor: pointer
|
cursor: pointer
|
||||||
|
|
||||||
&:hover>&_Menu
|
&:hover > &_Menu
|
||||||
display: flex
|
display: flex
|
||||||
flex-direction: column
|
flex-direction: column
|
||||||
|
|
||||||
|
|||||||
+22
-18
@@ -1,15 +1,15 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import './Navbar.sass'
|
import './Navbar.sass'
|
||||||
import {connect} from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import {userLogout} from "../../api/auth";
|
import { userLogout } from "../../api/auth";
|
||||||
import {Link} from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import {hasAccessToAdminPanel} from "../../utils";
|
import { hasAccessToAdminPanel } from "../../utils";
|
||||||
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import {faBars} from '@fortawesome/free-solid-svg-icons';
|
import { faBars } from '@fortawesome/free-solid-svg-icons';
|
||||||
import RegisterModal from "../Modals/RegisterModal";
|
import RegisterModal from "../Modals/RegisterModal";
|
||||||
import LoginModal from "../Modals/LoginModal";
|
import LoginModal from "../Modals/LoginModal";
|
||||||
import {logout} from "../../store/ducks/currentUser";
|
import { logout } from "../../store/ducks/currentUser";
|
||||||
import {setModal} from "../../store/ducks/modal";
|
import { setModal } from "../../store/ducks/modal";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
setModal: SetModal
|
setModal: SetModal
|
||||||
@@ -32,7 +32,8 @@ class Navbar extends React.Component<Props, State> {
|
|||||||
localStorage.removeItem('user');
|
localStorage.removeItem('user');
|
||||||
localStorage.removeItem('theme');
|
localStorage.removeItem('theme');
|
||||||
document.querySelector('body')!!.removeAttribute('theme');
|
document.querySelector('body')!!.removeAttribute('theme');
|
||||||
userLogout().catch(() => {});
|
userLogout().catch(() => {
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
changeSize = () => {
|
changeSize = () => {
|
||||||
@@ -61,7 +62,8 @@ class Navbar extends React.Component<Props, State> {
|
|||||||
Новеллы
|
Новеллы
|
||||||
</Link>
|
</Link>
|
||||||
{expand && isMinimized && (
|
{expand && isMinimized && (
|
||||||
<div onClick={this.changeSize} className={'Navbar_Button'} style={{ position: "absolute", right: 0, margin: '.5rem' }}>X</div>
|
<div onClick={this.changeSize} className={'Navbar_Button'}
|
||||||
|
style={{ position: "absolute", right: 0, margin: '.5rem' }}>X</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -69,7 +71,8 @@ class Navbar extends React.Component<Props, State> {
|
|||||||
const user = isMinimized ? (
|
const user = isMinimized ? (
|
||||||
<div className={'Navbar__Dropdown'}>
|
<div className={'Navbar__Dropdown'}>
|
||||||
<div className="Navbar__Dropdown_Button Navbar__User_Profile">
|
<div className="Navbar__Dropdown_Button Navbar__User_Profile">
|
||||||
<div className={'Navbar__User_Avatar'} style={{ backgroundImage: `url(${currentUser.avatar}?s=40&t=${new Date().getTime()})` }}/>
|
<div className={'Navbar__User_Avatar'}
|
||||||
|
style={{ backgroundImage: `url(${currentUser.avatar}?s=40&t=${new Date().getTime()})` }}/>
|
||||||
<div>{this.props.currentUser.username}</div>
|
<div>{this.props.currentUser.username}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="Navbar__Dropdown_Menu">
|
<div className="Navbar__Dropdown_Menu">
|
||||||
@@ -85,7 +88,8 @@ class Navbar extends React.Component<Props, State> {
|
|||||||
</div>
|
</div>
|
||||||
) : (<>
|
) : (<>
|
||||||
<Link to={`/user/${currentUser.id}`} className="Navbar__User_Profile">
|
<Link to={`/user/${currentUser.id}`} className="Navbar__User_Profile">
|
||||||
<div className={'Navbar__User_Avatar'} style={{ backgroundImage: `url(${currentUser.avatar}?s=40&t=${new Date().getTime()})` }}/>
|
<div className={'Navbar__User_Avatar'}
|
||||||
|
style={{ backgroundImage: `url(${currentUser.avatar}?s=40&t=${new Date().getTime()})` }}/>
|
||||||
<div>{this.props.currentUser.username}</div>
|
<div>{this.props.currentUser.username}</div>
|
||||||
</Link>
|
</Link>
|
||||||
{currentUser.group && hasAccessToAdminPanel(currentUser) && (
|
{currentUser.group && hasAccessToAdminPanel(currentUser) && (
|
||||||
@@ -107,12 +111,12 @@ class Navbar extends React.Component<Props, State> {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{currentUser &&
|
{currentUser &&
|
||||||
(<div className={'Navbar__User'}>
|
(<div className={'Navbar__User'}>
|
||||||
{currentUser.authorized ? user : (<>
|
{currentUser.authorized ? user : (<>
|
||||||
<div className={'Navbar_Button'} onClick={() => setModal(<RegisterModal/>)}>Регистрация</div>
|
<div className={'Navbar_Button'} onClick={() => setModal(<RegisterModal/>)}>Регистрация</div>
|
||||||
<div className={'Navbar_Button'} onClick={() => setModal(<LoginModal/>)}>Войти</div>
|
<div className={'Navbar_Button'} onClick={() => setModal(<LoginModal/>)}>Войти</div>
|
||||||
</>)}
|
</>)}
|
||||||
</div>)
|
</div>)
|
||||||
}
|
}
|
||||||
</nav>
|
</nav>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Loading from "../../ui/Loading";
|
import Loading from "../../ui/Loading";
|
||||||
import {fetchNews} from "../../api/news";
|
import { fetchNews } from "../../api/news";
|
||||||
import NewsPost from "../../ui/NewsPost/NewsPost";
|
import NewsPost from "../../ui/NewsPost/NewsPost";
|
||||||
import {Link} from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
news: PostType[]
|
news: PostType[]
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {fetchPost} from "../../api/news";
|
import { fetchPost } from "../../api/news";
|
||||||
import Loading from "../../ui/Loading";
|
import Loading from "../../ui/Loading";
|
||||||
import NotFoundError from "../NotFoundError";
|
import NotFoundError from "../NotFoundError";
|
||||||
import './Post.sass'
|
import './Post.sass'
|
||||||
import {Link} from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import parser from 'bbcode-to-react';
|
import parser from 'bbcode-to-react';
|
||||||
|
|
||||||
@@ -22,7 +22,7 @@ class Post extends React.Component<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
const { match: { params: { postId }} } = this.props;
|
const { match: { params: { postId } } } = this.props;
|
||||||
|
|
||||||
fetchPost(postId).then((post: PostType) => {
|
fetchPost(postId).then((post: PostType) => {
|
||||||
post.date = new Date(post.date);
|
post.date = new Date(post.date);
|
||||||
@@ -34,7 +34,7 @@ class Post extends React.Component<Props, State> {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { post, code } = this.state;
|
const { post, code } = this.state;
|
||||||
|
|
||||||
if(code === 100) return <NotFoundError/>;
|
if(code === 100) return <NotFoundError/>;
|
||||||
if(!post) return <Loading/>;
|
if(!post) return <Loading/>;
|
||||||
return (
|
return (
|
||||||
@@ -52,4 +52,4 @@ class Post extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Post;
|
export default Post;
|
||||||
|
|||||||
@@ -2,11 +2,11 @@ import React from "react";
|
|||||||
|
|
||||||
function NotFoundError() {
|
function NotFoundError() {
|
||||||
return (
|
return (
|
||||||
<div style={{textAlign: 'center'}}>
|
<div style={{ textAlign: 'center' }}>
|
||||||
<div style={{fontSize: '2rem'}}>Увы, данная страница не найдена!</div>
|
<div style={{ fontSize: '2rem' }}>Увы, данная страница не найдена!</div>
|
||||||
<div>Проверьте правильность написания ссылки!</div>
|
<div>Проверьте правильность написания ссылки!</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NotFoundError;
|
export default NotFoundError;
|
||||||
|
|||||||
+37
-26
@@ -1,22 +1,24 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import './Novel.sass'
|
import './Novel.sass'
|
||||||
import NotFoundError from "../NotFoundError";
|
import NotFoundError from "../NotFoundError";
|
||||||
import {connect} from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import {
|
import {
|
||||||
|
createUserNovel,
|
||||||
|
deleteUserNovel,
|
||||||
fetchNovel,
|
fetchNovel,
|
||||||
fetchNovelCharacters,
|
fetchNovelCharacters,
|
||||||
fetchNovelComments,
|
fetchNovelComments,
|
||||||
|
fetchNovelGenres,
|
||||||
fetchUserNovel,
|
fetchUserNovel,
|
||||||
updateUserNovel,
|
postNovelComment,
|
||||||
deleteUserNovel,
|
updateUserNovel
|
||||||
fetchNovelGenres, postNovelComment, createUserNovel
|
|
||||||
} from "../../api/novels";
|
} from "../../api/novels";
|
||||||
import {Link} from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import Loading from "../../ui/Loading";
|
import Loading from "../../ui/Loading";
|
||||||
import {TranslateExitStatus, TranslateStatus} from "../../api/api";
|
import { TranslateExitStatus, TranslateStatus } from "../../api/api";
|
||||||
import Comments from "../Comments/Comments";
|
import Comments from "../Comments/Comments";
|
||||||
import LoadingModal from "../Modals/LoadingModal";
|
import LoadingModal from "../Modals/LoadingModal";
|
||||||
import {hideModal, setModal} from "../../store/ducks/modal";
|
import { hideModal, setModal } from "../../store/ducks/modal";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
currentUser: UserType
|
currentUser: UserType
|
||||||
@@ -47,7 +49,7 @@ class Novel extends React.Component<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
updateNovelStatus = (status: string) => {
|
updateNovelStatus = (status: string) => {
|
||||||
const { match: { params } , currentUser, setModal, hideModal } = this.props;
|
const { match: { params }, currentUser, setModal, hideModal } = this.props;
|
||||||
const { userData } = this.state;
|
const { userData } = this.state;
|
||||||
|
|
||||||
setModal(<LoadingModal/>);
|
setModal(<LoadingModal/>);
|
||||||
@@ -65,7 +67,7 @@ class Novel extends React.Component<Props, State> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
deleteNovelStatus = () => {
|
deleteNovelStatus = () => {
|
||||||
const { match: { params } , currentUser, setModal, hideModal } = this.props;
|
const { match: { params }, currentUser, setModal, hideModal } = this.props;
|
||||||
|
|
||||||
setModal(<LoadingModal/>);
|
setModal(<LoadingModal/>);
|
||||||
deleteUserNovel(currentUser.id, params.novelId).then(() => {
|
deleteUserNovel(currentUser.id, params.novelId).then(() => {
|
||||||
@@ -114,14 +116,14 @@ class Novel extends React.Component<Props, State> {
|
|||||||
document.title = novel.localized_name ? `${novel.original_name} / ${novel.localized_name}` : novel.original_name;
|
document.title = novel.localized_name ? `${novel.original_name} / ${novel.localized_name}` : novel.original_name;
|
||||||
|
|
||||||
fetchNovelComments(params.novelId).then(r => {
|
fetchNovelComments(params.novelId).then(r => {
|
||||||
const hasMoreComments = r.count > 5;
|
const hasMoreComments = r.count > 5;
|
||||||
this.setState({ comments: r.comments.reverse(), hasMoreComments })
|
this.setState({ comments: r.comments.reverse(), hasMoreComments })
|
||||||
});
|
|
||||||
fetchNovelCharacters(params.novelId).then(characters => this.setState({ characters }));
|
|
||||||
fetchNovelGenres(params.novelId).then(genres => this.setState({ genres }));
|
|
||||||
}).catch((err: ApiError) => {
|
|
||||||
this.setState({ errorCode: err.code });
|
|
||||||
});
|
});
|
||||||
|
fetchNovelCharacters(params.novelId).then(characters => this.setState({ characters }));
|
||||||
|
fetchNovelGenres(params.novelId).then(genres => this.setState({ genres }));
|
||||||
|
}).catch((err: ApiError) => {
|
||||||
|
this.setState({ errorCode: err.code });
|
||||||
|
});
|
||||||
|
|
||||||
if(currentUser.authorized)
|
if(currentUser.authorized)
|
||||||
fetchUserNovel(currentUser.id, params.novelId).then((userData: UserNovelType) => {
|
fetchUserNovel(currentUser.id, params.novelId).then((userData: UserNovelType) => {
|
||||||
@@ -146,7 +148,7 @@ class Novel extends React.Component<Props, State> {
|
|||||||
|
|
||||||
countNovelDuration = (t: number) => {
|
countNovelDuration = (t: number) => {
|
||||||
const h = Math.round(t / 60);
|
const h = Math.round(t / 60);
|
||||||
const m = t - (t*60);
|
const m = t - (t * 60);
|
||||||
|
|
||||||
if(h === 0) return `${m} мин`;
|
if(h === 0) return `${m} мин`;
|
||||||
else return `${h} ч`;
|
else return `${h} ч`;
|
||||||
@@ -169,8 +171,10 @@ class Novel extends React.Component<Props, State> {
|
|||||||
<div className={'Novel__Main_Status'}>
|
<div className={'Novel__Main_Status'}>
|
||||||
<div className="Novel__Main_Status_Primary">
|
<div className="Novel__Main_Status_Primary">
|
||||||
{!userData
|
{!userData
|
||||||
? <div className={'Novel__Main_Status_Element'} onClick={() => this.updateNovelStatus('planned')}>Добавить в список</div>
|
? <div className={'Novel__Main_Status_Element'}
|
||||||
: <div className={"Novel__Main_Status_Element"}>{TranslateStatus[userData.status]}</div>}
|
onClick={() => this.updateNovelStatus('planned')}>Добавить в список</div>
|
||||||
|
: <div
|
||||||
|
className={"Novel__Main_Status_Element"}>{TranslateStatus[userData.status]}</div>}
|
||||||
{userData && (
|
{userData && (
|
||||||
<div
|
<div
|
||||||
className={'Novel__Main_Status_Element'}
|
className={'Novel__Main_Status_Element'}
|
||||||
@@ -184,12 +188,15 @@ class Novel extends React.Component<Props, State> {
|
|||||||
{statusExpanded &&
|
{statusExpanded &&
|
||||||
<div className="Novel__Main_Status_Extended">
|
<div className="Novel__Main_Status_Extended">
|
||||||
{userData && Object.entries(TranslateStatus).filter(([eng]) => eng !== userData.status).map(([eng, rus]) => (
|
{userData && Object.entries(TranslateStatus).filter(([eng]) => eng !== userData.status).map(([eng, rus]) => (
|
||||||
<div key={eng} className="Novel__Main_Status_Element" onClick={() => this.updateNovelStatus(eng)}>{rus}</div>
|
<div key={eng} className="Novel__Main_Status_Element"
|
||||||
|
onClick={() => this.updateNovelStatus(eng)}>{rus}</div>
|
||||||
))}
|
))}
|
||||||
<div className={"Novel__Main_Status_Element"} style={{ color: 'red' }} onClick={this.deleteNovelStatus}>Удалить из списка</div>
|
<div className={"Novel__Main_Status_Element"} style={{ color: 'red' }}
|
||||||
|
onClick={this.deleteNovelStatus}>Удалить из списка
|
||||||
|
</div>
|
||||||
</div>}
|
</div>}
|
||||||
<div className={'Novel__Main_Status_Mark'}>
|
<div className={'Novel__Main_Status_Mark'}>
|
||||||
{userData && [0,1,2,3,4,5,6,7,8,9,10].map(mark => (
|
{userData && [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map(mark => (
|
||||||
<div
|
<div
|
||||||
key={mark}
|
key={mark}
|
||||||
className={mark === userData.mark && userData.mark !== 0 ? 'Novel__Main_Status_Mark_Element Selected' : 'Novel__Main_Status_Mark_Element'}
|
className={mark === userData.mark && userData.mark !== 0 ? 'Novel__Main_Status_Mark_Element Selected' : 'Novel__Main_Status_Mark_Element'}
|
||||||
@@ -208,7 +215,8 @@ class Novel extends React.Component<Props, State> {
|
|||||||
</div>}
|
</div>}
|
||||||
{genres && genres.length > 0 &&
|
{genres && genres.length > 0 &&
|
||||||
<div className="Novel__Info_Genres">
|
<div className="Novel__Info_Genres">
|
||||||
<strong>Жанры</strong>: {genres.map(genre => <div className={'Genre'} key={genre.id}>{genre.localized_name}</div>)}
|
<strong>Жанры</strong>: {genres.map(genre => <div className={'Genre'}
|
||||||
|
key={genre.id}>{genre.localized_name}</div>)}
|
||||||
</div>}
|
</div>}
|
||||||
<div>
|
<div>
|
||||||
<strong>Год выхода</strong>: {novel.release_date.toLocaleDateString()}
|
<strong>Год выхода</strong>: {novel.release_date.toLocaleDateString()}
|
||||||
@@ -229,12 +237,15 @@ class Novel extends React.Component<Props, State> {
|
|||||||
<div className="Novel__Characters_List">
|
<div className="Novel__Characters_List">
|
||||||
{this.state.characters.filter(char => char.main).map(char =>
|
{this.state.characters.filter(char => char.main).map(char =>
|
||||||
<div className={'Novel__Character'} key={char.id}>
|
<div className={'Novel__Character'} key={char.id}>
|
||||||
<div className='Character_Image' style={{ backgroundImage: `url(${char.image})`}}/>
|
<div className='Character_Image' style={{ backgroundImage: `url(${char.image})` }}/>
|
||||||
<Link to={`/character/${char.id}`}><div className={'Novel__Character_Name'}>{char.localized_name}</div></Link>
|
<Link to={`/character/${char.id}`}>
|
||||||
|
<div className={'Novel__Character_Name'}>{char.localized_name}</div>
|
||||||
|
</Link>
|
||||||
</div>)}
|
</div>)}
|
||||||
</div>
|
</div>
|
||||||
</div>}
|
</div>}
|
||||||
<Comments user={currentUser} comments={comments} sendComment={this.sendComment} loadMore={this.loadMoreComments} hasMore={hasMoreComments} />
|
<Comments user={currentUser} comments={comments} sendComment={this.sendComment}
|
||||||
|
loadMore={this.loadMoreComments} hasMore={hasMoreComments}/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import './Novels.sass'
|
import './Novels.sass'
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import {fetchNovels} from "../../api/novels";
|
import { fetchNovels } from "../../api/novels";
|
||||||
import NovelItem from '../../ui/NovelItem/NovelItem';
|
import NovelItem from '../../ui/NovelItem/NovelItem';
|
||||||
import Loading from "../../ui/Loading";
|
import Loading from "../../ui/Loading";
|
||||||
|
|
||||||
@@ -52,7 +52,7 @@ class Novels extends React.Component<{}, State> {
|
|||||||
return (
|
return (
|
||||||
<div className={'Novels'}>
|
<div className={'Novels'}>
|
||||||
<div className="Novels__List">
|
<div className="Novels__List">
|
||||||
{novels.map((novel: NovelType) => <NovelItem {...novel} key={novel.id} viewType={'grid'} />)}
|
{novels.map((novel: NovelType) => <NovelItem {...novel} key={novel.id} viewType={'grid'}/>)}
|
||||||
</div>
|
</div>
|
||||||
{/*<div className="Novels__Filters">
|
{/*<div className="Novels__Filters">
|
||||||
<div className="Novels__Filters_Genre">
|
<div className="Novels__Filters_Genre">
|
||||||
@@ -72,4 +72,4 @@ class Novels extends React.Component<{}, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Novels;
|
export default Novels;
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {restore} from "../../api/auth";
|
import { restore } from "../../api/auth";
|
||||||
import errors from "../../api/errors";
|
import errors from "../../api/errors";
|
||||||
import './PasswordRestore.sass';
|
import './PasswordRestore.sass';
|
||||||
import Button from "../../ui/Button/Button";
|
import Button from "../../ui/Button/Button";
|
||||||
@@ -76,4 +76,4 @@ class PasswordRestore extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PasswordRestore;
|
export default PasswordRestore;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import React from "react";
|
|||||||
// import Recaptcha from "react-recaptcha";
|
// import Recaptcha from "react-recaptcha";
|
||||||
import Recaptcha from '../../ui/Recaptcha/Recaptcha';
|
import Recaptcha from '../../ui/Recaptcha/Recaptcha';
|
||||||
import './PasswordRestore.sass';
|
import './PasswordRestore.sass';
|
||||||
import {generateRestoreLink} from "../../api/users";
|
import { generateRestoreLink } from "../../api/users";
|
||||||
import Button from "../../ui/Button/Button";
|
import Button from "../../ui/Button/Button";
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
@@ -12,11 +12,10 @@ type State = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class PasswordRestoreGenerate extends React.Component<{}, State> {
|
class PasswordRestoreGenerate extends React.Component<{}, State> {
|
||||||
private recaptcha: any;
|
|
||||||
|
|
||||||
state: State = {
|
state: State = {
|
||||||
email: '', recaptcha: ''
|
email: '', recaptcha: ''
|
||||||
}
|
}
|
||||||
|
private recaptcha: any;
|
||||||
|
|
||||||
onSubmit = (event: React.FormEvent) => {
|
onSubmit = (event: React.FormEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -50,4 +49,4 @@ class PasswordRestoreGenerate extends React.Component<{}, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PasswordRestoreGenerate;
|
export default PasswordRestoreGenerate;
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import './UserNovels.sass';
|
import './UserNovels.sass';
|
||||||
import { fetchUserNovels, fetchUser } from '../../../api/users';
|
import { fetchUser, fetchUserNovels } from '../../../api/users';
|
||||||
import Loading from '../../../ui/Loading';
|
import Loading from '../../../ui/Loading';
|
||||||
import NovelItem from '../../../ui/NovelItem/NovelItem';
|
import NovelItem from '../../../ui/NovelItem/NovelItem';
|
||||||
import {capitalize, generateClassName, getRandomInt} from "../../../utils";
|
import { capitalize, generateClassName, getRandomInt } from "../../../utils";
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import {faAlignJustify, faThLarge} from "@fortawesome/free-solid-svg-icons";
|
import { faAlignJustify, faThLarge } from "@fortawesome/free-solid-svg-icons";
|
||||||
import Button from "../../../ui/Button/Button";
|
import Button from "../../../ui/Button/Button";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
@@ -27,7 +27,7 @@ class UserNovels extends React.Component<Props, State> {
|
|||||||
const { history } = this.props;
|
const { history } = this.props;
|
||||||
const { novels } = this.state;
|
const { novels } = this.state;
|
||||||
const planned = novels.filter(n => n.status === 'planned');
|
const planned = novels.filter(n => n.status === 'planned');
|
||||||
const index = getRandomInt(0, planned.length-1);
|
const index = getRandomInt(0, planned.length - 1);
|
||||||
history.push(`/novels/${planned[index].id}`);
|
history.push(`/novels/${planned[index].id}`);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -77,7 +77,8 @@ class UserNovels extends React.Component<Props, State> {
|
|||||||
<Button onClick={this.getRandomNovel}>Рандомная новелла</Button>
|
<Button onClick={this.getRandomNovel}>Рандомная новелла</Button>
|
||||||
</div>
|
</div>
|
||||||
<div className={generateClassName("UserNovels__List_Novels", capitalize(viewType) || 'Grid')}>
|
<div className={generateClassName("UserNovels__List_Novels", capitalize(viewType) || 'Grid')}>
|
||||||
{planned.map((novel, id) => <NovelItem {...novel} key={novel.id} novelId={id+1} viewType={viewType}/>)}
|
{planned.map((novel, id) => <NovelItem {...novel} key={novel.id} novelId={id + 1}
|
||||||
|
viewType={viewType}/>)}
|
||||||
</div>
|
</div>
|
||||||
</div>}
|
</div>}
|
||||||
|
|
||||||
@@ -86,7 +87,8 @@ class UserNovels extends React.Component<Props, State> {
|
|||||||
Пройденные
|
Пройденные
|
||||||
</div>
|
</div>
|
||||||
<div className={generateClassName("UserNovels__List_Novels", capitalize(viewType) || 'Grid')}>
|
<div className={generateClassName("UserNovels__List_Novels", capitalize(viewType) || 'Grid')}>
|
||||||
{completed.map((novel, id) => <NovelItem {...novel} key={novel.id} novelId={id+1} viewType={viewType}/>)}
|
{completed.map((novel, id) => <NovelItem {...novel} key={novel.id} novelId={id + 1}
|
||||||
|
viewType={viewType}/>)}
|
||||||
</div>
|
</div>
|
||||||
</div>}
|
</div>}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import Button from "../../../ui/Button/Button";
|
import Button from "../../../ui/Button/Button";
|
||||||
import Group from "../../../ui/Group/Group";
|
import Group from "../../../ui/Group/Group";
|
||||||
import React, {FormEvent} from "react";
|
import React, { FormEvent } from "react";
|
||||||
import {updateUserAppearanceSettings} from "../../../api/users";
|
import { updateUserAppearanceSettings } from "../../../api/users";
|
||||||
import {connect} from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import {setUser} from "../../../store/ducks/currentUser";
|
import { setUser } from "../../../store/ducks/currentUser";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
setUser: SetUser
|
setUser: SetUser
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
import React, {ChangeEvent, FormEvent} from "react";
|
import React, { ChangeEvent, FormEvent } from "react";
|
||||||
import Button from "../../../ui/Button/Button";
|
import Button from "../../../ui/Button/Button";
|
||||||
import Group from "../../../ui/Group/Group";
|
import Group from "../../../ui/Group/Group";
|
||||||
import {updateUserGeneralSettings, uploadAvatar} from "../../../api/users";
|
import { updateUserGeneralSettings, uploadAvatar } from "../../../api/users";
|
||||||
import {connect} from "react-redux";
|
import { connect } from "react-redux";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
setUser: SetUser
|
setUser: SetUser
|
||||||
@@ -28,7 +28,7 @@ class General extends React.Component<Props, State> {
|
|||||||
|
|
||||||
saveAvatar = (event: FormEvent) => {
|
saveAvatar = (event: FormEvent) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const { avatar, useGravatar} = this.state;
|
const { avatar, useGravatar } = this.state;
|
||||||
const { setUser } = this.props;
|
const { setUser } = this.props;
|
||||||
|
|
||||||
if(avatar) {
|
if(avatar) {
|
||||||
@@ -49,8 +49,11 @@ class General extends React.Component<Props, State> {
|
|||||||
return (
|
return (
|
||||||
<Group title={'Аватар'} className={'Settings_Group'}>
|
<Group title={'Аватар'} className={'Settings_Group'}>
|
||||||
<form onSubmit={this.saveAvatar}>
|
<form onSubmit={this.saveAvatar}>
|
||||||
<label>Использовать Gravatar <input type="checkbox" onChange={event => this.setState({ useGravatar: event.target.checked })} checked={useGravatar}/></label>
|
<label>Использовать Gravatar <input type="checkbox"
|
||||||
<label>Загрузить аватар <input type="file" onChange={this.onChangeAvatar} disabled={useGravatar}/></label>
|
onChange={event => this.setState({ useGravatar: event.target.checked })}
|
||||||
|
checked={useGravatar}/></label>
|
||||||
|
<label>Загрузить аватар <input type="file" onChange={this.onChangeAvatar}
|
||||||
|
disabled={useGravatar}/></label>
|
||||||
<Button>Сохранить</Button>
|
<Button>Сохранить</Button>
|
||||||
</form>
|
</form>
|
||||||
</Group>
|
</Group>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import Group from "../../../ui/Group/Group";
|
import Group from "../../../ui/Group/Group";
|
||||||
import {connect} from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import NotFoundError from "../../NotFoundError";
|
import NotFoundError from "../../NotFoundError";
|
||||||
import './Settings.sass';
|
import './Settings.sass';
|
||||||
import Tabs from "../../../ui/Tabs/Tabs";
|
import Tabs from "../../../ui/Tabs/Tabs";
|
||||||
@@ -8,7 +8,7 @@ import TabItem from "../../../ui/Tabs/TabItem";
|
|||||||
import Appearance from "./Appearance";
|
import Appearance from "./Appearance";
|
||||||
import General from "./General";
|
import General from "./General";
|
||||||
import Security from "./Security";
|
import Security from "./Security";
|
||||||
import {setUser} from "../../../store/ducks/currentUser";
|
import { setUser } from "../../../store/ducks/currentUser";
|
||||||
|
|
||||||
enum TabsNames {
|
enum TabsNames {
|
||||||
General,
|
General,
|
||||||
@@ -38,37 +38,37 @@ class Settings extends React.Component<Props, State> {
|
|||||||
if(parseInt(userId) !== currentUser.id) return <NotFoundError/>;
|
if(parseInt(userId) !== currentUser.id) return <NotFoundError/>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Group title={''}>
|
<Group title={''}>
|
||||||
<Tabs>
|
<Tabs>
|
||||||
<TabItem
|
<TabItem
|
||||||
selected={currentTab === TabsNames.General}
|
selected={currentTab === TabsNames.General}
|
||||||
onClick={() => this.setState({ currentTab: TabsNames.General })}
|
onClick={() => this.setState({ currentTab: TabsNames.General })}
|
||||||
>
|
>
|
||||||
Главное
|
Главное
|
||||||
</TabItem>
|
</TabItem>
|
||||||
<TabItem
|
<TabItem
|
||||||
selected={currentTab === TabsNames.Security}
|
selected={currentTab === TabsNames.Security}
|
||||||
onClick={() => this.setState({ currentTab: TabsNames.Security })}
|
onClick={() => this.setState({ currentTab: TabsNames.Security })}
|
||||||
>
|
>
|
||||||
Безопастность
|
Безопастность
|
||||||
</TabItem>
|
</TabItem>
|
||||||
<TabItem
|
<TabItem
|
||||||
selected={currentTab === TabsNames.Appearance}
|
selected={currentTab === TabsNames.Appearance}
|
||||||
onClick={() => this.setState({ currentTab: TabsNames.Appearance })}
|
onClick={() => this.setState({ currentTab: TabsNames.Appearance })}
|
||||||
>
|
>
|
||||||
Внешний вид
|
Внешний вид
|
||||||
</TabItem>
|
</TabItem>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
{currentTab === TabsNames.General && (
|
{currentTab === TabsNames.General && (
|
||||||
<General setUser={setUser}/>
|
<General setUser={setUser}/>
|
||||||
)}
|
)}
|
||||||
{currentTab === TabsNames.Security && (
|
{currentTab === TabsNames.Security && (
|
||||||
<Security/>
|
<Security/>
|
||||||
)}
|
)}
|
||||||
{currentTab === TabsNames.Appearance && (
|
{currentTab === TabsNames.Appearance && (
|
||||||
<Appearance/>
|
<Appearance/>
|
||||||
)}
|
)}
|
||||||
</Group>
|
</Group>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+48
-26
@@ -1,14 +1,14 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {fetchUser, fetchUserNovels, generateActivateLink} from "../../api/users";
|
import { fetchUser, fetchUserNovels, generateActivateLink } from "../../api/users";
|
||||||
import './User.sass'
|
import './User.sass'
|
||||||
import NotFoundError from "../NotFoundError";
|
import NotFoundError from "../NotFoundError";
|
||||||
import {Link} from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import Loading from "../../ui/Loading";
|
import Loading from "../../ui/Loading";
|
||||||
import NovelItem from "../../ui/NovelItem/NovelItem";
|
import NovelItem from "../../ui/NovelItem/NovelItem";
|
||||||
import {connect} from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import Button from "../../ui/Button/Button";
|
import Button from "../../ui/Button/Button";
|
||||||
import NotificationMessage from "../../ui/Notifications/NotificationMessage";
|
import NotificationMessage from "../../ui/Notifications/NotificationMessage";
|
||||||
import {addNotification} from "../../store/ducks/notifications";
|
import { addNotification } from "../../store/ducks/notifications";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
match: { params: { userId: string } }
|
match: { params: { userId: string } }
|
||||||
@@ -76,7 +76,7 @@ class User extends React.Component<Props, State> {
|
|||||||
const { currentUser } = this.props;
|
const { currentUser } = this.props;
|
||||||
const { errorCode, user, novels } = this.state;
|
const { errorCode, user, novels } = this.state;
|
||||||
if(errorCode === 100) return <NotFoundError/>;
|
if(errorCode === 100) return <NotFoundError/>;
|
||||||
if(!user) return <Loading />;
|
if(!user) return <Loading/>;
|
||||||
|
|
||||||
const style = !user.is_activated ? { marginTop: '1rem' } : {}
|
const style = !user.is_activated ? { marginTop: '1rem' } : {}
|
||||||
|
|
||||||
@@ -85,27 +85,38 @@ class User extends React.Component<Props, State> {
|
|||||||
{!user.is_activated && user.id === currentUser.id && (
|
{!user.is_activated && user.id === currentUser.id && (
|
||||||
<div className={'User__Activate'}>
|
<div className={'User__Activate'}>
|
||||||
<h2>Ваш аккаунт не активирован!</h2>
|
<h2>Ваш аккаунт не активирован!</h2>
|
||||||
<p>Активируйте аккаунт, для доступа ко многим функциям. Так же актвация аккаунта позволит восстановить пароль.</p>
|
<p>Активируйте аккаунт, для доступа ко многим функциям. Так же актвация аккаунта позволит
|
||||||
|
восстановить пароль.</p>
|
||||||
<div style={{ display: "flex", justifyContent: "flex-end" }}>
|
<div style={{ display: "flex", justifyContent: "flex-end" }}>
|
||||||
<Button onClick={this.sendActivateLink} style={{ fontSize: '1.2rem' }}>Активировать!</Button>
|
<Button onClick={this.sendActivateLink}
|
||||||
|
style={{ fontSize: '1.2rem' }}>Активировать!</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="User__Info" style={style}>
|
<div className="User__Info" style={style}>
|
||||||
{user.cover ? (
|
{user.cover ? (
|
||||||
<div className="User__Info_Cover User__Info_Main" style={{ backgroundImage: `url(${user.cover})` }}>
|
<div className="User__Info_Cover User__Info_Main"
|
||||||
<div className="User__Info_Avatar" style={{ backgroundImage: `url(${user.avatar}?s=96&t=${new Date().getTime()})` }} />
|
style={{ backgroundImage: `url(${user.cover})` }}>
|
||||||
<div>
|
<div className="User__Info_Avatar"
|
||||||
<div className='User__Info_Nick'>{user.username}</div>
|
style={{ backgroundImage: `url(${user.avatar}?s=96&t=${new Date().getTime()})` }}/>
|
||||||
<div className='User__Info_Group' style={{ borderColor: user.group.color, color: user.group.color }}>{user.group.name}</div>
|
|
||||||
</div>
|
|
||||||
</div>) : (
|
|
||||||
<div className={'User__Info_Main'}>
|
|
||||||
<div className="User__Info_Avatar" style={{ backgroundImage: `url(${user.avatar}?s=96&t=${new Date().getTime()})` }} />
|
|
||||||
<div>
|
<div>
|
||||||
<div className='User__Info_Nick'>{user.username}</div>
|
<div className='User__Info_Nick'>{user.username}</div>
|
||||||
<div className='User__Info_Group' style={{ borderColor: user.group.color, color: user.group.color }}>{user.group.name}</div>
|
<div className='User__Info_Group' style={{
|
||||||
|
borderColor: user.group.color,
|
||||||
|
color: user.group.color
|
||||||
|
}}>{user.group.name}</div>
|
||||||
|
</div>
|
||||||
|
</div>) : (
|
||||||
|
<div className={'User__Info_Main'}>
|
||||||
|
<div className="User__Info_Avatar"
|
||||||
|
style={{ backgroundImage: `url(${user.avatar}?s=96&t=${new Date().getTime()})` }}/>
|
||||||
|
<div>
|
||||||
|
<div className='User__Info_Nick'>{user.username}</div>
|
||||||
|
<div className='User__Info_Group' style={{
|
||||||
|
borderColor: user.group.color,
|
||||||
|
color: user.group.color
|
||||||
|
}}>{user.group.name}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -115,11 +126,21 @@ class User extends React.Component<Props, State> {
|
|||||||
<div className="User__Statistic_Item">
|
<div className="User__Statistic_Item">
|
||||||
<div className="User__Statistic_Title">Новеллы</div>
|
<div className="User__Statistic_Title">Новеллы</div>
|
||||||
<div className="User__Statistic_Blocks">
|
<div className="User__Statistic_Blocks">
|
||||||
<div className="User__Statistic_Block Planned" data-count={novels.filter(n => n.status === 'planned').length}>Запланированно</div>
|
<div className="User__Statistic_Block Planned"
|
||||||
<div className="User__Statistic_Block Completed" data-count={novels.filter(n => n.status === 'completed').length}>Пройдено</div>
|
data-count={novels.filter(n => n.status === 'planned').length}>Запланированно
|
||||||
<div className="User__Statistic_Block InProgress" data-count={novels.filter(n => n.status === 'in_progress').length}>Прохожу</div>
|
</div>
|
||||||
<div className="User__Statistic_Block Deferred" data-count={novels.filter(n => n.status === 'deferred').length}>Отложено</div>
|
<div className="User__Statistic_Block Completed"
|
||||||
<div className="User__Statistic_Block Dropped" data-count={novels.filter(n => n.status === 'dropped').length}>Брошено</div>
|
data-count={novels.filter(n => n.status === 'completed').length}>Пройдено
|
||||||
|
</div>
|
||||||
|
<div className="User__Statistic_Block InProgress"
|
||||||
|
data-count={novels.filter(n => n.status === 'in_progress').length}>Прохожу
|
||||||
|
</div>
|
||||||
|
<div className="User__Statistic_Block Deferred"
|
||||||
|
data-count={novels.filter(n => n.status === 'deferred').length}>Отложено
|
||||||
|
</div>
|
||||||
|
<div className="User__Statistic_Block Dropped"
|
||||||
|
data-count={novels.filter(n => n.status === 'dropped').length}>Брошено
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -131,10 +152,11 @@ class User extends React.Component<Props, State> {
|
|||||||
</div>
|
</div>
|
||||||
<div className="User__List_Items">
|
<div className="User__List_Items">
|
||||||
{novels.length > 0 ?
|
{novels.length > 0 ?
|
||||||
novels.slice(0, 4).map((novel, id) => <NovelItem {...novel} key={novel.id} novelId={id+1} viewType={'grid'} />
|
novels.slice(0, 4).map((novel, id) => <NovelItem {...novel} key={novel.id} novelId={id + 1}
|
||||||
) : (
|
viewType={'grid'}/>
|
||||||
<div>У этого пользователя нет новелл!</div>
|
) : (
|
||||||
)}
|
<div>У этого пользователя нет новелл!</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import {fetchUsers} from "../../api/users";
|
import { fetchUsers } from "../../api/users";
|
||||||
import Loading from "../../ui/Loading";
|
import Loading from "../../ui/Loading";
|
||||||
import './Users.sass';
|
import './Users.sass';
|
||||||
import {Link} from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
|
||||||
type Props = {
|
type Props = {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
type State = {
|
type State = {
|
||||||
users: UserType[]
|
users: UserType[]
|
||||||
@@ -29,7 +27,8 @@ class Users extends React.Component<Props, State> {
|
|||||||
<div className={'Users'}>
|
<div className={'Users'}>
|
||||||
{users.map(user => (
|
{users.map(user => (
|
||||||
<Link className={'Users__User'} key={user.id} to={`user/${user.id}`}>
|
<Link className={'Users__User'} key={user.id} to={`user/${user.id}`}>
|
||||||
<div className="Users__User_Avatar" style={{ backgroundImage: `url(${user.avatar}?s=96?t=${new Date().getTime()})` }}/>
|
<div className="Users__User_Avatar"
|
||||||
|
style={{ backgroundImage: `url(${user.avatar}?s=96?t=${new Date().getTime()})` }}/>
|
||||||
{user.username}
|
{user.username}
|
||||||
</Link>
|
</Link>
|
||||||
))}
|
))}
|
||||||
@@ -38,4 +37,4 @@ class Users extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Users;
|
export default Users;
|
||||||
|
|||||||
+81
-81
@@ -1,107 +1,107 @@
|
|||||||
const isLocalhost = Boolean(
|
const isLocalhost = Boolean(
|
||||||
window.location.hostname === 'localhost' ||
|
window.location.hostname === 'localhost' ||
|
||||||
window.location.hostname === '[::1]' ||
|
window.location.hostname === '[::1]' ||
|
||||||
window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)
|
window.location.hostname.match(/^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/)
|
||||||
);
|
);
|
||||||
|
|
||||||
type Config = {
|
type Config = {
|
||||||
onSuccess?: (registration: ServiceWorkerRegistration) => void;
|
onSuccess?: (registration: ServiceWorkerRegistration) => void;
|
||||||
onUpdate?: (registration: ServiceWorkerRegistration) => void;
|
onUpdate?: (registration: ServiceWorkerRegistration) => void;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function register(config?: Config) {
|
export function register(config?: Config) {
|
||||||
if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
if(process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
|
||||||
const publicUrl = new URL(
|
const publicUrl = new URL(
|
||||||
(process as { env: { [key: string]: string } }).env.PUBLIC_URL,
|
(process as { env: { [key: string]: string } }).env.PUBLIC_URL,
|
||||||
window.location.href
|
window.location.href
|
||||||
);
|
);
|
||||||
if (publicUrl.origin !== window.location.origin) {
|
if(publicUrl.origin !== window.location.origin) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
window.addEventListener('load', () => {
|
window.addEventListener('load', () => {
|
||||||
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
|
||||||
|
|
||||||
if (isLocalhost) {
|
if(isLocalhost) {
|
||||||
checkValidServiceWorker(swUrl, config);
|
checkValidServiceWorker(swUrl, config);
|
||||||
|
|
||||||
navigator.serviceWorker.ready.then(() => {
|
navigator.serviceWorker.ready.then(() => {
|
||||||
console.log(
|
console.log(
|
||||||
'This web app is being served cache-first by a service ' +
|
'This web app is being served cache-first by a service ' +
|
||||||
'worker. To learn more, visit https://bit.ly/CRA-PWA'
|
'worker. To learn more, visit https://bit.ly/CRA-PWA'
|
||||||
);
|
);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
registerValidSW(swUrl, config);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
}
|
||||||
registerValidSW(swUrl, config);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function registerValidSW(swUrl: string, config?: Config) {
|
function registerValidSW(swUrl: string, config?: Config) {
|
||||||
navigator.serviceWorker
|
navigator.serviceWorker
|
||||||
.register(swUrl)
|
.register(swUrl)
|
||||||
.then(registration => {
|
.then(registration => {
|
||||||
registration.onupdatefound = () => {
|
registration.onupdatefound = () => {
|
||||||
const installingWorker = registration.installing;
|
const installingWorker = registration.installing;
|
||||||
if (installingWorker == null) {
|
if(installingWorker == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
installingWorker.onstatechange = () => {
|
installingWorker.onstatechange = () => {
|
||||||
if (installingWorker.state === 'installed') {
|
if(installingWorker.state === 'installed') {
|
||||||
if (navigator.serviceWorker.controller) {
|
if(navigator.serviceWorker.controller) {
|
||||||
console.log(
|
console.log(
|
||||||
'New content is available and will be used when all ' +
|
'New content is available and will be used when all ' +
|
||||||
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
|
'tabs for this page are closed. See https://bit.ly/CRA-PWA.'
|
||||||
);
|
);
|
||||||
|
|
||||||
if (config && config.onUpdate) {
|
if(config && config.onUpdate) {
|
||||||
config.onUpdate(registration);
|
config.onUpdate(registration);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log('Content is cached for offline use.');
|
console.log('Content is cached for offline use.');
|
||||||
|
|
||||||
if (config && config.onSuccess) {
|
if(config && config.onSuccess) {
|
||||||
config.onSuccess(registration);
|
config.onSuccess(registration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
console.error('Error during service worker registration:', error);
|
console.error('Error during service worker registration:', error);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkValidServiceWorker(swUrl: string, config?: Config) {
|
function checkValidServiceWorker(swUrl: string, config?: Config) {
|
||||||
fetch(swUrl)
|
fetch(swUrl)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
const contentType = response.headers.get('content-type');
|
const contentType = response.headers.get('content-type');
|
||||||
if (
|
if(
|
||||||
response.status === 404 ||
|
response.status === 404 ||
|
||||||
(contentType != null && contentType.indexOf('javascript') === -1)
|
(contentType != null && contentType.indexOf('javascript') === -1)
|
||||||
) {
|
) {
|
||||||
navigator.serviceWorker.ready.then(registration => {
|
navigator.serviceWorker.ready.then(registration => {
|
||||||
registration.unregister().then(() => {
|
registration.unregister().then(() => {
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
registerValidSW(swUrl, config);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
console.log(
|
||||||
|
'No internet connection found. App is running in offline mode.'
|
||||||
|
);
|
||||||
});
|
});
|
||||||
} else {
|
|
||||||
registerValidSW(swUrl, config);
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(() => {
|
|
||||||
console.log(
|
|
||||||
'No internet connection found. App is running in offline mode.'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function unregister() {
|
export function unregister() {
|
||||||
if ('serviceWorker' in navigator) {
|
if('serviceWorker' in navigator) {
|
||||||
navigator.serviceWorker.ready.then(registration => {
|
navigator.serviceWorker.ready.then(registration => {
|
||||||
registration.unregister();
|
registration.unregister();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ type Action = {
|
|||||||
userData: UserType
|
userData: UserType
|
||||||
};
|
};
|
||||||
const reducer = (state = initialState, action: Action) => {
|
const reducer = (state = initialState, action: Action) => {
|
||||||
switch (action.type) {
|
switch(action.type) {
|
||||||
case SET_USER:
|
case SET_USER:
|
||||||
if(action.userData) {
|
if(action.userData) {
|
||||||
state = Object.assign({}, state, action.userData);
|
state = Object.assign({}, state, action.userData);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import {combineReducers} from "redux";
|
import { combineReducers } from "redux";
|
||||||
import currentUser from './currentUser'
|
import currentUser from './currentUser'
|
||||||
import modal from "./modal";
|
import modal from "./modal";
|
||||||
import notifications from './notifications'
|
import notifications from './notifications'
|
||||||
|
|||||||
@@ -10,15 +10,16 @@ type Action = {
|
|||||||
type: string
|
type: string
|
||||||
modal: React.ReactNode | null
|
modal: React.ReactNode | null
|
||||||
}
|
}
|
||||||
const reducer = (state=initialState, action: Action) => {
|
const reducer = (state = initialState, action: Action) => {
|
||||||
switch (action.type) {
|
switch(action.type) {
|
||||||
case SET_MODAL: {
|
case SET_MODAL: {
|
||||||
return action.modal;
|
return action.modal;
|
||||||
}
|
}
|
||||||
case HIDE_MODAL: {
|
case HIDE_MODAL: {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
default: return state;
|
default:
|
||||||
|
return state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,13 +10,14 @@ type Action = {
|
|||||||
notification: React.ReactNode
|
notification: React.ReactNode
|
||||||
};
|
};
|
||||||
const reducer = (state = initialState, action: Action) => {
|
const reducer = (state = initialState, action: Action) => {
|
||||||
switch (action.type) {
|
switch(action.type) {
|
||||||
case ADD_NOTIFICATION: {
|
case ADD_NOTIFICATION: {
|
||||||
if(state.length === 3)
|
if(state.length === 3)
|
||||||
return [...state.slice(1), action.notification];
|
return [...state.slice(1), action.notification];
|
||||||
return [...state, action.notification];
|
return [...state, action.notification];
|
||||||
}
|
}
|
||||||
default: return state;
|
default:
|
||||||
|
return state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
const SET_SETTINGS = 'unmei/userSettings/SET_SETTINGS';
|
const SET_SETTINGS = 'unmei/userSettings/SET_SETTINGS';
|
||||||
|
|
||||||
const reducer = (state={}, action: Action<{settings: UserSettingsType}>) => {
|
const reducer = (state = {}, action: Action<{ settings: UserSettingsType }>) => {
|
||||||
switch (action.type) {
|
switch(action.type) {
|
||||||
case SET_SETTINGS:
|
case SET_SETTINGS:
|
||||||
state = Object.assign({}, state, action.payload.settings);
|
state = Object.assign({}, state, action.payload.settings);
|
||||||
return state;
|
return state;
|
||||||
|
|||||||
+2
-2
@@ -1,5 +1,5 @@
|
|||||||
import {createStore} from "redux";
|
import { createStore } from "redux";
|
||||||
import {composeWithDevTools} from "redux-devtools-extension";
|
import { composeWithDevTools } from "redux-devtools-extension";
|
||||||
import reducers from "./ducks/index";
|
import reducers from "./ducks/index";
|
||||||
|
|
||||||
const composeEnhancers = composeWithDevTools({
|
const composeEnhancers = composeWithDevTools({
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import React, {useState} from "react";
|
import React, { useState } from "react";
|
||||||
import {FontAwesomeIcon} from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
import {
|
import {
|
||||||
faBold,
|
faBold,
|
||||||
faExclamationTriangle,
|
faExclamationTriangle,
|
||||||
@@ -48,4 +48,4 @@ const BBEditor = ({ inputRef, ref, ...props }: Props) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default BBEditor;
|
export default BBEditor;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, {ButtonHTMLAttributes} from "react";
|
import React, { ButtonHTMLAttributes } from "react";
|
||||||
import './Button.sass';
|
import './Button.sass';
|
||||||
import classNames from "../../classNames";
|
import classNames from "../../classNames";
|
||||||
|
|
||||||
@@ -11,4 +11,4 @@ const Button = (restProps: ButtonHTMLAttributes<HTMLElement>) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Button;
|
export default Button;
|
||||||
|
|||||||
@@ -17,5 +17,5 @@
|
|||||||
|
|
||||||
&__Content
|
&__Content
|
||||||
.Comment__User_Username
|
.Comment__User_Username
|
||||||
font-size: 1.1rem
|
font-size: 1.1rem
|
||||||
font-weight: 600
|
font-weight: 600
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import './Comment.sass'
|
import './Comment.sass'
|
||||||
import {Link} from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
import parser from 'bbcode-to-react';
|
import parser from 'bbcode-to-react';
|
||||||
import Loading from "../Loading";
|
import Loading from "../Loading";
|
||||||
@@ -27,4 +27,4 @@ class Comment extends React.Component<Props> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Comment;
|
export default Comment;
|
||||||
|
|||||||
@@ -2,8 +2,8 @@ import React from "react";
|
|||||||
import Button from "../Button/Button";
|
import Button from "../Button/Button";
|
||||||
import './ConfirmPopout.sass'
|
import './ConfirmPopout.sass'
|
||||||
import '../Modal/Modal.sass';
|
import '../Modal/Modal.sass';
|
||||||
import {connect} from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import {hideModal} from "../../store/ducks/modal";
|
import { hideModal } from "../../store/ducks/modal";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
hideModal: () => void
|
hideModal: () => void
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, {HTMLAttributes} from "react";
|
import React, { HTMLAttributes } from "react";
|
||||||
import classNames from "../../classNames";
|
import classNames from "../../classNames";
|
||||||
import './Group.sass'
|
import './Group.sass'
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, {InputHTMLAttributes} from "react";
|
import React, { InputHTMLAttributes } from "react";
|
||||||
import classNames from "../../classNames";
|
import classNames from "../../classNames";
|
||||||
import './Input.sass';
|
import './Input.sass';
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import './Modal.sass'
|
import './Modal.sass'
|
||||||
import {connect} from "react-redux";
|
import { connect } from "react-redux";
|
||||||
import {setModal} from "../../store/ducks/modal";
|
import { setModal } from "../../store/ducks/modal";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
setModal: (modal: React.ReactNode | null) => void
|
setModal: (modal: React.ReactNode | null) => void
|
||||||
|
|||||||
@@ -32,4 +32,4 @@ const NewsPost = (restProps: Props) => {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NewsPost;
|
export default NewsPost;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import './NotificationMessage.sass'
|
import './NotificationMessage.sass'
|
||||||
import {capitalize} from "../../utils";
|
import { capitalize } from "../../utils";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
children: React.ReactNode
|
children: React.ReactNode
|
||||||
@@ -32,10 +32,10 @@ class NotificationMessage extends React.Component<Props, State> {
|
|||||||
this.setState({ paused: false });
|
this.setState({ paused: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
interval = (step=50) => {
|
interval = (step = 50) => {
|
||||||
const { time, paused } = this.state;
|
const { time, paused } = this.state;
|
||||||
if(time <= 0 && this.timer) clearInterval(this.timer);
|
if(time <= 0 && this.timer) clearInterval(this.timer);
|
||||||
if(!paused) this.setState({ time: time-step });
|
if(!paused) this.setState({ time: time - step });
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount(): void {
|
componentDidMount(): void {
|
||||||
@@ -70,4 +70,4 @@ class NotificationMessage extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default NotificationMessage;
|
export default NotificationMessage;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React from 'react';
|
|||||||
import { TranslateStatus } from '../../api/api';
|
import { TranslateStatus } from '../../api/api';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import './NovelItem.sass';
|
import './NovelItem.sass';
|
||||||
import {capitalize, generateClassName} from "../../utils";
|
import { capitalize, generateClassName } from "../../utils";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
id: number
|
id: number
|
||||||
@@ -18,7 +18,8 @@ type Props = {
|
|||||||
const NovelItem = ({ id, original_name, localized_name, image, status, mark, viewType, novelId }: Props) => (
|
const NovelItem = ({ id, original_name, localized_name, image, status, mark, viewType, novelId }: Props) => (
|
||||||
<Link to={`/novels/${id}`} className={generateClassName("NovelItem", capitalize(viewType) || 'Grid')}>
|
<Link to={`/novels/${id}`} className={generateClassName("NovelItem", capitalize(viewType) || 'Grid')}>
|
||||||
{viewType === 'grid' && (<>
|
{viewType === 'grid' && (<>
|
||||||
<div className='NovelItem__Image' style={{ backgroundImage: `url(${image || '/static/img/no-image.png'})` }}/>
|
<div className='NovelItem__Image'
|
||||||
|
style={{ backgroundImage: `url(${image || '/static/img/no-image.png'})` }}/>
|
||||||
<div className="NovelItem__Title">
|
<div className="NovelItem__Title">
|
||||||
{localized_name || original_name}
|
{localized_name || original_name}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -113,7 +113,9 @@ $label-font-size-redo: $default-size * 4
|
|||||||
|
|
||||||
&.progress-65
|
&.progress-65
|
||||||
@include draw-progress--solid(65, #e67e22, $bg-color)
|
@include draw-progress--solid(65, #e67e22, $bg-color)
|
||||||
|
|
||||||
&.progress-25
|
&.progress-25
|
||||||
@include draw-progress--solid(25, #9b59b6, $bg-color)
|
@include draw-progress--solid(25, #9b59b6, $bg-color)
|
||||||
|
|
||||||
&.progress-88
|
&.progress-88
|
||||||
@include draw-progress--solid(88, #3498db, $bg-color)
|
@include draw-progress--solid(88, #3498db, $bg-color)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, {CSSProperties} from "react";
|
import React, { CSSProperties } from "react";
|
||||||
import './ProgressBar.sass';
|
import './ProgressBar.sass';
|
||||||
|
|
||||||
const ProgressBar = ({ progress, color, alternative }: { progress: number, color: string, alternative?: boolean }) => {
|
const ProgressBar = ({ progress, color, alternative }: { progress: number, color: string, alternative?: boolean }) => {
|
||||||
@@ -9,8 +9,9 @@ const ProgressBar = ({ progress, color, alternative }: { progress: number, color
|
|||||||
<div className={alternative ? 'pie-wrapper progress style-2' : "pie-wrapper progress-75"}>
|
<div className={alternative ? 'pie-wrapper progress style-2' : "pie-wrapper progress-75"}>
|
||||||
<span className="label">{progress}<span className="percent">%</span></span>
|
<span className="label">{progress}<span className="percent">%</span></span>
|
||||||
<div className="pie" style={progress <= 50 ? {} : { clip: 'rect(auto, auto, auto, auto)' }}>
|
<div className="pie" style={progress <= 50 ? {} : { clip: 'rect(auto, auto, auto, auto)' }}>
|
||||||
<div className="left-side half-circle" style={{...borderColor, transform: `rotate(${progress*3.6}deg)`}}/>
|
<div className="left-side half-circle"
|
||||||
<div className="right-side half-circle" style={{...borderColor, ...rightSide}}/>
|
style={{ ...borderColor, transform: `rotate(${progress * 3.6}deg)` }}/>
|
||||||
|
<div className="right-side half-circle" style={{ ...borderColor, ...rightSide }}/>
|
||||||
</div>
|
</div>
|
||||||
{alternative && <div className="shadow"/>}
|
{alternative && <div className="shadow"/>}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,10 +13,10 @@ type State = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Recaptcha extends React.Component<Props, State> {
|
class Recaptcha extends React.Component<Props, State> {
|
||||||
private readonly interval: NodeJS.Timeout;
|
|
||||||
state: State = {
|
state: State = {
|
||||||
isReady: false
|
isReady: false
|
||||||
}
|
}
|
||||||
|
private readonly interval: NodeJS.Timeout;
|
||||||
|
|
||||||
constructor(props: Props) {
|
constructor(props: Props) {
|
||||||
super(props);
|
super(props);
|
||||||
@@ -59,4 +59,4 @@ class Recaptcha extends React.Component<Props, State> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Recaptcha;
|
export default Recaptcha;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ type State = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class Spoiler extends React.Component<Props, State> {
|
class Spoiler extends React.Component<Props, State> {
|
||||||
state = {
|
state = {
|
||||||
expand: false
|
expand: false
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -19,15 +19,15 @@ class Spoiler extends React.Component<Props, State> {
|
|||||||
const { children } = this.props;
|
const { children } = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="Spoiler"
|
className="Spoiler"
|
||||||
onClick={() => this.setState({ expand: !expand })}
|
onClick={() => this.setState({ expand: !expand })}
|
||||||
style={{ fontStyle: expand ? 'normal' : 'italic' }}
|
style={{ fontStyle: expand ? 'normal' : 'italic' }}
|
||||||
>
|
>
|
||||||
{expand ? children : '[Спойлер]'}
|
{expand ? children : '[Спойлер]'}
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Spoiler;
|
export default Spoiler;
|
||||||
|
|||||||
@@ -10,4 +10,4 @@ class SpoilerTag extends Tag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default SpoilerTag;
|
export default SpoilerTag;
|
||||||
|
|||||||
@@ -13,4 +13,4 @@ class ColorTag extends Tag {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ColorTag;
|
export default ColorTag;
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import React, {TextareaHTMLAttributes} from "react";
|
import React from "react";
|
||||||
import classNames from "../../classNames";
|
import classNames from "../../classNames";
|
||||||
import './TextField.sass';
|
import './TextField.sass';
|
||||||
|
|
||||||
const TextField = React.forwardRef(
|
const TextField = React.forwardRef(
|
||||||
(restProps: React.DetailedHTMLProps<React.TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>, ref: React.Ref<HTMLTextAreaElement>) => {
|
(restProps: React.DetailedHTMLProps<React.TextareaHTMLAttributes<HTMLTextAreaElement>, HTMLTextAreaElement>, ref: React.Ref<HTMLTextAreaElement>) => {
|
||||||
const { className, ...props } = restProps;
|
const { className, ...props } = restProps;
|
||||||
return (
|
return (
|
||||||
<textarea className={classNames('TextField', className)} ref={ref} {...props} />
|
<textarea className={classNames('TextField', className)} ref={ref} {...props} />
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
export default TextField;
|
export default TextField;
|
||||||
|
|||||||
@@ -5,4 +5,4 @@ const Title = ({ children }: any) => (
|
|||||||
<div className={'Title'}>{children}</div>
|
<div className={'Title'}>{children}</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
export default Title;
|
export default Title;
|
||||||
|
|||||||
+1
-1
@@ -23,7 +23,7 @@ const generateClassName = (baseClassName: string, ...classNames: string[]) => {
|
|||||||
const getImage: (path: string) => string = (path: string) => {
|
const getImage: (path: string) => string = (path: string) => {
|
||||||
let cdnUrl = process.env['CDN_URL'];
|
let cdnUrl = process.env['CDN_URL'];
|
||||||
if(!cdnUrl) return path;
|
if(!cdnUrl) return path;
|
||||||
if(cdnUrl.endsWith('/')) cdnUrl = cdnUrl.slice(cdnUrl.length-1);
|
if(cdnUrl.endsWith('/')) cdnUrl = cdnUrl.slice(cdnUrl.length - 1);
|
||||||
if(path.startsWith('/')) path = path.slice(1, path.length);
|
if(path.startsWith('/')) path = path.slice(1, path.length);
|
||||||
return `${cdnUrl}/${path}`;
|
return `${cdnUrl}/${path}`;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user