forked from MapComplete/MapComplete
Feature(reviews): fix #2457, add report functionality with reason
This commit is contained in:
parent
dc62db7dcf
commit
7ce320075d
3 changed files with 89 additions and 10 deletions
|
|
@ -817,6 +817,9 @@
|
||||||
"question_opinion": "How was your experience?",
|
"question_opinion": "How was your experience?",
|
||||||
"rate": "Rate {n} stars",
|
"rate": "Rate {n} stars",
|
||||||
"rated": "Rated {n} stars",
|
"rated": "Rated {n} stars",
|
||||||
|
"reportReason": "Why should this report be reported?",
|
||||||
|
"reportReview": "Report this review as inappropriate",
|
||||||
|
"reportReviewTitle": "Report this review as inappropriate?",
|
||||||
"reviewPlaceholder": "Describe your experience…",
|
"reviewPlaceholder": "Describe your experience…",
|
||||||
"reviewing_as": "Reviewing as {nickname}",
|
"reviewing_as": "Reviewing as {nickname}",
|
||||||
"reviewing_as_anonymous": "Reviewing as anonymous",
|
"reviewing_as_anonymous": "Reviewing as anonymous",
|
||||||
|
|
@ -942,4 +945,4 @@
|
||||||
"startsWithQ": "A wikidata identifier starts with Q and is followed by a number"
|
"startsWithQ": "A wikidata identifier starts with Q and is followed by a number"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -452,9 +452,14 @@ export default class FeatureReviews {
|
||||||
|
|
||||||
public async deleteReview(review: Review & {signature: string}){
|
public async deleteReview(review: Review & {signature: string}){
|
||||||
await MangroveReviews.deleteReview(await this._identity.getKeypair(), review)
|
await MangroveReviews.deleteReview(await this._identity.getKeypair(), review)
|
||||||
|
this.removeReviewLocally(review)
|
||||||
|
}
|
||||||
|
|
||||||
|
public removeReviewLocally(review: Review){
|
||||||
this._reviews.set(
|
this._reviews.set(
|
||||||
this._reviews.data.filter(r => r !== review)
|
this._reviews.data.filter(r => r !== review)
|
||||||
)
|
)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { MangroveReviews, Review } from "mangrove-reviews-typescript"
|
import { MangroveReviews, Review } from "mangrove-reviews-typescript"
|
||||||
|
|
||||||
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"
|
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import StarsBar from "./StarsBar.svelte"
|
import StarsBar from "./StarsBar.svelte"
|
||||||
import Translations from "../i18n/Translations"
|
import Translations from "../i18n/Translations"
|
||||||
|
|
@ -7,7 +8,6 @@
|
||||||
import { ariaLabel } from "../../Utils/ariaLabel"
|
import { ariaLabel } from "../../Utils/ariaLabel"
|
||||||
import ThemeViewState from "../../Models/ThemeViewState"
|
import ThemeViewState from "../../Models/ThemeViewState"
|
||||||
import Markdown from "../Base/Markdown.svelte"
|
import Markdown from "../Base/Markdown.svelte"
|
||||||
import AccordionSingle from "../Flowbite/AccordionSingle.svelte"
|
|
||||||
import AttributedImage from "../Image/AttributedImage.svelte"
|
import AttributedImage from "../Image/AttributedImage.svelte"
|
||||||
import DotMenu from "../Base/DotMenu.svelte"
|
import DotMenu from "../Base/DotMenu.svelte"
|
||||||
import { TrashIcon } from "@rgossiaux/svelte-heroicons/solid"
|
import { TrashIcon } from "@rgossiaux/svelte-heroicons/solid"
|
||||||
|
|
@ -17,7 +17,11 @@
|
||||||
import ReviewForm from "./ReviewForm.svelte"
|
import ReviewForm from "./ReviewForm.svelte"
|
||||||
import type { Feature } from "geojson"
|
import type { Feature } from "geojson"
|
||||||
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
import LayerConfig from "../../Models/ThemeConfig/LayerConfig"
|
||||||
import FeatureReviews from "../../Logic/Web/MangroveReviews"
|
import FeatureReviews, { MangroveIdentity } from "../../Logic/Web/MangroveReviews"
|
||||||
|
import ShieldExclamation from "@babeard/svelte-heroicons/solid/ShieldExclamation"
|
||||||
|
import Delete_icon from "../../assets/svg/Delete_icon.svelte"
|
||||||
|
import ValidatedInput from "../InputElement/ValidatedInput.svelte"
|
||||||
|
|
||||||
|
|
||||||
export let state: ThemeViewState = undefined
|
export let state: ThemeViewState = undefined
|
||||||
export let tags: UIEventSource<Record<string, string>> = undefined
|
export let tags: UIEventSource<Record<string, string>> = undefined
|
||||||
|
|
@ -53,21 +57,39 @@
|
||||||
|
|
||||||
let isTesting = state?.featureSwitchIsTesting ?? new ImmutableStore(false)
|
let isTesting = state?.featureSwitchIsTesting ?? new ImmutableStore(false)
|
||||||
|
|
||||||
function report() {
|
async function report() {
|
||||||
MangroveReviews.reportAbuseReview(identity, review, "This review was reported by a MapComplete user")
|
let reason = reportReason.data
|
||||||
|
if (!reason) {
|
||||||
|
reason = "This review was reported by a MapComplete user"
|
||||||
|
}
|
||||||
|
const identity: CryptoKeyPair = await state?.userRelatedState?.mangroveIdentity.getKeypair()
|
||||||
|
if (!isTesting.data) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
await MangroveReviews.reportAbuseReview(identity, review, reason)
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Could not report review due to", e)
|
||||||
|
await state.reportError(e)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log("Not actually reporting, test mode")
|
||||||
|
}
|
||||||
|
showReport.set(false)
|
||||||
|
reviews.removeReviewLocally(review)
|
||||||
}
|
}
|
||||||
|
|
||||||
let deleted = new UIEventSource(false)
|
let deleted = new UIEventSource(false)
|
||||||
|
|
||||||
async function deleteR() {
|
async function deleteR() {
|
||||||
const identity: MangroveIdentity = await state?.userRelatedState?.mangroveIdentity.getKeypair()
|
const identity: CryptoKeyPair = await state?.userRelatedState?.mangroveIdentity.getKeypair()
|
||||||
console.log("Deleting review...", identity)
|
console.log("Deleting review...", identity)
|
||||||
if (!isTesting.data) {
|
if (!isTesting.data) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
reviews.deleteReview(review)
|
await reviews.deleteReview(review)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("Could not delete review... ", e)
|
console.log("Could not delete review... ", e)
|
||||||
|
await state.reportError(e)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log("Not really deleting the review, testing")
|
console.log("Not really deleting the review, testing")
|
||||||
|
|
@ -76,8 +98,10 @@
|
||||||
deleted.setData(true)
|
deleted.setData(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let reportReason = new UIEventSource("")
|
||||||
let showDelete = new UIEventSource(false)
|
let showDelete = new UIEventSource(false)
|
||||||
let showEdit = new UIEventSource(false)
|
let showEdit = new UIEventSource(false)
|
||||||
|
let showReport = new UIEventSource(false)
|
||||||
let isDebugging = state?.featureSwitches?.featureSwitchIsDebugging
|
let isDebugging = state?.featureSwitches?.featureSwitchIsDebugging
|
||||||
const t = Translations.t.reviews
|
const t = Translations.t.reviews
|
||||||
</script>
|
</script>
|
||||||
|
|
@ -87,20 +111,62 @@
|
||||||
<Tr t={t.deleteTitle} />
|
<Tr t={t.deleteTitle} />
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
|
|
||||||
|
<div class="flex gap-x-4 items-center m-8">
|
||||||
|
<Delete_icon class="w-16" />
|
||||||
|
<div class="p-4 low-interaction border-interactive">
|
||||||
|
<StarsBar starSize="w-4 h-4 md:w-6 md:h-6" readonly={true} score={review.rating} />
|
||||||
|
<div class="disable-links">
|
||||||
|
<Markdown src={review.opinion} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<Tr t={t.deleteText} />
|
<Tr t={t.deleteText} />
|
||||||
|
|
||||||
<NextButton clss="primary" on:click={() => deleteR()}>
|
<NextButton clss="primary float-right" on:click={() => deleteR()}>
|
||||||
<TrashIcon class="w-12 text-red-600" />
|
<TrashIcon class="w-12 text-red-600" />
|
||||||
<Tr t={t.deleteConfirm} />
|
<Tr t={t.deleteConfirm} />
|
||||||
</NextButton>
|
</NextButton>
|
||||||
</Popup>
|
</Popup>
|
||||||
|
|
||||||
|
|
||||||
|
<Popup shown={showReport}>
|
||||||
|
<svelte:fragment slot="header">
|
||||||
|
<Tr t={t.reportReviewTitle} />
|
||||||
|
</svelte:fragment>
|
||||||
|
|
||||||
|
<div class="flex gap-x-4 items-center m-8">
|
||||||
|
<ShieldExclamation class="w-16" />
|
||||||
|
<div class="p-4 low-interaction border-interactive">
|
||||||
|
<StarsBar starSize="w-4 h-4 md:w-6 md:h-6" readonly={true} score={review.rating} />
|
||||||
|
<div class="disable-links">
|
||||||
|
<Markdown src={review.opinion} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<h3>
|
||||||
|
<Tr t={t.reportReason} />
|
||||||
|
</h3>
|
||||||
|
<div class="w-full">
|
||||||
|
|
||||||
|
<ValidatedInput type="text" value={reportReason} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Tr t={t.deleteText} />
|
||||||
|
|
||||||
|
<NextButton clss="primary float-right" on:click={() => {report()}}>
|
||||||
|
<TrashIcon class="w-12 text-red-600" />
|
||||||
|
<Tr t={t.reportReview} />
|
||||||
|
</NextButton>
|
||||||
|
</Popup>
|
||||||
|
|
||||||
<Popup shown={showEdit}>
|
<Popup shown={showEdit}>
|
||||||
<svelte:fragment slot="header">
|
<svelte:fragment slot="header">
|
||||||
<Tr t={t.edit} />
|
<Tr t={t.edit} />
|
||||||
</svelte:fragment>
|
</svelte:fragment>
|
||||||
|
|
||||||
<ReviewForm {state} editReview={review} {reviews} />
|
<ReviewForm {tags} {feature} {layer} {state} editReview={review} {reviews} />
|
||||||
|
|
||||||
</Popup>
|
</Popup>
|
||||||
|
|
||||||
|
|
@ -149,7 +215,7 @@
|
||||||
{#if review.signature}
|
{#if review.signature}
|
||||||
<div class="self-start">
|
<div class="self-start">
|
||||||
<DotMenu>
|
<DotMenu>
|
||||||
{#if byLoggedInUser}
|
{#if $byLoggedInUser}
|
||||||
<button on:click={() => showEdit.set(true)}>
|
<button on:click={() => showEdit.set(true)}>
|
||||||
<PencilIcon />
|
<PencilIcon />
|
||||||
<Tr t={t.edit} />
|
<Tr t={t.edit} />
|
||||||
|
|
@ -158,6 +224,11 @@
|
||||||
<TrashIcon />
|
<TrashIcon />
|
||||||
<Tr t={t.delete} />
|
<Tr t={t.delete} />
|
||||||
</button>
|
</button>
|
||||||
|
{:else}
|
||||||
|
<button on:click={() => showReport.set(true)}>
|
||||||
|
<ShieldExclamation />
|
||||||
|
<Tr t={t.reportReview} />
|
||||||
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
</DotMenu>
|
</DotMenu>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue