feat: support sending 1984 reports
This commit is contained in:
306
package-lock.json
generated
306
package-lock.json
generated
@@ -23,6 +23,7 @@
|
|||||||
"@radix-ui/react-hover-card": "^1.1.4",
|
"@radix-ui/react-hover-card": "^1.1.4",
|
||||||
"@radix-ui/react-label": "^2.1.1",
|
"@radix-ui/react-label": "^2.1.1",
|
||||||
"@radix-ui/react-popover": "^1.1.4",
|
"@radix-ui/react-popover": "^1.1.4",
|
||||||
|
"@radix-ui/react-radio-group": "^1.3.8",
|
||||||
"@radix-ui/react-scroll-area": "1.2.0",
|
"@radix-ui/react-scroll-area": "1.2.0",
|
||||||
"@radix-ui/react-select": "^2.1.4",
|
"@radix-ui/react-select": "^2.1.4",
|
||||||
"@radix-ui/react-separator": "^1.1.1",
|
"@radix-ui/react-separator": "^1.1.1",
|
||||||
@@ -3288,6 +3289,311 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-radio-group": {
|
||||||
|
"version": "1.3.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.8.tgz",
|
||||||
|
"integrity": "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/primitive": "1.1.3",
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.2",
|
||||||
|
"@radix-ui/react-context": "1.1.2",
|
||||||
|
"@radix-ui/react-direction": "1.1.1",
|
||||||
|
"@radix-ui/react-presence": "1.1.5",
|
||||||
|
"@radix-ui/react-primitive": "2.1.3",
|
||||||
|
"@radix-ui/react-roving-focus": "1.1.11",
|
||||||
|
"@radix-ui/react-use-controllable-state": "1.2.2",
|
||||||
|
"@radix-ui/react-use-previous": "1.1.1",
|
||||||
|
"@radix-ui/react-use-size": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/primitive": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-collection": {
|
||||||
|
"version": "1.1.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz",
|
||||||
|
"integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.2",
|
||||||
|
"@radix-ui/react-context": "1.1.2",
|
||||||
|
"@radix-ui/react-primitive": "2.1.3",
|
||||||
|
"@radix-ui/react-slot": "1.2.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-compose-refs": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-context": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-direction": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-id": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-presence": {
|
||||||
|
"version": "1.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz",
|
||||||
|
"integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.2",
|
||||||
|
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-primitive": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-slot": "1.2.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-roving-focus": {
|
||||||
|
"version": "1.1.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz",
|
||||||
|
"integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/primitive": "1.1.3",
|
||||||
|
"@radix-ui/react-collection": "1.1.7",
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.2",
|
||||||
|
"@radix-ui/react-context": "1.1.2",
|
||||||
|
"@radix-ui/react-direction": "1.1.1",
|
||||||
|
"@radix-ui/react-id": "1.1.1",
|
||||||
|
"@radix-ui/react-primitive": "2.1.3",
|
||||||
|
"@radix-ui/react-use-callback-ref": "1.1.1",
|
||||||
|
"@radix-ui/react-use-controllable-state": "1.2.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-slot": {
|
||||||
|
"version": "1.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
|
||||||
|
"integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-use-callback-ref": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-use-controllable-state": {
|
||||||
|
"version": "1.2.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
|
||||||
|
"integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-use-effect-event": "0.0.2",
|
||||||
|
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-use-layout-effect": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-use-previous": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-use-size": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/react-use-layout-effect": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-roving-focus": {
|
"node_modules/@radix-ui/react-roving-focus": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.1.tgz",
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
"@radix-ui/react-hover-card": "^1.1.4",
|
"@radix-ui/react-hover-card": "^1.1.4",
|
||||||
"@radix-ui/react-label": "^2.1.1",
|
"@radix-ui/react-label": "^2.1.1",
|
||||||
"@radix-ui/react-popover": "^1.1.4",
|
"@radix-ui/react-popover": "^1.1.4",
|
||||||
|
"@radix-ui/react-radio-group": "^1.3.8",
|
||||||
"@radix-ui/react-scroll-area": "1.2.0",
|
"@radix-ui/react-scroll-area": "1.2.0",
|
||||||
"@radix-ui/react-select": "^2.1.4",
|
"@radix-ui/react-select": "^2.1.4",
|
||||||
"@radix-ui/react-separator": "^1.1.1",
|
"@radix-ui/react-separator": "^1.1.1",
|
||||||
|
|||||||
129
src/components/NoteOptions/ReportDialog.tsx
Normal file
129
src/components/NoteOptions/ReportDialog.tsx
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
import { Button } from '@/components/ui/button'
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle
|
||||||
|
} from '@/components/ui/dialog'
|
||||||
|
import {
|
||||||
|
Drawer,
|
||||||
|
DrawerContent,
|
||||||
|
DrawerDescription,
|
||||||
|
DrawerHeader,
|
||||||
|
DrawerTitle
|
||||||
|
} from '@/components/ui/drawer'
|
||||||
|
import { Label } from '@/components/ui/label'
|
||||||
|
import { RadioGroup, RadioGroupItem } from '@/components/ui/radio-group'
|
||||||
|
import { createReportDraftEvent } from '@/lib/draft-event'
|
||||||
|
import { useNostr } from '@/providers/NostrProvider'
|
||||||
|
import { useScreenSize } from '@/providers/ScreenSizeProvider'
|
||||||
|
import { Loader } from 'lucide-react'
|
||||||
|
import { NostrEvent } from 'nostr-tools'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { toast } from 'sonner'
|
||||||
|
|
||||||
|
export default function ReportDialog({
|
||||||
|
event,
|
||||||
|
isOpen,
|
||||||
|
closeDialog
|
||||||
|
}: {
|
||||||
|
event: NostrEvent
|
||||||
|
isOpen: boolean
|
||||||
|
closeDialog: () => void
|
||||||
|
}) {
|
||||||
|
const { isSmallScreen } = useScreenSize()
|
||||||
|
|
||||||
|
if (isSmallScreen) {
|
||||||
|
return (
|
||||||
|
<Drawer
|
||||||
|
open={isOpen}
|
||||||
|
onOpenChange={(open) => {
|
||||||
|
if (!open) {
|
||||||
|
closeDialog()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DrawerContent>
|
||||||
|
<DrawerHeader>
|
||||||
|
<DrawerTitle className="hidden" />
|
||||||
|
<DrawerDescription className="hidden" />
|
||||||
|
</DrawerHeader>
|
||||||
|
<div className="p-4">
|
||||||
|
<ReportContent event={event} closeDialog={closeDialog} />
|
||||||
|
</div>
|
||||||
|
</DrawerContent>
|
||||||
|
</Drawer>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
open={isOpen}
|
||||||
|
onOpenChange={(open) => {
|
||||||
|
if (!open) {
|
||||||
|
closeDialog()
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle className="hidden" />
|
||||||
|
<DialogDescription className="hidden" />
|
||||||
|
</DialogHeader>
|
||||||
|
<ReportContent event={event} closeDialog={closeDialog} />
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function ReportContent({ event, closeDialog }: { event: NostrEvent; closeDialog: () => void }) {
|
||||||
|
const { t } = useTranslation()
|
||||||
|
const { pubkey, publish } = useNostr()
|
||||||
|
const [reason, setReason] = useState<string | null>(null)
|
||||||
|
const [reporting, setReporting] = useState(false)
|
||||||
|
|
||||||
|
const handleReport = async () => {
|
||||||
|
if (!reason || !pubkey) return
|
||||||
|
|
||||||
|
try {
|
||||||
|
setReporting(true)
|
||||||
|
const draftEvent = createReportDraftEvent(event, reason)
|
||||||
|
await publish(draftEvent)
|
||||||
|
toast.success(t('Successfully report'))
|
||||||
|
closeDialog()
|
||||||
|
} catch (error) {
|
||||||
|
toast.error(t('Failed to report') + ': ' + (error as Error).message)
|
||||||
|
} finally {
|
||||||
|
setReporting(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="w-full space-y-4">
|
||||||
|
<RadioGroup value={reason} onValueChange={setReason} className="space-y-2">
|
||||||
|
{['nudity', 'malware', 'profanity', 'illegal', 'spam', 'other'].map((item) => (
|
||||||
|
<div key={item} className="flex items-center space-x-2">
|
||||||
|
<RadioGroupItem value={item} id={item} />
|
||||||
|
<Label htmlFor={item} className="text-base">
|
||||||
|
{t(item)}
|
||||||
|
</Label>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</RadioGroup>
|
||||||
|
<Button
|
||||||
|
variant="destructive"
|
||||||
|
className="w-full"
|
||||||
|
disabled={!reason || reporting}
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation()
|
||||||
|
handleReport()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{reporting && <Loader className="animate-spin" />}
|
||||||
|
{t('Report')}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -5,11 +5,13 @@ import { useState } from 'react'
|
|||||||
import { DesktopMenu } from './DesktopMenu'
|
import { DesktopMenu } from './DesktopMenu'
|
||||||
import { MobileMenu } from './MobileMenu'
|
import { MobileMenu } from './MobileMenu'
|
||||||
import RawEventDialog from './RawEventDialog'
|
import RawEventDialog from './RawEventDialog'
|
||||||
|
import ReportDialog from './ReportDialog'
|
||||||
import { SubMenuAction, useMenuActions } from './useMenuActions'
|
import { SubMenuAction, useMenuActions } from './useMenuActions'
|
||||||
|
|
||||||
export default function NoteOptions({ event, className }: { event: Event; className?: string }) {
|
export default function NoteOptions({ event, className }: { event: Event; className?: string }) {
|
||||||
const { isSmallScreen } = useScreenSize()
|
const { isSmallScreen } = useScreenSize()
|
||||||
const [isRawEventDialogOpen, setIsRawEventDialogOpen] = useState(false)
|
const [isRawEventDialogOpen, setIsRawEventDialogOpen] = useState(false)
|
||||||
|
const [isReportDialogOpen, setIsReportDialogOpen] = useState(false)
|
||||||
const [isDrawerOpen, setIsDrawerOpen] = useState(false)
|
const [isDrawerOpen, setIsDrawerOpen] = useState(false)
|
||||||
const [showSubMenu, setShowSubMenu] = useState(false)
|
const [showSubMenu, setShowSubMenu] = useState(false)
|
||||||
const [activeSubMenu, setActiveSubMenu] = useState<SubMenuAction[]>([])
|
const [activeSubMenu, setActiveSubMenu] = useState<SubMenuAction[]>([])
|
||||||
@@ -35,6 +37,7 @@ export default function NoteOptions({ event, className }: { event: Event; classN
|
|||||||
closeDrawer,
|
closeDrawer,
|
||||||
showSubMenuActions,
|
showSubMenuActions,
|
||||||
setIsRawEventDialogOpen,
|
setIsRawEventDialogOpen,
|
||||||
|
setIsReportDialogOpen,
|
||||||
isSmallScreen
|
isSmallScreen
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -70,6 +73,11 @@ export default function NoteOptions({ event, className }: { event: Event; classN
|
|||||||
isOpen={isRawEventDialogOpen}
|
isOpen={isRawEventDialogOpen}
|
||||||
onClose={() => setIsRawEventDialogOpen(false)}
|
onClose={() => setIsRawEventDialogOpen(false)}
|
||||||
/>
|
/>
|
||||||
|
<ReportDialog
|
||||||
|
event={event}
|
||||||
|
isOpen={isReportDialogOpen}
|
||||||
|
closeDialog={() => setIsReportDialogOpen(false)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,18 @@ import { useFavoriteRelays } from '@/providers/FavoriteRelaysProvider'
|
|||||||
import { useMuteList } from '@/providers/MuteListProvider'
|
import { useMuteList } from '@/providers/MuteListProvider'
|
||||||
import { useNostr } from '@/providers/NostrProvider'
|
import { useNostr } from '@/providers/NostrProvider'
|
||||||
import client from '@/services/client.service'
|
import client from '@/services/client.service'
|
||||||
import { Bell, BellOff, Code, Copy, Link, Mail, SatelliteDish, Server, Trash2 } from 'lucide-react'
|
import {
|
||||||
|
Bell,
|
||||||
|
BellOff,
|
||||||
|
Code,
|
||||||
|
Copy,
|
||||||
|
Link,
|
||||||
|
Mail,
|
||||||
|
SatelliteDish,
|
||||||
|
Server,
|
||||||
|
Trash2,
|
||||||
|
TriangleAlert
|
||||||
|
} from 'lucide-react'
|
||||||
import { Event } from 'nostr-tools'
|
import { Event } from 'nostr-tools'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@@ -34,6 +45,7 @@ interface UseMenuActionsProps {
|
|||||||
closeDrawer: () => void
|
closeDrawer: () => void
|
||||||
showSubMenuActions: (subMenu: SubMenuAction[], title: string) => void
|
showSubMenuActions: (subMenu: SubMenuAction[], title: string) => void
|
||||||
setIsRawEventDialogOpen: (open: boolean) => void
|
setIsRawEventDialogOpen: (open: boolean) => void
|
||||||
|
setIsReportDialogOpen: (open: boolean) => void
|
||||||
isSmallScreen: boolean
|
isSmallScreen: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,6 +54,7 @@ export function useMenuActions({
|
|||||||
closeDrawer,
|
closeDrawer,
|
||||||
showSubMenuActions,
|
showSubMenuActions,
|
||||||
setIsRawEventDialogOpen,
|
setIsRawEventDialogOpen,
|
||||||
|
setIsReportDialogOpen,
|
||||||
isSmallScreen
|
isSmallScreen
|
||||||
}: UseMenuActionsProps) {
|
}: UseMenuActionsProps) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@@ -198,6 +211,19 @@ export function useMenuActions({
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pubkey && event.pubkey !== pubkey) {
|
||||||
|
actions.push({
|
||||||
|
icon: TriangleAlert,
|
||||||
|
label: t('Report'),
|
||||||
|
className: 'text-destructive focus:text-destructive',
|
||||||
|
onClick: () => {
|
||||||
|
closeDrawer()
|
||||||
|
setIsReportDialogOpen(true)
|
||||||
|
},
|
||||||
|
separator: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
if (pubkey && event.pubkey !== pubkey) {
|
if (pubkey && event.pubkey !== pubkey) {
|
||||||
if (isMuted) {
|
if (isMuted) {
|
||||||
actions.push({
|
actions.push({
|
||||||
|
|||||||
36
src/components/ui/radio-group.tsx
Normal file
36
src/components/ui/radio-group.tsx
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
import * as React from 'react'
|
||||||
|
import * as RadioGroupPrimitive from '@radix-ui/react-radio-group'
|
||||||
|
import { Circle } from 'lucide-react'
|
||||||
|
|
||||||
|
import { cn } from '@/lib/utils'
|
||||||
|
|
||||||
|
const RadioGroup = React.forwardRef<
|
||||||
|
React.ElementRef<typeof RadioGroupPrimitive.Root>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Root>
|
||||||
|
>(({ className, ...props }, ref) => {
|
||||||
|
return <RadioGroupPrimitive.Root className={cn('grid gap-2', className)} {...props} ref={ref} />
|
||||||
|
})
|
||||||
|
RadioGroup.displayName = RadioGroupPrimitive.Root.displayName
|
||||||
|
|
||||||
|
const RadioGroupItem = React.forwardRef<
|
||||||
|
React.ElementRef<typeof RadioGroupPrimitive.Item>,
|
||||||
|
React.ComponentPropsWithoutRef<typeof RadioGroupPrimitive.Item>
|
||||||
|
>(({ className, ...props }, ref) => {
|
||||||
|
return (
|
||||||
|
<RadioGroupPrimitive.Item
|
||||||
|
ref={ref}
|
||||||
|
className={cn(
|
||||||
|
'aspect-square h-4 w-4 rounded-full border focus:outline-none focus-visible:ring-1 focus-visible:ring-foreground disabled:cursor-not-allowed disabled:opacity-50',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<RadioGroupPrimitive.Indicator className="flex items-center justify-center">
|
||||||
|
<Circle className="h-2.5 w-2.5 fill-foreground" />
|
||||||
|
</RadioGroupPrimitive.Indicator>
|
||||||
|
</RadioGroupPrimitive.Item>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
RadioGroupItem.displayName = RadioGroupPrimitive.Item.displayName
|
||||||
|
|
||||||
|
export { RadioGroup, RadioGroupItem }
|
||||||
@@ -383,6 +383,15 @@ export default {
|
|||||||
'reposted your note': 'أعاد نشر ملاحظتك',
|
'reposted your note': 'أعاد نشر ملاحظتك',
|
||||||
'zapped your note': 'زاب ملاحظتك',
|
'zapped your note': 'زاب ملاحظتك',
|
||||||
'zapped you': 'زابك',
|
'zapped you': 'زابك',
|
||||||
'Mark as read': 'تعليم كمقروء'
|
'Mark as read': 'تعليم كمقروء',
|
||||||
|
Report: 'تبليغ',
|
||||||
|
'Successfully report': 'تم التبليغ بنجاح',
|
||||||
|
'Failed to report': 'فشل في التبليغ',
|
||||||
|
nudity: 'عُري',
|
||||||
|
malware: 'برامج ضارة',
|
||||||
|
profanity: 'ألفاظ نابية',
|
||||||
|
illegal: 'محتوى غير قانوني',
|
||||||
|
spam: 'رسائل مزعجة',
|
||||||
|
other: 'أخرى'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -392,6 +392,15 @@ export default {
|
|||||||
'reposted your note': 'hat Ihre Notiz geteilt',
|
'reposted your note': 'hat Ihre Notiz geteilt',
|
||||||
'zapped your note': 'hat Ihre Notiz gezappt',
|
'zapped your note': 'hat Ihre Notiz gezappt',
|
||||||
'zapped you': 'hat Sie gezappt',
|
'zapped you': 'hat Sie gezappt',
|
||||||
'Mark as read': 'Als gelesen markieren'
|
'Mark as read': 'Als gelesen markieren',
|
||||||
|
Report: 'Melden',
|
||||||
|
'Successfully report': 'Erfolgreich gemeldet',
|
||||||
|
'Failed to report': 'Meldung fehlgeschlagen',
|
||||||
|
nudity: 'Nacktheit',
|
||||||
|
malware: 'Schadsoftware',
|
||||||
|
profanity: 'Obszönität',
|
||||||
|
illegal: 'Illegaler Inhalt',
|
||||||
|
spam: 'Spam',
|
||||||
|
other: 'Sonstiges'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -382,6 +382,15 @@ export default {
|
|||||||
'reposted your note': 'reposted your note',
|
'reposted your note': 'reposted your note',
|
||||||
'zapped your note': 'zapped your note',
|
'zapped your note': 'zapped your note',
|
||||||
'zapped you': 'zapped you',
|
'zapped you': 'zapped you',
|
||||||
'Mark as read': 'Mark as read'
|
'Mark as read': 'Mark as read',
|
||||||
|
Report: 'Report',
|
||||||
|
'Successfully report': 'Successfully reported',
|
||||||
|
'Failed to report': 'Failed to report',
|
||||||
|
nudity: 'Nudity',
|
||||||
|
malware: 'Malware',
|
||||||
|
profanity: 'Profanity',
|
||||||
|
illegal: 'Illegal content',
|
||||||
|
spam: 'Spam',
|
||||||
|
other: 'Other'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -388,6 +388,15 @@ export default {
|
|||||||
'reposted your note': 'reposteó tu nota',
|
'reposted your note': 'reposteó tu nota',
|
||||||
'zapped your note': 'zappeó tu nota',
|
'zapped your note': 'zappeó tu nota',
|
||||||
'zapped you': 'te zappeó',
|
'zapped you': 'te zappeó',
|
||||||
'Mark as read': 'Marcar como leído'
|
'Mark as read': 'Marcar como leído',
|
||||||
|
Report: 'Reportar',
|
||||||
|
'Successfully report': 'Reporte exitoso',
|
||||||
|
'Failed to report': 'Fallo al reportar',
|
||||||
|
nudity: 'Desnudez',
|
||||||
|
malware: 'Software malicioso',
|
||||||
|
profanity: 'Blasfemia',
|
||||||
|
illegal: 'Contenido ilegal',
|
||||||
|
spam: 'Spam',
|
||||||
|
other: 'Otro'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -384,6 +384,15 @@ export default {
|
|||||||
'reposted your note': 'یادداشت شما را بازنشر کرد',
|
'reposted your note': 'یادداشت شما را بازنشر کرد',
|
||||||
'zapped your note': 'یادداشت شما را زپ کرد',
|
'zapped your note': 'یادداشت شما را زپ کرد',
|
||||||
'zapped you': 'شما را زپ کرد',
|
'zapped you': 'شما را زپ کرد',
|
||||||
'Mark as read': 'علامتگذاری به عنوان خوانده شده'
|
'Mark as read': 'علامتگذاری به عنوان خوانده شده',
|
||||||
|
Report: 'گزارش',
|
||||||
|
'Successfully report': 'گزارش با موفقیت ارسال شد',
|
||||||
|
'Failed to report': 'ارسال گزارش ناموفق بود',
|
||||||
|
nudity: 'برهنگی',
|
||||||
|
malware: 'بدافزار',
|
||||||
|
profanity: 'فحاشی',
|
||||||
|
illegal: 'محتوای غیرقانونی',
|
||||||
|
spam: 'اسپم',
|
||||||
|
other: 'سایر'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -392,6 +392,15 @@ export default {
|
|||||||
'reposted your note': 'a repartagé votre note',
|
'reposted your note': 'a repartagé votre note',
|
||||||
'zapped your note': 'a zappé votre note',
|
'zapped your note': 'a zappé votre note',
|
||||||
'zapped you': 'vous a zappé',
|
'zapped you': 'vous a zappé',
|
||||||
'Mark as read': 'Marquer comme lu'
|
'Mark as read': 'Marquer comme lu',
|
||||||
|
Report: 'Signaler',
|
||||||
|
'Successfully report': 'Signalement réussi',
|
||||||
|
'Failed to report': 'Échec du signalement',
|
||||||
|
nudity: 'Nudité',
|
||||||
|
malware: 'Logiciel malveillant',
|
||||||
|
profanity: 'Blasphème',
|
||||||
|
illegal: 'Contenu illégal',
|
||||||
|
spam: 'Spam',
|
||||||
|
other: 'Autre'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -388,6 +388,15 @@ export default {
|
|||||||
'reposted your note': 'ha ricondiviso la tua nota',
|
'reposted your note': 'ha ricondiviso la tua nota',
|
||||||
'zapped your note': 'ha zappato la tua nota',
|
'zapped your note': 'ha zappato la tua nota',
|
||||||
'zapped you': 'ti ha zappato',
|
'zapped you': 'ti ha zappato',
|
||||||
'Mark as read': 'Segna come letto'
|
'Mark as read': 'Segna come letto',
|
||||||
|
Report: 'Segnala',
|
||||||
|
'Successfully report': 'Segnalazione riuscita',
|
||||||
|
'Failed to report': 'Segnalazione fallita',
|
||||||
|
nudity: 'Nudità',
|
||||||
|
malware: 'Malware',
|
||||||
|
profanity: 'Blasfemia',
|
||||||
|
illegal: 'Contenuto illegale',
|
||||||
|
spam: 'Spam',
|
||||||
|
other: 'Altro'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -385,6 +385,15 @@ export default {
|
|||||||
'reposted your note': 'あなたのノートをリポストしました',
|
'reposted your note': 'あなたのノートをリポストしました',
|
||||||
'zapped your note': 'あなたのノートにザップしました',
|
'zapped your note': 'あなたのノートにザップしました',
|
||||||
'zapped you': 'あなたにザップしました',
|
'zapped you': 'あなたにザップしました',
|
||||||
'Mark as read': '既読にする'
|
'Mark as read': '既読にする',
|
||||||
|
Report: '報告',
|
||||||
|
'Successfully report': '報告が成功しました',
|
||||||
|
'Failed to report': '報告に失敗しました',
|
||||||
|
nudity: 'ヌード',
|
||||||
|
malware: 'マルウェア',
|
||||||
|
profanity: '冒涜的な内容',
|
||||||
|
illegal: '違法コンテンツ',
|
||||||
|
spam: 'スパム',
|
||||||
|
other: 'その他'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -385,6 +385,15 @@ export default {
|
|||||||
'reposted your note': '당신의 노트를 리포스트했습니다',
|
'reposted your note': '당신의 노트를 리포스트했습니다',
|
||||||
'zapped your note': '당신의 노트를 잽했습니다',
|
'zapped your note': '당신의 노트를 잽했습니다',
|
||||||
'zapped you': '당신을 잽했습니다',
|
'zapped you': '당신을 잽했습니다',
|
||||||
'Mark as read': '읽음으로 표시'
|
'Mark as read': '읽음으로 표시',
|
||||||
|
Report: '신고',
|
||||||
|
'Successfully report': '신고가 성공적으로 완료되었습니다',
|
||||||
|
'Failed to report': '신고에 실패했습니다',
|
||||||
|
nudity: '음란물',
|
||||||
|
malware: '악성 소프트웨어',
|
||||||
|
profanity: '욕설',
|
||||||
|
illegal: '불법 콘텐츠',
|
||||||
|
spam: '스팸',
|
||||||
|
other: '기타'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -389,6 +389,15 @@ export default {
|
|||||||
'reposted your note': 'przepostował twoją notatkę',
|
'reposted your note': 'przepostował twoją notatkę',
|
||||||
'zapped your note': 'zappował twoją notatkę',
|
'zapped your note': 'zappował twoją notatkę',
|
||||||
'zapped you': 'zappował cię',
|
'zapped you': 'zappował cię',
|
||||||
'Mark as read': 'Oznacz jako przeczytane'
|
'Mark as read': 'Oznacz jako przeczytane',
|
||||||
|
Report: 'Zgłoś',
|
||||||
|
'Successfully report': 'Pomyślnie zgłoszono',
|
||||||
|
'Failed to report': 'Nie udało się zgłosić',
|
||||||
|
nudity: 'Nagość',
|
||||||
|
malware: 'Złośliwe oprogramowanie',
|
||||||
|
profanity: 'Wulgaryzmy',
|
||||||
|
illegal: 'Nielegalna treść',
|
||||||
|
spam: 'Spam',
|
||||||
|
other: 'Inne'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -385,6 +385,15 @@ export default {
|
|||||||
'reposted your note': 'republicou sua nota',
|
'reposted your note': 'republicou sua nota',
|
||||||
'zapped your note': 'zappeou sua nota',
|
'zapped your note': 'zappeou sua nota',
|
||||||
'zapped you': 'zappeou você',
|
'zapped you': 'zappeou você',
|
||||||
'Mark as read': 'Marcar como lida'
|
'Mark as read': 'Marcar como lida',
|
||||||
|
Report: 'Denunciar',
|
||||||
|
'Successfully report': 'Denúncia enviada com sucesso',
|
||||||
|
'Failed to report': 'Falha ao enviar denúncia',
|
||||||
|
nudity: 'Nudez',
|
||||||
|
malware: 'Malware',
|
||||||
|
profanity: 'Blasfêmia',
|
||||||
|
illegal: 'Conteúdo ilegal',
|
||||||
|
spam: 'Spam',
|
||||||
|
other: 'Outro'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -388,6 +388,15 @@ export default {
|
|||||||
'reposted your note': 'republicou a sua nota',
|
'reposted your note': 'republicou a sua nota',
|
||||||
'zapped your note': 'zappeou a sua nota',
|
'zapped your note': 'zappeou a sua nota',
|
||||||
'zapped you': 'zappeou-o',
|
'zapped you': 'zappeou-o',
|
||||||
'Mark as read': 'Marcar como lida'
|
'Mark as read': 'Marcar como lida',
|
||||||
|
Report: 'Denunciar',
|
||||||
|
'Successfully report': 'Denúncia enviada com sucesso',
|
||||||
|
'Failed to report': 'Falha ao enviar denúncia',
|
||||||
|
nudity: 'Nudez',
|
||||||
|
malware: 'Malware',
|
||||||
|
profanity: 'Blasfémia',
|
||||||
|
illegal: 'Conteúdo ilegal',
|
||||||
|
spam: 'Spam',
|
||||||
|
other: 'Outro'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -389,6 +389,15 @@ export default {
|
|||||||
'reposted your note': 'репостнул вашу заметку',
|
'reposted your note': 'репостнул вашу заметку',
|
||||||
'zapped your note': 'заппил вашу заметку',
|
'zapped your note': 'заппил вашу заметку',
|
||||||
'zapped you': 'заппил вас',
|
'zapped you': 'заппил вас',
|
||||||
'Mark as read': 'Отметить как прочитанное'
|
'Mark as read': 'Отметить как прочитанное',
|
||||||
|
Report: 'Пожаловаться',
|
||||||
|
'Successfully report': 'Жалоба успешно отправлена',
|
||||||
|
'Failed to report': 'Не удалось отправить жалобу',
|
||||||
|
nudity: 'Обнаженность',
|
||||||
|
malware: 'Вредоносное ПО',
|
||||||
|
profanity: 'Ненормативная лексика',
|
||||||
|
illegal: 'Незаконный контент',
|
||||||
|
spam: 'Спам',
|
||||||
|
other: 'Другое'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -380,6 +380,15 @@ export default {
|
|||||||
'reposted your note': 'ได้รีโพสต์โน้ตของคุณ',
|
'reposted your note': 'ได้รีโพสต์โน้ตของคุณ',
|
||||||
'zapped your note': 'ได้แซปโน้ตของคุณ',
|
'zapped your note': 'ได้แซปโน้ตของคุณ',
|
||||||
'zapped you': 'ได้แซปคุณ',
|
'zapped you': 'ได้แซปคุณ',
|
||||||
'Mark as read': 'ทำเครื่องหมายว่าอ่านแล้ว'
|
'Mark as read': 'ทำเครื่องหมายว่าอ่านแล้ว',
|
||||||
|
Report: 'รายงาน',
|
||||||
|
'Successfully report': 'รายงานสำเร็จ',
|
||||||
|
'Failed to report': 'การรายงานล้มเหลว',
|
||||||
|
nudity: 'ภาพลามก',
|
||||||
|
malware: 'มัลแวร์',
|
||||||
|
profanity: 'คำหยาบคาย',
|
||||||
|
illegal: 'เนื้อหาผิดกฎหมาย',
|
||||||
|
spam: 'สแปม',
|
||||||
|
other: 'อื่นๆ'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -378,6 +378,15 @@ export default {
|
|||||||
'reposted your note': '转发了您的笔记',
|
'reposted your note': '转发了您的笔记',
|
||||||
'zapped your note': '打闪了您的笔记',
|
'zapped your note': '打闪了您的笔记',
|
||||||
'zapped you': '给您打闪',
|
'zapped you': '给您打闪',
|
||||||
'Mark as read': '标记为已读'
|
'Mark as read': '标记为已读',
|
||||||
|
Report: '举报',
|
||||||
|
'Successfully report': '举报成功',
|
||||||
|
'Failed to report': '举报失败',
|
||||||
|
nudity: '色情内容',
|
||||||
|
malware: '恶意软件',
|
||||||
|
profanity: '亵渎言论',
|
||||||
|
illegal: '违法内容',
|
||||||
|
spam: '垃圾信息',
|
||||||
|
other: '其他'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -432,6 +432,26 @@ export function createDeletionRequestDraftEvent(event: Event): TDraftEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createReportDraftEvent(event: Event, reason: string): TDraftEvent {
|
||||||
|
const tags: string[][] = []
|
||||||
|
if (event.kind === kinds.Metadata) {
|
||||||
|
tags.push(['p', event.pubkey, reason])
|
||||||
|
} else {
|
||||||
|
tags.push(['p', event.pubkey])
|
||||||
|
tags.push(['e', event.id, reason])
|
||||||
|
if (isReplaceableEvent(event.kind)) {
|
||||||
|
tags.push(['a', getReplaceableCoordinateFromEvent(event), reason])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
kind: kinds.Report,
|
||||||
|
content: '',
|
||||||
|
tags,
|
||||||
|
created_at: dayjs().unix()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function generateImetaTags(imageUrls: string[]) {
|
function generateImetaTags(imageUrls: string[]) {
|
||||||
return imageUrls
|
return imageUrls
|
||||||
.map((imageUrl) => {
|
.map((imageUrl) => {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import {
|
|||||||
} from '@/lib/event'
|
} from '@/lib/event'
|
||||||
import { getProfileFromEvent, getRelayListFromEvent } from '@/lib/event-metadata'
|
import { getProfileFromEvent, getRelayListFromEvent } from '@/lib/event-metadata'
|
||||||
import { formatPubkey, isValidPubkey, pubkeyToNpub, userIdToPubkey } from '@/lib/pubkey'
|
import { formatPubkey, isValidPubkey, pubkeyToNpub, userIdToPubkey } from '@/lib/pubkey'
|
||||||
import { getPubkeysFromPTags, getServersFromServerTags } from '@/lib/tag'
|
import { getPubkeysFromPTags, getServersFromServerTags, tagNameEquals } from '@/lib/tag'
|
||||||
import { isLocalNetworkUrl, isWebsocketUrl, normalizeUrl } from '@/lib/url'
|
import { isLocalNetworkUrl, isWebsocketUrl, normalizeUrl } from '@/lib/url'
|
||||||
import { isSafari } from '@/lib/utils'
|
import { isSafari } from '@/lib/utils'
|
||||||
import { ISigner, TProfile, TPublishOptions, TRelayList, TSubRequestFilter } from '@/types'
|
import { ISigner, TProfile, TPublishOptions, TRelayList, TSubRequestFilter } from '@/types'
|
||||||
@@ -87,6 +87,13 @@ class ClientService extends EventTarget {
|
|||||||
event: NEvent,
|
event: NEvent,
|
||||||
{ specifiedRelayUrls, additionalRelayUrls }: TPublishOptions = {}
|
{ specifiedRelayUrls, additionalRelayUrls }: TPublishOptions = {}
|
||||||
) {
|
) {
|
||||||
|
if (event.kind === kinds.Report) {
|
||||||
|
const targetEventId = event.tags.find(tagNameEquals('e'))?.[1]
|
||||||
|
if (targetEventId) {
|
||||||
|
return this.getSeenEventRelayUrls(targetEventId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const _additionalRelayUrls: string[] = additionalRelayUrls ?? []
|
const _additionalRelayUrls: string[] = additionalRelayUrls ?? []
|
||||||
if (!specifiedRelayUrls?.length && ![kinds.Contacts, kinds.Mutelist].includes(event.kind)) {
|
if (!specifiedRelayUrls?.length && ![kinds.Contacts, kinds.Mutelist].includes(event.kind)) {
|
||||||
const mentions: string[] = []
|
const mentions: string[] = []
|
||||||
|
|||||||
Reference in New Issue
Block a user