Support Replies bot (#1444)

This commit is contained in:
Alexander Zinchuk 2021-09-16 11:27:20 +03:00
parent 20cf5ecdda
commit 324f7c5e5c
22 changed files with 201 additions and 145 deletions

149
package-lock.json generated
View File

@ -4536,9 +4536,9 @@
"dev": true "dev": true
}, },
"@types/react": { "@types/react": {
"version": "17.0.17", "version": "17.0.19",
"resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.17.tgz", "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.19.tgz",
"integrity": "sha512-nrfi7I13cAmrd0wje8czYpf5SFbryczCtPzFc6ijqvdjKcyA3tCvGxwchOUlxb2ucBPuJ9Y3oUqKrRqZvrz0lw==", "integrity": "sha512-sX1HisdB1/ZESixMTGnMxH9TDe8Sk709734fEQZzCV/4lSu9kJCPbo2PbTRoZM+53Pp0P10hYVyReUueGwUi4A==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/prop-types": "*", "@types/prop-types": "*",
@ -4604,13 +4604,13 @@
"dev": true "dev": true
}, },
"@typescript-eslint/eslint-plugin": { "@typescript-eslint/eslint-plugin": {
"version": "4.29.1", "version": "4.29.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.29.2.tgz",
"integrity": "sha512-AHqIU+SqZZgBEiWOrtN94ldR3ZUABV5dUG94j8Nms9rQnHFc8fvDOue/58K4CFz6r8OtDDc35Pw9NQPWo0Ayrw==", "integrity": "sha512-x4EMgn4BTfVd9+Z+r+6rmWxoAzBaapt4QFqE+d8L8sUtYZYLDTK6VG/y/SMMWA5t1/BVU5Kf+20rX4PtWzUYZg==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/experimental-utils": "4.29.1", "@typescript-eslint/experimental-utils": "4.29.2",
"@typescript-eslint/scope-manager": "4.29.1", "@typescript-eslint/scope-manager": "4.29.2",
"debug": "^4.3.1", "debug": "^4.3.1",
"functional-red-black-tree": "^1.0.1", "functional-red-black-tree": "^1.0.1",
"regexpp": "^3.1.0", "regexpp": "^3.1.0",
@ -4639,15 +4639,15 @@
} }
}, },
"@typescript-eslint/experimental-utils": { "@typescript-eslint/experimental-utils": {
"version": "4.29.1", "version": "4.29.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-4.29.2.tgz",
"integrity": "sha512-kl6QG6qpzZthfd2bzPNSJB2YcZpNOrP6r9jueXupcZHnL74WiuSjaft7WSu17J9+ae9zTlk0KJMXPUj0daBxMw==", "integrity": "sha512-P6mn4pqObhftBBPAv4GQtEK7Yos1fz/MlpT7+YjH9fTxZcALbiiPKuSIfYP/j13CeOjfq8/fr9Thr2glM9ub7A==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/json-schema": "^7.0.7", "@types/json-schema": "^7.0.7",
"@typescript-eslint/scope-manager": "4.29.1", "@typescript-eslint/scope-manager": "4.29.2",
"@typescript-eslint/types": "4.29.1", "@typescript-eslint/types": "4.29.2",
"@typescript-eslint/typescript-estree": "4.29.1", "@typescript-eslint/typescript-estree": "4.29.2",
"eslint-scope": "^5.1.1", "eslint-scope": "^5.1.1",
"eslint-utils": "^3.0.0" "eslint-utils": "^3.0.0"
}, },
@ -4670,14 +4670,14 @@
} }
}, },
"@typescript-eslint/parser": { "@typescript-eslint/parser": {
"version": "4.29.1", "version": "4.29.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.29.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-4.29.2.tgz",
"integrity": "sha512-3fL5iN20hzX3Q4OkG7QEPFjZV2qsVGiDhEwwh+EkmE/w7oteiOvUNzmpu5eSwGJX/anCryONltJ3WDmAzAoCMg==", "integrity": "sha512-WQ6BPf+lNuwteUuyk1jD/aHKqMQ9jrdCn7Gxt9vvBnzbpj7aWEf+aZsJ1zvTjx5zFxGCt000lsbD9tQPEL8u6g==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/scope-manager": "4.29.1", "@typescript-eslint/scope-manager": "4.29.2",
"@typescript-eslint/types": "4.29.1", "@typescript-eslint/types": "4.29.2",
"@typescript-eslint/typescript-estree": "4.29.1", "@typescript-eslint/typescript-estree": "4.29.2",
"debug": "^4.3.1" "debug": "^4.3.1"
}, },
"dependencies": { "dependencies": {
@ -4693,29 +4693,29 @@
} }
}, },
"@typescript-eslint/scope-manager": { "@typescript-eslint/scope-manager": {
"version": "4.29.1", "version": "4.29.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.29.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-4.29.2.tgz",
"integrity": "sha512-Hzv/uZOa9zrD/W5mftZa54Jd5Fed3tL6b4HeaOpwVSabJK8CJ+2MkDasnX/XK4rqP5ZTWngK1ZDeCi6EnxPQ7A==", "integrity": "sha512-mfHmvlQxmfkU8D55CkZO2sQOueTxLqGvzV+mG6S/6fIunDiD2ouwsAoiYCZYDDK73QCibYjIZmGhpvKwAB5BOA==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/types": "4.29.1", "@typescript-eslint/types": "4.29.2",
"@typescript-eslint/visitor-keys": "4.29.1" "@typescript-eslint/visitor-keys": "4.29.2"
} }
}, },
"@typescript-eslint/types": { "@typescript-eslint/types": {
"version": "4.29.1", "version": "4.29.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.29.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-4.29.2.tgz",
"integrity": "sha512-Jj2yu78IRfw4nlaLtKjVaGaxh/6FhofmQ/j8v3NXmAiKafbIqtAPnKYrf0sbGjKdj0hS316J8WhnGnErbJ4RCA==", "integrity": "sha512-K6ApnEXId+WTGxqnda8z4LhNMa/pZmbTFkDxEBLQAbhLZL50DjeY0VIDCml/0Y3FlcbqXZrABqrcKxq+n0LwzQ==",
"dev": true "dev": true
}, },
"@typescript-eslint/typescript-estree": { "@typescript-eslint/typescript-estree": {
"version": "4.29.1", "version": "4.29.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-4.29.2.tgz",
"integrity": "sha512-lIkkrR9E4lwZkzPiRDNq0xdC3f2iVCUjw/7WPJ4S2Sl6C3nRWkeE1YXCQ0+KsiaQRbpY16jNaokdWnm9aUIsfw==", "integrity": "sha512-TJ0/hEnYxapYn9SGn3dCnETO0r+MjaxtlWZ2xU+EvytF0g4CqTpZL48SqSNn2hXsPolnewF30pdzR9a5Lj3DNg==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/types": "4.29.1", "@typescript-eslint/types": "4.29.2",
"@typescript-eslint/visitor-keys": "4.29.1", "@typescript-eslint/visitor-keys": "4.29.2",
"debug": "^4.3.1", "debug": "^4.3.1",
"globby": "^11.0.3", "globby": "^11.0.3",
"is-glob": "^4.0.1", "is-glob": "^4.0.1",
@ -4744,12 +4744,12 @@
} }
}, },
"@typescript-eslint/visitor-keys": { "@typescript-eslint/visitor-keys": {
"version": "4.29.1", "version": "4.29.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.1.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-4.29.2.tgz",
"integrity": "sha512-zLqtjMoXvgdZY/PG6gqA73V8BjqPs4af1v2kiiETBObp+uC6gRYnJLmJHxC0QyUrrHDLJPIWNYxoBV3wbcRlag==", "integrity": "sha512-bDgJLQ86oWHJoZ1ai4TZdgXzJxsea3Ee9u9wsTAvjChdj2WLcVsgWYAPeY7RQMn16tKrlQaBnpKv7KBfs4EQag==",
"dev": true, "dev": true,
"requires": { "requires": {
"@typescript-eslint/types": "4.29.1", "@typescript-eslint/types": "4.29.2",
"eslint-visitor-keys": "^2.0.0" "eslint-visitor-keys": "^2.0.0"
}, },
"dependencies": { "dependencies": {
@ -4923,9 +4923,9 @@
} }
}, },
"@webpack-cli/serve": { "@webpack-cli/serve": {
"version": "1.5.1", "version": "1.5.2",
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.5.1.tgz", "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.5.2.tgz",
"integrity": "sha512-4vSVUiOPJLmr45S8rMGy7WDvpWxfFxfP/Qx/cxZFCfvoypTYpPPL1X8VIZMe0WTA+Jr7blUxwUSEZNkjoMTgSw==", "integrity": "sha512-vgJ5OLWadI8aKjDlOH3rb+dYyPd2GTZuQC/Tihjct6F9GpXGZINo3Y/IVuZVTM1eDQB+/AOsjPUWH/WySDaXvw==",
"dev": true "dev": true
}, },
"@xtuc/ieee754": { "@xtuc/ieee754": {
@ -8816,9 +8816,9 @@
"dev": true "dev": true
}, },
"fastq": { "fastq": {
"version": "1.11.1", "version": "1.12.0",
"resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.1.tgz", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.12.0.tgz",
"integrity": "sha512-HOnr8Mc60eNYl1gzwp6r5RoUyAn5/glBolUzP/Ez6IFVPMPirxn/9phgL6zhOtaTy7ISwPvQ+wT+hfcRZh/bzw==", "integrity": "sha512-VNX0QkHK3RsXVKr9KrlUv/FoTa0NdbYoHHl7uXHv2rzyHSlxjdNAKug2twd9luJxpcyNeAgf5iPPMutJO67Dfg==",
"dev": true, "dev": true,
"requires": { "requires": {
"reusify": "^1.0.4" "reusify": "^1.0.4"
@ -17153,9 +17153,9 @@
"dev": true "dev": true
}, },
"sass": { "sass": {
"version": "1.37.5", "version": "1.38.0",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.37.5.tgz", "resolved": "https://registry.npmjs.org/sass/-/sass-1.38.0.tgz",
"integrity": "sha512-Cx3ewxz9QB/ErnVIiWg2cH0kiYZ0FPvheDTVC6BsiEGBTZKKZJ1Gq5Kq6jy3PKtL6+EJ8NIoaBW/RSd2R6cZOA==", "integrity": "sha512-WBccZeMigAGKoI+NgD7Adh0ab1HUq+6BmyBUEaGxtErbUtWUevEbdgo5EZiJQofLUGcKtlNaO2IdN73AHEua5g==",
"dev": true, "dev": true,
"requires": { "requires": {
"chokidar": ">=3.0.0 <4.0.0" "chokidar": ">=3.0.0 <4.0.0"
@ -18655,9 +18655,9 @@
} }
}, },
"ts-node": { "ts-node": {
"version": "10.2.0", "version": "10.2.1",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.0.tgz", "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.2.1.tgz",
"integrity": "sha512-FstYHtQz6isj8rBtYMN4bZdnXN1vq4HCbqn9vdNQcInRqtB86PePJQIxE6es0PhxKWhj2PHuwbG40H+bxkZPmg==", "integrity": "sha512-hCnyOyuGmD5wHleOQX6NIjJtYVIO8bPP8F2acWkB4W06wdlkgyvJtubO/I9NkI88hCFECbsEgoLc0VNkYmcSfw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@cspotcode/source-map-support": "0.6.1", "@cspotcode/source-map-support": "0.6.1",
@ -19206,9 +19206,9 @@
"dev": true "dev": true
}, },
"webpack": { "webpack": {
"version": "5.50.0", "version": "5.51.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.50.0.tgz", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.51.0.tgz",
"integrity": "sha512-hqxI7t/KVygs0WRv/kTgUW8Kl3YC81uyWQSo/7WUs5LsuRw0htH/fCwbVBGCuiX/t4s7qzjXFcf41O8Reiypag==", "integrity": "sha512-oySQoKUuf5r0JaPIYi8q90c/GmU9fGdSbZ0cAjFq3OWx57wniRTWvta1T9t+e5WZ6H6mHrxksNatkqfIEuTWGg==",
"dev": true, "dev": true,
"requires": { "requires": {
"@types/eslint-scope": "^3.7.0", "@types/eslint-scope": "^3.7.0",
@ -19407,15 +19407,15 @@
} }
}, },
"webpack-cli": { "webpack-cli": {
"version": "4.7.2", "version": "4.8.0",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.7.2.tgz", "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.8.0.tgz",
"integrity": "sha512-mEoLmnmOIZQNiRl0ebnjzQ74Hk0iKS5SiEEnpq3dRezoyR3yPaeQZCMCe+db4524pj1Pd5ghZXjT41KLzIhSLw==", "integrity": "sha512-+iBSWsX16uVna5aAYN6/wjhJy1q/GKk4KjKvfg90/6hykCTSgozbfz5iRgDTSJt/LgSbYxdBX3KBHeobIs+ZEw==",
"dev": true, "dev": true,
"requires": { "requires": {
"@discoveryjs/json-ext": "^0.5.0", "@discoveryjs/json-ext": "^0.5.0",
"@webpack-cli/configtest": "^1.0.4", "@webpack-cli/configtest": "^1.0.4",
"@webpack-cli/info": "^1.3.0", "@webpack-cli/info": "^1.3.0",
"@webpack-cli/serve": "^1.5.1", "@webpack-cli/serve": "^1.5.2",
"colorette": "^1.2.1", "colorette": "^1.2.1",
"commander": "^7.0.0", "commander": "^7.0.0",
"execa": "^5.0.0", "execa": "^5.0.0",
@ -19467,12 +19467,6 @@
"integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==",
"dev": true "dev": true
}, },
"human-signals": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz",
"integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==",
"dev": true
},
"import-local": { "import-local": {
"version": "3.0.2", "version": "3.0.2",
"resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz",
@ -19495,12 +19489,6 @@
"integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==",
"dev": true "dev": true
}, },
"mimic-fn": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
"dev": true
},
"npm-run-path": { "npm-run-path": {
"version": "4.0.1", "version": "4.0.1",
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
@ -19510,15 +19498,6 @@
"path-key": "^3.0.0" "path-key": "^3.0.0"
} }
}, },
"onetime": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
"dev": true,
"requires": {
"mimic-fn": "^2.1.0"
}
},
"path-key": { "path-key": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
@ -19561,22 +19540,6 @@
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==",
"dev": true "dev": true
}, },
"v8-compile-cache": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz",
"integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
"dev": true
},
"webpack-merge": {
"version": "5.8.0",
"resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz",
"integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==",
"dev": true,
"requires": {
"clone-deep": "^4.0.1",
"wildcard": "^2.0.0"
}
},
"which": { "which": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",

View File

@ -46,7 +46,7 @@
"@types/css-font-loading-module": "0.0.6", "@types/css-font-loading-module": "0.0.6",
"@types/dom-mediacapture-record": "^1.0.10", "@types/dom-mediacapture-record": "^1.0.10",
"@types/jest": "^27.0.1", "@types/jest": "^27.0.1",
"@types/react": "^17.0.17", "@types/react": "^17.0.19",
"@types/react-dom": "^17.0.9", "@types/react-dom": "^17.0.9",
"@types/resize-observer-browser": "^0.1.6", "@types/resize-observer-browser": "^0.1.6",
"@types/wicg-mediasession": "^1.1.2", "@types/wicg-mediasession": "^1.1.2",
@ -87,17 +87,17 @@
"raw-loader": "^4.0.2", "raw-loader": "^4.0.2",
"react": "^17.0.2", "react": "^17.0.2",
"replace-in-file": "^6.2.0", "replace-in-file": "^6.2.0",
"sass": "^1.37.5", "sass": "^1.38.0",
"sass-loader": "^12.1.0", "sass-loader": "^12.1.0",
"style-loader": "^3.2.1", "style-loader": "^3.2.1",
"terser": "^5.7.1", "terser": "^5.7.1",
"terser-webpack-plugin": "^5.1.4", "terser-webpack-plugin": "^5.1.4",
"ts-node": "^10.2.0", "ts-node": "^10.2.1",
"typescript": "^4.3.5", "typescript": "^4.3.5",
"url-loader": "^4.1.1", "url-loader": "^4.1.1",
"webpack": "^5.50.0", "webpack": "^5.51.0",
"webpack-bundle-analyzer": "^4.4.2", "webpack-bundle-analyzer": "^4.4.2",
"webpack-cli": "^4.7.2", "webpack-cli": "^4.8.0",
"webpack-dev-server": "^3.11.2", "webpack-dev-server": "^3.11.2",
"webpack-merge": "^5.8.0" "webpack-merge": "^5.8.0"
}, },

View File

@ -137,7 +137,7 @@ export function buildApiMessageWithChatId(chatId: number, mtpMessage: UniversalM
content.action = action; content.action = action;
} }
const { replyToMsgId, replyToTopId } = mtpMessage.replyTo || {}; const { replyToMsgId, replyToTopId, replyToPeerId } = mtpMessage.replyTo || {};
const isEdited = mtpMessage.editDate && !mtpMessage.editHide; const isEdited = mtpMessage.editDate && !mtpMessage.editHide;
const { const {
inlineButtons, keyboardButtons, keyboardPlaceholder, isKeyboardSingleUse, inlineButtons, keyboardButtons, keyboardPlaceholder, isKeyboardSingleUse,
@ -158,6 +158,7 @@ export function buildApiMessageWithChatId(chatId: number, mtpMessage: UniversalM
views: mtpMessage.views, views: mtpMessage.views,
isFromScheduled: mtpMessage.fromScheduled, isFromScheduled: mtpMessage.fromScheduled,
...(replyToMsgId && { replyToMessageId: replyToMsgId }), ...(replyToMsgId && { replyToMessageId: replyToMsgId }),
...(replyToPeerId && { replyToChatId: getApiChatIdFromMtpPeer(replyToPeerId) }),
...(replyToTopId && { replyToTopMessageId: replyToTopId }), ...(replyToTopId && { replyToTopMessageId: replyToTopId }),
...(forwardInfo && { forwardInfo }), ...(forwardInfo && { forwardInfo }),
...(isEdited && { isEdited }), ...(isEdited && { isEdited }),

View File

@ -214,12 +214,12 @@ export async function invokeRequest<T extends GramJs.AnyRequest>(
console.error(err); console.error(err);
} }
dispatchErrorUpdate(err, request);
if (shouldThrow) { if (shouldThrow) {
throw err; throw err;
} }
dispatchErrorUpdate(err, request);
return undefined; return undefined;
} }
} }

View File

@ -116,16 +116,36 @@ export async function fetchMessages({
export async function fetchMessage({ chat, messageId }: { chat: ApiChat; messageId: number }) { export async function fetchMessage({ chat, messageId }: { chat: ApiChat; messageId: number }) {
const isChannel = getEntityTypeById(chat.id) === 'channel'; const isChannel = getEntityTypeById(chat.id) === 'channel';
const result = await invokeRequest( let result;
isChannel try {
? new GramJs.channels.GetMessages({ result = await invokeRequest(
channel: buildInputEntity(chat.id, chat.accessHash) as GramJs.InputChannel, isChannel
id: [new GramJs.InputMessageID({ id: messageId })], ? new GramJs.channels.GetMessages({
}) channel: buildInputEntity(chat.id, chat.accessHash) as GramJs.InputChannel,
: new GramJs.messages.GetMessages({ id: [new GramJs.InputMessageID({ id: messageId })],
id: [new GramJs.InputMessageID({ id: messageId })], })
}), : new GramJs.messages.GetMessages({
); id: [new GramJs.InputMessageID({ id: messageId })],
}),
undefined,
true,
);
} catch (err) {
const { message } = err;
// When fetching messages for the bot @replies, there may be situations when the user was banned
// in the comment group or this group was deleted
if (message !== 'CHANNEL_PRIVATE') {
onUpdate({
'@type': 'error',
error: {
message,
isSlowMode: false,
hasErrorKey: true,
},
});
}
}
if (!result || result instanceof GramJs.messages.MessagesNotModified) { if (!result || result instanceof GramJs.messages.MessagesNotModified) {
return undefined; return undefined;
@ -731,6 +751,7 @@ export async function requestThreadInfoUpdate({
chatId: discussionChatId, chatId: discussionChatId,
threadId, threadId,
threadInfo: { threadInfo: {
threadId,
topMessageId: topMessageResult.messages[topMessageResult.messages.length - 1].id, topMessageId: topMessageResult.messages[topMessageResult.messages.length - 1].id,
lastReadInboxMessageId: topMessageResult.readInboxMaxId, lastReadInboxMessageId: topMessageResult.readInboxMaxId,
messagesCount: (repliesResult instanceof GramJs.messages.ChannelMessages) ? repliesResult.count : undefined, messagesCount: (repliesResult instanceof GramJs.messages.ChannelMessages) ? repliesResult.count : undefined,

View File

@ -236,6 +236,7 @@ export interface ApiMessage {
date: number; date: number;
isOutgoing: boolean; isOutgoing: boolean;
senderId?: number; senderId?: number;
replyToChatId?: number;
replyToMessageId?: number; replyToMessageId?: number;
replyToTopMessageId?: number; replyToTopMessageId?: number;
sendingState?: 'messageSendingStatePending' | 'messageSendingStateFailed'; sendingState?: 'messageSendingStatePending' | 'messageSendingStateFailed';

View File

@ -23,6 +23,10 @@
i { i {
font-size: 2.5rem; font-size: 2.5rem;
&.icon-reply-filled {
transform: scale(.7);
}
} }
&.size-micro { &.size-micro {

View File

@ -6,7 +6,7 @@ import { ApiUser, ApiChat, ApiMediaFormat } from '../../api/types';
import { IS_TEST } from '../../config'; import { IS_TEST } from '../../config';
import { import {
getChatAvatarHash, getChatTitle, isChatPrivate, getChatAvatarHash, getChatTitle, isChatPrivate,
getUserFullName, isUserOnline, isDeletedUser, getUserColorKey, getUserFullName, isUserOnline, isDeletedUser, getUserColorKey, isChatWithRepliesBot,
} from '../../modules/helpers'; } from '../../modules/helpers';
import { getFirstLetters } from '../../util/textFormat'; import { getFirstLetters } from '../../util/textFormat';
import buildClassName from '../../util/buildClassName'; import buildClassName from '../../util/buildClassName';
@ -41,6 +41,7 @@ const Avatar: FC<OwnProps> = ({
onClick, onClick,
}) => { }) => {
const isDeleted = user && isDeletedUser(user); const isDeleted = user && isDeletedUser(user);
const isReplies = user && isChatWithRepliesBot(user.id);
let imageHash: string | undefined; let imageHash: string | undefined;
if (!isSavedMessages && !isDeleted) { if (!isSavedMessages && !isDeleted) {
@ -62,6 +63,8 @@ const Avatar: FC<OwnProps> = ({
content = <i className="icon-avatar-saved-messages" />; content = <i className="icon-avatar-saved-messages" />;
} else if (isDeleted) { } else if (isDeleted) {
content = <i className="icon-avatar-deleted-account" />; content = <i className="icon-avatar-deleted-account" />;
} else if (isReplies) {
content = <i className="icon-reply-filled" />;
} else if (shouldRenderFullMedia) { } else if (shouldRenderFullMedia) {
content = <img src={dataUri} className={`${transitionClassNames} avatar-media`} alt="" decoding="async" />; content = <img src={dataUri} className={`${transitionClassNames} avatar-media`} alt="" decoding="async" />;
} else if (user) { } else if (user) {
@ -81,6 +84,7 @@ const Avatar: FC<OwnProps> = ({
`color-bg-${getUserColorKey(user || chat)}`, `color-bg-${getUserColorKey(user || chat)}`,
isSavedMessages && 'saved-messages', isSavedMessages && 'saved-messages',
isDeleted && 'deleted-account', isDeleted && 'deleted-account',
isReplies && 'replies-bot-account',
withOnlineStatus && isOnline && 'online', withOnlineStatus && isOnline && 'online',
onClick && 'interactive', onClick && 'interactive',
(!isSavedMessages && !shouldRenderFullMedia) && 'no-photo', (!isSavedMessages && !shouldRenderFullMedia) && 'no-photo',

View File

@ -7,7 +7,6 @@ import { ApiMediaFormat, ApiVideo } from '../../api/types';
import buildClassName from '../../util/buildClassName'; import buildClassName from '../../util/buildClassName';
import { ObserveFn, useIsIntersecting } from '../../hooks/useIntersectionObserver'; import { ObserveFn, useIsIntersecting } from '../../hooks/useIntersectionObserver';
import useMedia from '../../hooks/useMedia'; import useMedia from '../../hooks/useMedia';
import useTransitionForMedia from '../../hooks/useTransitionForMedia';
import useVideoCleanup from '../../hooks/useVideoCleanup'; import useVideoCleanup from '../../hooks/useVideoCleanup';
import useBuffering from '../../hooks/useBuffering'; import useBuffering from '../../hooks/useBuffering';
import useCanvasBlur from '../../hooks/useCanvasBlur'; import useCanvasBlur from '../../hooks/useCanvasBlur';

View File

@ -23,6 +23,7 @@
.spinner-wrapper, .spinner-wrapper,
&.deleted-account, &.deleted-account,
&.replies-bot-account,
&.no-photo, &.no-photo,
&.saved-messages { &.saved-messages {
display: flex; display: flex;
@ -37,6 +38,7 @@
font-size: 14rem; font-size: 14rem;
} }
&.replies-bot-account,
&.deleted-account, &.deleted-account,
&.saved-messages { &.saved-messages {
font-size: 20rem; font-size: 20rem;

View File

@ -5,7 +5,7 @@ import {
} from '../../api/types'; } from '../../api/types';
import { import {
getChatAvatarHash, isDeletedUser, getUserColorKey, getChatTitle, isChatPrivate, getUserFullName, getChatAvatarHash, isDeletedUser, getUserColorKey, getChatTitle, isChatPrivate, getUserFullName, isChatWithRepliesBot,
} from '../../modules/helpers'; } from '../../modules/helpers';
import renderText from './helpers/renderText'; import renderText from './helpers/renderText';
import buildClassName from '../../util/buildClassName'; import buildClassName from '../../util/buildClassName';
@ -40,6 +40,7 @@ const ProfilePhoto: FC<OwnProps> = ({
}) => { }) => {
const lang = useLang(); const lang = useLang();
const isDeleted = user && isDeletedUser(user); const isDeleted = user && isDeletedUser(user);
const isRepliesChat = chat && isChatWithRepliesBot(chat.id);
function getMediaHash(size: 'normal' | 'big' = 'big', forceAvatar?: boolean) { function getMediaHash(size: 'normal' | 'big' = 'big', forceAvatar?: boolean) {
if (photo && !forceAvatar) { if (photo && !forceAvatar) {
@ -47,7 +48,7 @@ const ProfilePhoto: FC<OwnProps> = ({
} }
let hash: string | undefined; let hash: string | undefined;
if (!isSavedMessages && !isDeleted) { if (!isSavedMessages && !isDeleted && !isRepliesChat) {
if (user) { if (user) {
hash = getChatAvatarHash(user, size); hash = getChatAvatarHash(user, size);
} else if (chat) { } else if (chat) {
@ -81,6 +82,8 @@ const ProfilePhoto: FC<OwnProps> = ({
content = <i className="icon-avatar-saved-messages" />; content = <i className="icon-avatar-saved-messages" />;
} else if (isDeleted) { } else if (isDeleted) {
content = <i className="icon-avatar-deleted-account" />; content = <i className="icon-avatar-deleted-account" />;
} else if (isRepliesChat) {
content = <i className="icon-reply-filled" />;
} else if (imageSrc) { } else if (imageSrc) {
content = <img src={imageSrc} className="avatar-media" alt="" decoding="async" />; content = <img src={imageSrc} className="avatar-media" alt="" decoding="async" />;
} else if (!imageSrc && user) { } else if (!imageSrc && user) {
@ -102,6 +105,7 @@ const ProfilePhoto: FC<OwnProps> = ({
`color-bg-${getUserColorKey(user || chat)}`, `color-bg-${getUserColorKey(user || chat)}`,
isSavedMessages && 'saved-messages', isSavedMessages && 'saved-messages',
isDeleted && 'deleted-account', isDeleted && 'deleted-account',
isRepliesChat && 'replies-bot-account',
(!isSavedMessages && !(imageSrc)) && 'no-photo', (!isSavedMessages && !(imageSrc)) && 'no-photo',
); );

View File

@ -3,10 +3,9 @@ import React, {
} from '../../lib/teact/teact'; } from '../../lib/teact/teact';
import { getGlobal, withGlobal } from '../../lib/teact/teactn'; import { getGlobal, withGlobal } from '../../lib/teact/teactn';
import { AudioOrigin } from '../../types'; import { AudioOrigin, LangCode } from '../../types';
import { GlobalActions } from '../../global/types'; import { GlobalActions } from '../../global/types';
import { ApiMessage } from '../../api/types'; import { ApiMessage } from '../../api/types';
import { LangCode } from '../../types';
import '../../modules/actions/all'; import '../../modules/actions/all';
import { import {

View File

@ -26,7 +26,12 @@ import {
selectScheduledMessages, selectScheduledMessages,
selectCurrentMessageIds, selectCurrentMessageIds,
} from '../../modules/selectors'; } from '../../modules/selectors';
import { isChatChannel, isChatGroup, isChatPrivate } from '../../modules/helpers'; import {
isChatChannel,
isChatPrivate,
isChatWithRepliesBot,
isChatGroup,
} from '../../modules/helpers';
import { orderBy, pick } from '../../util/iteratees'; import { orderBy, pick } from '../../util/iteratees';
import { fastRaf, debounce, onTickEnd } from '../../util/schedulers'; import { fastRaf, debounce, onTickEnd } from '../../util/schedulers';
import useLayoutEffectWithPrevDeps from '../../hooks/useLayoutEffectWithPrevDeps'; import useLayoutEffectWithPrevDeps from '../../hooks/useLayoutEffectWithPrevDeps';
@ -67,6 +72,7 @@ type StateProps = {
isChannelChat?: boolean; isChannelChat?: boolean;
isGroupChat?: boolean; isGroupChat?: boolean;
isChatWithSelf?: boolean; isChatWithSelf?: boolean;
isRepliesChat?: boolean;
isCreator?: boolean; isCreator?: boolean;
isBot?: boolean; isBot?: boolean;
messageIds?: number[]; messageIds?: number[];
@ -112,6 +118,7 @@ const MessageList: FC<OwnProps & StateProps & DispatchProps> = ({
isReady, isReady,
isActive, isActive,
isChatWithSelf, isChatWithSelf,
isRepliesChat,
isCreator, isCreator,
isBot, isBot,
messageIds, messageIds,
@ -441,7 +448,7 @@ const MessageList: FC<OwnProps & StateProps & DispatchProps> = ({
const lang = useLang(); const lang = useLang();
const isPrivate = Boolean(chatId && isChatPrivate(chatId)); const isPrivate = Boolean(chatId && isChatPrivate(chatId));
const withUsers = Boolean((!isPrivate && !isChannelChat) || isChatWithSelf); const withUsers = Boolean((!isPrivate && !isChannelChat) || isChatWithSelf || isRepliesChat);
const noAvatars = Boolean(!withUsers || isChannelChat); const noAvatars = Boolean(!withUsers || isChannelChat);
const shouldRenderGreeting = isChatPrivate(chatId) && !isChatWithSelf && !isBot const shouldRenderGreeting = isChatPrivate(chatId) && !isChatWithSelf && !isBot
&& ( && (
@ -567,6 +574,7 @@ export default memo(withGlobal<OwnProps>(
isGroupChat: isChatGroup(chat), isGroupChat: isChatGroup(chat),
isCreator: chat.isCreator, isCreator: chat.isCreator,
isChatWithSelf: selectIsChatWithSelf(global, chatId), isChatWithSelf: selectIsChatWithSelf(global, chatId),
isRepliesChat: isChatWithRepliesBot(chatId),
isBot: Boolean(chatBot), isBot: Boolean(chatBot),
messageIds, messageIds,
messagesById, messagesById,

View File

@ -315,14 +315,14 @@ const MiddleHeader: FC<OwnProps & StateProps & DispatchProps> = ({
<> <>
{renderBackButton()} {renderBackButton()}
<h3> <h3>
{lang('CommentsCount', messagesCount)} {lang('CommentsCount', messagesCount, 'i')}
</h3> </h3>
</> </>
) : messageListType === 'pinned' ? ( ) : messageListType === 'pinned' ? (
<> <>
{renderBackButton()} {renderBackButton()}
<h3> <h3>
{lang('PinnedMessagesCount', messagesCount)} {lang('PinnedMessagesCount', messagesCount, 'i')}
</h3> </h3>
</> </>
) : messageListType === 'scheduled' ? ( ) : messageListType === 'scheduled' ? (
@ -448,9 +448,7 @@ export default memo(withGlobal<OwnProps>(
messagesCount = scheduledIds?.length; messagesCount = scheduledIds?.length;
} else if (messageListType === 'thread' && threadId !== MAIN_THREAD_ID) { } else if (messageListType === 'thread' && threadId !== MAIN_THREAD_ID) {
const threadInfo = selectThreadInfo(global, chatId, threadId); const threadInfo = selectThreadInfo(global, chatId, threadId);
if (threadInfo) { messagesCount = threadInfo?.messagesCount || 0;
messagesCount = threadInfo.messagesCount;
}
} }
const state: StateProps = { const state: StateProps = {

View File

@ -52,6 +52,7 @@ import {
isAnonymousOwnMessage, isAnonymousOwnMessage,
isMessageLocal, isMessageLocal,
isChatPrivate, isChatPrivate,
isChatWithRepliesBot,
getMessageCustomShape, getMessageCustomShape,
isChatChannel, isChatChannel,
getMessageSingleEmoji, getMessageSingleEmoji,
@ -142,6 +143,7 @@ type StateProps = {
isResizingContainer?: boolean; isResizingContainer?: boolean;
isForwarding?: boolean; isForwarding?: boolean;
isChatWithSelf?: boolean; isChatWithSelf?: boolean;
isRepliesChat?: boolean;
isChannel?: boolean; isChannel?: boolean;
canReply?: boolean; canReply?: boolean;
lastSyncTime?: number; lastSyncTime?: number;
@ -203,6 +205,7 @@ const Message: FC<OwnProps & StateProps & DispatchProps> = ({
isResizingContainer, isResizingContainer,
isForwarding, isForwarding,
isChatWithSelf, isChatWithSelf,
isRepliesChat,
isChannel, isChannel,
canReply, canReply,
lastSyncTime, lastSyncTime,
@ -262,7 +265,7 @@ const Message: FC<OwnProps & StateProps & DispatchProps> = ({
const hasReply = isReplyMessage(message) && !shouldHideReply; const hasReply = isReplyMessage(message) && !shouldHideReply;
const hasThread = Boolean(threadInfo) && messageListType === 'thread'; const hasThread = Boolean(threadInfo) && messageListType === 'thread';
const { forwardInfo, viaBotId } = message; const { forwardInfo, viaBotId } = message;
const asForwarded = forwardInfo && !isChatWithSelf && !forwardInfo.isLinkedChannelPost; const asForwarded = forwardInfo && !isChatWithSelf && !isRepliesChat && !forwardInfo.isLinkedChannelPost;
const isInDocumentGroup = Boolean(message.groupedId) && !message.isInAlbum; const isInDocumentGroup = Boolean(message.groupedId) && !message.isInAlbum;
const isAlbum = Boolean(album) && album!.messages.length > 1; const isAlbum = Boolean(album) && album!.messages.length > 1;
const { const {
@ -283,8 +286,11 @@ const Message: FC<OwnProps & StateProps & DispatchProps> = ({
); );
const canForward = isChannel && !isScheduled; const canForward = isChannel && !isScheduled;
const canFocus = Boolean(isPinnedList const canFocus = Boolean(isPinnedList
|| (forwardInfo && (forwardInfo.isChannelPost || (isChatWithSelf && !isOwn)) && forwardInfo.fromMessageId)); || (forwardInfo
const avatarPeer = forwardInfo && (isChatWithSelf || !sender) ? originSender : sender; && (forwardInfo.isChannelPost || (isChatWithSelf && !isOwn) || isRepliesChat)
&& forwardInfo.fromMessageId
));
const avatarPeer = forwardInfo && (isChatWithSelf || isRepliesChat || !sender) ? originSender : sender;
const senderPeer = forwardInfo ? originSender : sender; const senderPeer = forwardInfo ? originSender : sender;
const selectMessage = useCallback((e?: React.MouseEvent<HTMLDivElement, MouseEvent>, groupedId?: string) => { const selectMessage = useCallback((e?: React.MouseEvent<HTMLDivElement, MouseEvent>, groupedId?: string) => {
@ -344,6 +350,7 @@ const Message: FC<OwnProps & StateProps & DispatchProps> = ({
threadId, threadId,
isInDocumentGroup, isInDocumentGroup,
Boolean(isScheduled), Boolean(isScheduled),
isRepliesChat,
album, album,
avatarPeer, avatarPeer,
senderPeer, senderPeer,
@ -389,7 +396,12 @@ const Message: FC<OwnProps & StateProps & DispatchProps> = ({
&& messageListType === 'thread' && !noComments; && messageListType === 'thread' && !noComments;
const withAppendix = contentClassName.includes('has-appendix'); const withAppendix = contentClassName.includes('has-appendix');
useEnsureMessage(chatId, hasReply ? message.replyToMessageId : undefined, replyMessage, message.id); useEnsureMessage(
isRepliesChat && message.replyToChatId ? message.replyToChatId : chatId,
hasReply ? message.replyToMessageId : undefined,
replyMessage,
message.id,
);
useFocusMessage(ref, chatId, isFocused, focusDirection, noFocusHighlight, isResizingContainer); useFocusMessage(ref, chatId, isFocused, focusDirection, noFocusHighlight, isResizingContainer);
useLayoutEffect(() => { useLayoutEffect(() => {
if (!appendixRef.current) { if (!appendixRef.current) {
@ -796,11 +808,12 @@ export default memo(withGlobal<OwnProps>(
message, album, withSenderName, withAvatar, threadId, messageListType, message, album, withSenderName, withAvatar, threadId, messageListType,
} = ownProps; } = ownProps;
const { const {
id, chatId, viaBotId, replyToMessageId, isOutgoing, id, chatId, viaBotId, replyToChatId, replyToMessageId, isOutgoing,
} = message; } = message;
const chat = selectChat(global, chatId); const chat = selectChat(global, chatId);
const isChatWithSelf = selectIsChatWithSelf(global, chatId); const isChatWithSelf = selectIsChatWithSelf(global, chatId);
const isRepliesChat = isChatWithRepliesBot(chatId);
const isChannel = chat && isChatChannel(chat); const isChannel = chat && isChatChannel(chat);
const chatUsername = chat?.username; const chatUsername = chat?.username;
@ -815,7 +828,7 @@ export default memo(withGlobal<OwnProps>(
const shouldHideReply = replyToMessageId === threadTopMessageId; const shouldHideReply = replyToMessageId === threadTopMessageId;
const replyMessage = replyToMessageId && !shouldHideReply const replyMessage = replyToMessageId && !shouldHideReply
? selectChatMessage(global, chatId, replyToMessageId) ? selectChatMessage(global, isRepliesChat && replyToChatId ? replyToChatId : chatId, replyToMessageId)
: undefined; : undefined;
const replyMessageSender = replyMessage && selectSender(global, replyMessage); const replyMessageSender = replyMessage && selectSender(global, replyMessage);
@ -859,6 +872,7 @@ export default memo(withGlobal<OwnProps>(
isFocused, isFocused,
isForwarding, isForwarding,
isChatWithSelf, isChatWithSelf,
isRepliesChat,
isChannel, isChannel,
canReply, canReply,
lastSyncTime, lastSyncTime,

View File

@ -16,6 +16,7 @@ export default function useInnerHandlers(
threadId: number, threadId: number,
isInDocumentGroup: boolean, isInDocumentGroup: boolean,
isScheduled?: boolean, isScheduled?: boolean,
isChatWithRepliesBot?: boolean,
album?: IAlbum, album?: IAlbum,
avatarPeer?: ApiUser | ApiChat, avatarPeer?: ApiUser | ApiChat,
senderPeer?: ApiUser | ApiChat, senderPeer?: ApiUser | ApiChat,
@ -23,11 +24,11 @@ export default function useInnerHandlers(
) { ) {
const { const {
openUserInfo, openChat, showNotification, focusMessage, openMediaViewer, openAudioPlayer, openUserInfo, openChat, showNotification, focusMessage, openMediaViewer, openAudioPlayer,
markMessagesRead, cancelSendingMessage, sendPollVote, openForwardMenu, markMessagesRead, cancelSendingMessage, sendPollVote, openForwardMenu, focusMessageInComments,
} = getDispatch(); } = getDispatch();
const { const {
id: messageId, forwardInfo, replyToMessageId, groupedId, id: messageId, forwardInfo, replyToMessageId, replyToChatId, replyToTopMessageId, groupedId,
} = message; } = message;
const handleAvatarClick = useCallback(() => { const handleAvatarClick = useCallback(() => {
@ -66,9 +67,12 @@ export default function useInnerHandlers(
const handleReplyClick = useCallback((): void => { const handleReplyClick = useCallback((): void => {
focusMessage({ focusMessage({
chatId, threadId, messageId: replyToMessageId, replyMessageId: messageId, chatId: isChatWithRepliesBot && replyToChatId ? replyToChatId : chatId,
threadId,
messageId: replyToMessageId,
replyMessageId: isChatWithRepliesBot && replyToChatId ? undefined : messageId,
}); });
}, [focusMessage, chatId, threadId, replyToMessageId, messageId]); }, [focusMessage, isChatWithRepliesBot, replyToChatId, chatId, threadId, replyToMessageId, messageId]);
const handleMediaClick = useCallback((): void => { const handleMediaClick = useCallback((): void => {
openMediaViewer({ openMediaViewer({
@ -127,10 +131,22 @@ export default function useInnerHandlers(
}); });
return; return;
} }
focusMessage({
chatId: forwardInfo!.fromChatId, messageId: forwardInfo!.fromMessageId, if (isChatWithRepliesBot && replyToChatId) {
}); focusMessageInComments({
}, [isInDocumentGroup, focusMessage, forwardInfo, groupedId, chatId]); chatId: replyToChatId,
threadId: replyToTopMessageId,
messageId: forwardInfo!.fromMessageId,
});
} else {
focusMessage({
chatId: forwardInfo!.fromChatId, messageId: forwardInfo!.fromMessageId,
});
}
}, [
isInDocumentGroup, isChatWithRepliesBot, replyToChatId, focusMessage, forwardInfo, groupedId, chatId,
focusMessageInComments, replyToTopMessageId,
]);
const selectWithGroupedId = useCallback((e: React.MouseEvent<HTMLDivElement, MouseEvent>) => { const selectWithGroupedId = useCallback((e: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
e.stopPropagation(); e.stopPropagation();

View File

@ -136,7 +136,7 @@ export const RE_TME_ADDSTICKERS_LINK = /^(?:https?:\/\/)?(?:t\.me\/addstickers\/
// MTProto constants // MTProto constants
export const SERVICE_NOTIFICATIONS_USER_ID = 777000; export const SERVICE_NOTIFICATIONS_USER_ID = 777000;
export const REPLIES_USER_ID = 1271266957; export const REPLIES_USER_ID = 1271266957; // TODO For Test connection ID must be equal to 708513
export const ALL_FOLDER_ID = 0; export const ALL_FOLDER_ID = 0;
export const ARCHIVED_FOLDER_ID = 1; export const ARCHIVED_FOLDER_ID = 1;
export const DELETED_COMMENTS_CHANNEL_ID = 777; export const DELETED_COMMENTS_CHANNEL_ID = 777;

View File

@ -453,7 +453,7 @@ export type ActionTypes = (
'setAuthRememberMe' | 'clearAuthError' | 'uploadProfilePhoto' | 'goToAuthQrCode' | 'clearCache' | 'setAuthRememberMe' | 'clearAuthError' | 'uploadProfilePhoto' | 'goToAuthQrCode' | 'clearCache' |
// chats // chats
'preloadTopChatMessages' | 'loadChats' | 'loadMoreChats' | 'openChat' | 'openChatWithInfo' | 'openLinkedChat' | 'preloadTopChatMessages' | 'loadChats' | 'loadMoreChats' | 'openChat' | 'openChatWithInfo' | 'openLinkedChat' |
'openSupportChat' | 'openTipsChat' | 'openSupportChat' | 'openTipsChat' | 'focusMessageInComments' |
'loadFullChat' | 'loadTopChats' | 'requestChatUpdate' | 'updateChatMutedState' | 'loadFullChat' | 'loadTopChats' | 'requestChatUpdate' | 'updateChatMutedState' |
'joinChannel' | 'leaveChannel' | 'deleteChannel' | 'toggleChatPinned' | 'toggleChatArchived' | 'toggleChatUnread' | 'joinChannel' | 'leaveChannel' | 'deleteChannel' | 'toggleChatPinned' | 'toggleChatArchived' | 'toggleChatUnread' |
'loadChatFolders' | 'loadRecommendedChatFolders' | 'editChatFolder' | 'addChatFolder' | 'deleteChatFolder' | 'loadChatFolders' | 'loadRecommendedChatFolders' | 'editChatFolder' | 'addChatFolder' | 'deleteChatFolder' |

View File

@ -140,6 +140,23 @@ addReducer('openLinkedChat', (global, actions, payload) => {
})(); })();
}); });
addReducer('focusMessageInComments', (global, actions, payload) => {
const { chatId, threadId, messageId } = payload!;
const chat = selectChat(global, chatId);
if (!chat) {
return;
}
(async () => {
const result = await callApi('requestThreadInfoUpdate', { chat, threadId });
if (!result) {
return;
}
actions.focusMessage({ chatId, threadId, messageId });
})();
});
addReducer('openSupportChat', (global, actions) => { addReducer('openSupportChat', (global, actions) => {
const chat = selectSupportChat(global); const chat = selectSupportChat(global);

View File

@ -10,7 +10,7 @@ import {
import { NotifyException, NotifySettings } from '../../types'; import { NotifyException, NotifySettings } from '../../types';
import { LangFn } from '../../hooks/useLang'; import { LangFn } from '../../hooks/useLang';
import { ARCHIVED_FOLDER_ID } from '../../config'; import { ARCHIVED_FOLDER_ID, REPLIES_USER_ID } from '../../config';
import { orderBy } from '../../util/iteratees'; import { orderBy } from '../../util/iteratees';
import { getUserFirstOrLastName } from './users'; import { getUserFirstOrLastName } from './users';
import { formatDateToString, formatTime } from '../../util/dateFormat'; import { formatDateToString, formatTime } from '../../util/dateFormat';
@ -44,6 +44,10 @@ export function isCommonBoxChat(chat: ApiChat) {
return chat.type === 'chatTypePrivate' || chat.type === 'chatTypeBasicGroup'; return chat.type === 'chatTypePrivate' || chat.type === 'chatTypeBasicGroup';
} }
export function isChatWithRepliesBot(chatId: number) {
return chatId === REPLIES_USER_ID;
}
export function getChatTypeString(chat: ApiChat) { export function getChatTypeString(chat: ApiChat) {
switch (chat.type) { switch (chat.type) {
case 'chatTypePrivate': case 'chatTypePrivate':
@ -131,7 +135,7 @@ export function getCanPostInChat(chat: ApiChat, threadId: number) {
return true; return true;
} }
if (chat.isRestricted || chat.migratedTo || chat.isNotJoined) { if (chat.isRestricted || chat.migratedTo || chat.isNotJoined || isChatWithRepliesBot(chat.id)) {
return false; return false;
} }

View File

@ -126,6 +126,7 @@ div {
--color-user: var(--color-user-8); --color-user: var(--color-user-8);
} }
&.replies-bot-account,
&.saved-messages { &.saved-messages {
--color-user: var(--color-primary); --color-user: var(--color-primary);
} }

View File

@ -1,5 +1,5 @@
import EMOJI_REGEX from "../lib/twemojiRegex"; import EMOJI_REGEX from '../lib/twemojiRegex';
import { fixNonStandardEmoji } from "./emoji"; import { fixNonStandardEmoji } from './emoji';
export function formatInteger(value: number) { export function formatInteger(value: number) {
return String(value).replace(/\d(?=(\d{3})+$)/g, '$& '); return String(value).replace(/\d(?=(\d{3})+$)/g, '$& ');
@ -39,7 +39,7 @@ export function getFirstLetters(phrase: string, count = 2) {
if (emojis && word.startsWith(emojis[0])) { if (emojis && word.startsWith(emojis[0])) {
return emojis[0]; return emojis[0];
} }
return word.match(/./u)![0].toUpperCase() return word.match(/./u)![0].toUpperCase();
}) })
.join(''); .join('');
} }