forked from MapComplete/MapComplete
UI(Reviews): move 'loading allowed' to FeatureReviews
This commit is contained in:
parent
ce3a049d9d
commit
d662bc2707
10 changed files with 105 additions and 63 deletions
|
@ -810,9 +810,12 @@
|
||||||
"deleteConfirm": "Permantently delete this review",
|
"deleteConfirm": "Permantently delete this review",
|
||||||
"deleteText": "This cannot be undone",
|
"deleteText": "This cannot be undone",
|
||||||
"deleteTitle": "Delete this review?",
|
"deleteTitle": "Delete this review?",
|
||||||
|
"disabledForPrivacy": "Reviews are disabled due to your privacy settings.",
|
||||||
"edit": "Edit review",
|
"edit": "Edit review",
|
||||||
|
"editPrivacySettings": "Edit your privacy settings",
|
||||||
"i_am_affiliated": "I am affiliated with this object",
|
"i_am_affiliated": "I am affiliated with this object",
|
||||||
"i_am_affiliated_explanation": "Check if you are an owner, creator, employee, …",
|
"i_am_affiliated_explanation": "Check if you are an owner, creator, employee, …",
|
||||||
|
"loadOnce": "Load reviews once",
|
||||||
"no_reviews_yet": "There are no reviews yet. Be the first one!",
|
"no_reviews_yet": "There are no reviews yet. Be the first one!",
|
||||||
"non_place_review": "One review is not about a place and is not shown here.",
|
"non_place_review": "One review is not about a place and is not shown here.",
|
||||||
"non_place_reviews": "{n} reviews are not about a place and are not shown here.",
|
"non_place_reviews": "{n} reviews are not about a place and are not shown here.",
|
||||||
|
|
|
@ -369,7 +369,7 @@ export default class UserRelatedState {
|
||||||
|
|
||||||
private static initUserSettingsState(): LayerConfig {
|
private static initUserSettingsState(): LayerConfig {
|
||||||
try {
|
try {
|
||||||
return new LayerConfig(<LayerConfigJson>usersettings, "userinformationpanel")
|
return new LayerConfig(<LayerConfigJson><any>usersettings, "userinformationpanel")
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
|
@ -655,7 +655,7 @@ export default class UserRelatedState {
|
||||||
|
|
||||||
for (const key in featureSwitches) {
|
for (const key in featureSwitches) {
|
||||||
if (featureSwitches[key].addCallbackAndRun) {
|
if (featureSwitches[key].addCallbackAndRun) {
|
||||||
featureSwitches[key].addCallbackAndRun((v) => {
|
featureSwitches[key].addCallbackAndRun((v: string) => {
|
||||||
const oldV = amendedPrefs.data["__" + key]
|
const oldV = amendedPrefs.data["__" + key]
|
||||||
if (oldV === v) {
|
if (oldV === v) {
|
||||||
return
|
return
|
||||||
|
|
|
@ -4,6 +4,17 @@ import { Utils } from "../../Utils"
|
||||||
import { Feature, Position } from "geojson"
|
import { Feature, Position } from "geojson"
|
||||||
import { GeoOperations } from "../GeoOperations"
|
import { GeoOperations } from "../GeoOperations"
|
||||||
import { SpecialVisualizationState } from "../../UI/SpecialVisualization"
|
import { SpecialVisualizationState } from "../../UI/SpecialVisualization"
|
||||||
|
import { WithUserRelatedState } from "../../Models/ThemeViewState/WithUserRelatedState"
|
||||||
|
|
||||||
|
export interface ReviewCollection {
|
||||||
|
readonly subjectUri?: Store<string>
|
||||||
|
readonly loadingAllowed: UIEventSource<boolean>
|
||||||
|
removeReviewLocally(review: Review): void
|
||||||
|
|
||||||
|
deleteReview(review: Review & { signature: string }): Promise<void>
|
||||||
|
|
||||||
|
createReview(review: Omit<Review, "sub">): Promise<void>
|
||||||
|
}
|
||||||
|
|
||||||
export class MangroveIdentity {
|
export class MangroveIdentity {
|
||||||
private readonly keypair: UIEventSource<CryptoKeyPair> = new UIEventSource<CryptoKeyPair>(
|
private readonly keypair: UIEventSource<CryptoKeyPair> = new UIEventSource<CryptoKeyPair>(
|
||||||
|
@ -134,12 +145,13 @@ export class MangroveIdentity {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tracks all reviews of a given feature, allows to create a new review (and inserts this into the list)
|
* Tracks all reviews of a given feature, allows to create a new review (and inserts this into the list)
|
||||||
*
|
*
|
||||||
* This object will start fetching the reviews as soon as it is constructed
|
* This object will start fetching the reviews as soon as it is constructed
|
||||||
*/
|
*/
|
||||||
export default class FeatureReviews {
|
export default class FeatureReviews implements ReviewCollection {
|
||||||
/**
|
/**
|
||||||
* See https://gitlab.com/open-reviews/mangrove/-/blob/master/servers/reviewer/src/review.rs#L269 and https://source.mapcomplete.org/MapComplete/MapComplete/issues/1775
|
* See https://gitlab.com/open-reviews/mangrove/-/blob/master/servers/reviewer/src/review.rs#L269 and https://source.mapcomplete.org/MapComplete/MapComplete/issues/1775
|
||||||
*/
|
*/
|
||||||
|
@ -147,10 +159,11 @@ export default class FeatureReviews {
|
||||||
private static readonly _featureReviewsCache: Record<string, FeatureReviews> = {}
|
private static readonly _featureReviewsCache: Record<string, FeatureReviews> = {}
|
||||||
public readonly subjectUri: Store<string>
|
public readonly subjectUri: Store<string>
|
||||||
public readonly average: Store<number | null>
|
public readonly average: Store<number | null>
|
||||||
|
public readonly loadingAllowed: UIEventSource<boolean>
|
||||||
private readonly _reviews: UIEventSource<
|
private readonly _reviews: UIEventSource<
|
||||||
(Review & { kid: string; signature: string; madeByLoggedInUser: Store<boolean> })[]
|
(Review & { kid: string; signature: string; madeByLoggedInUser: Store<boolean> })[]
|
||||||
> = new UIEventSource(undefined)
|
> = new UIEventSource(undefined)
|
||||||
public readonly reviews: Store<(Review & { signature: string, madeByLoggedInUser: Store<boolean> })[]> =
|
public readonly reviews: Store<(Review & { kid: string, signature: string, madeByLoggedInUser: Store<boolean> })[]> =
|
||||||
this._reviews
|
this._reviews
|
||||||
private readonly _lat: number
|
private readonly _lat: number
|
||||||
private readonly _lon: number
|
private readonly _lon: number
|
||||||
|
@ -158,23 +171,21 @@ export default class FeatureReviews {
|
||||||
private readonly _name: Store<string>
|
private readonly _name: Store<string>
|
||||||
private readonly _identity: MangroveIdentity
|
private readonly _identity: MangroveIdentity
|
||||||
private readonly _testmode: Store<boolean>
|
private readonly _testmode: Store<boolean>
|
||||||
public readonly loadingAllowed: UIEventSource<boolean | null>
|
|
||||||
private readonly _reportError: (msg: string, extra: string) => Promise<void>
|
private readonly _reportError: (msg: string, extra: string) => Promise<void>
|
||||||
|
|
||||||
private constructor(
|
private constructor(
|
||||||
feature: Feature,
|
feature: Feature,
|
||||||
tagsSource: UIEventSource<Record<string, string>>,
|
tagsSource: UIEventSource<Record<string, string>>,
|
||||||
mangroveIdentity: MangroveIdentity,
|
mangroveIdentity: MangroveIdentity,
|
||||||
|
loadingAllowed?: UIEventSource<boolean>,
|
||||||
options?: Readonly<{
|
options?: Readonly<{
|
||||||
nameKey?: "name" | string
|
nameKey?: "name" | string
|
||||||
fallbackName?: string
|
fallbackName?: string
|
||||||
uncertaintyRadius?: number
|
uncertaintyRadius?: number,
|
||||||
}>,
|
}>,
|
||||||
testmode?: Store<boolean>,
|
testmode?: Store<boolean>,
|
||||||
loadingAllowed?: UIEventSource<boolean | null>,
|
|
||||||
reportError?: (msg: string, extra: string) => Promise<void>
|
reportError?: (msg: string, extra: string) => Promise<void>
|
||||||
) {
|
) {
|
||||||
this.loadingAllowed = loadingAllowed
|
|
||||||
this._reportError = reportError
|
this._reportError = reportError
|
||||||
const centerLonLat = GeoOperations.centerpointCoordinates(feature)
|
const centerLonLat = GeoOperations.centerpointCoordinates(feature)
|
||||||
;[this._lon, this._lat] = centerLonLat
|
;[this._lon, this._lat] = centerLonLat
|
||||||
|
@ -221,14 +232,17 @@ export default class FeatureReviews {
|
||||||
})
|
})
|
||||||
|
|
||||||
this.subjectUri = this.ConstructSubjectUri()
|
this.subjectUri = this.ConstructSubjectUri()
|
||||||
|
this.loadingAllowed = loadingAllowed
|
||||||
this.subjectUri.mapD(
|
this.subjectUri.mapD(
|
||||||
async (sub) => {
|
async (sub) => {
|
||||||
|
if (!loadingAllowed.data) {
|
||||||
|
return
|
||||||
|
}
|
||||||
const reviews = await MangroveReviews.getReviews({ sub })
|
const reviews = await MangroveReviews.getReviews({ sub })
|
||||||
console.debug("Got reviews for", feature, reviews, sub)
|
console.debug("Got reviews for", feature, reviews, sub)
|
||||||
this.addReviews(reviews.reviews, this._name.data)
|
this.addReviews(reviews.reviews, this._name.data)
|
||||||
},
|
},
|
||||||
[this._name]
|
[this._name, loadingAllowed]
|
||||||
)
|
)
|
||||||
/* We also construct all subject queries _without_ encoding the name to work around a previous bug
|
/* We also construct all subject queries _without_ encoding the name to work around a previous bug
|
||||||
* See https://github.com/giggls/opencampsitemap/issues/30
|
* See https://github.com/giggls/opencampsitemap/issues/30
|
||||||
|
@ -267,6 +281,7 @@ export default class FeatureReviews {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct a featureReviewsFor or fetches it from the cache
|
* Construct a featureReviewsFor or fetches it from the cache
|
||||||
*
|
*
|
||||||
|
@ -288,7 +303,7 @@ export default class FeatureReviews {
|
||||||
tagsSource: UIEventSource<Record<string, string>>,
|
tagsSource: UIEventSource<Record<string, string>>,
|
||||||
mangroveIdentity: MangroveIdentity,
|
mangroveIdentity: MangroveIdentity,
|
||||||
options: { nameKey: string; fallbackName: string },
|
options: { nameKey: string; fallbackName: string },
|
||||||
state?: SpecialVisualizationState
|
state?: SpecialVisualizationState & WithUserRelatedState,
|
||||||
): FeatureReviews {
|
): FeatureReviews {
|
||||||
const key =
|
const key =
|
||||||
feature.properties.id +
|
feature.properties.id +
|
||||||
|
@ -300,34 +315,14 @@ export default class FeatureReviews {
|
||||||
if (cached !== undefined) {
|
if (cached !== undefined) {
|
||||||
return cached
|
return cached
|
||||||
}
|
}
|
||||||
const themeIsSensitive = state?.theme?.enableMorePrivacy ?? false
|
|
||||||
const settings =
|
|
||||||
state?.osmConnection?.getPreference<"always" | "yes" | "ask" | "hidden">(
|
|
||||||
"reviews-allowed"
|
|
||||||
) ?? new ImmutableStore("yes")
|
|
||||||
const loadingAllowed = new UIEventSource(false)
|
|
||||||
settings.addCallbackAndRun((s) => {
|
|
||||||
if (s === "hidden") {
|
|
||||||
loadingAllowed.set(null)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (s === "always") {
|
|
||||||
loadingAllowed.set(true)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (themeIsSensitive || s === "ask") {
|
|
||||||
loadingAllowed.set(false)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
loadingAllowed.set(true)
|
|
||||||
})
|
|
||||||
const featureReviews = new FeatureReviews(
|
const featureReviews = new FeatureReviews(
|
||||||
feature,
|
feature,
|
||||||
tagsSource,
|
tagsSource,
|
||||||
mangroveIdentity,
|
mangroveIdentity,
|
||||||
|
new UIEventSource(state?.loadReviews?.data ?? true),
|
||||||
options,
|
options,
|
||||||
state?.featureSwitchIsTesting,
|
state?.featureSwitchIsTesting,
|
||||||
loadingAllowed,
|
|
||||||
(msg, extra) => state?.reportError(msg, extra)
|
(msg, extra) => state?.reportError(msg, extra)
|
||||||
)
|
)
|
||||||
FeatureReviews._featureReviewsCache[key] = featureReviews
|
FeatureReviews._featureReviewsCache[key] = featureReviews
|
||||||
|
@ -458,7 +453,7 @@ export default class FeatureReviews {
|
||||||
this.removeReviewLocally(review)
|
this.removeReviewLocally(review)
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeReviewLocally(review: Review){
|
public removeReviewLocally(review: Review): void {
|
||||||
this._reviews.set(
|
this._reviews.set(
|
||||||
this._reviews.data?.filter(r => r !== review)
|
this._reviews.data?.filter(r => r !== review)
|
||||||
)
|
)
|
||||||
|
|
|
@ -4,7 +4,7 @@ import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||||
import UserRelatedState from "../../Logic/State/UserRelatedState"
|
import UserRelatedState from "../../Logic/State/UserRelatedState"
|
||||||
import { QueryParameters } from "../../Logic/Web/QueryParameters"
|
import { QueryParameters } from "../../Logic/Web/QueryParameters"
|
||||||
import FeatureSwitchState from "../../Logic/State/FeatureSwitchState"
|
import FeatureSwitchState from "../../Logic/State/FeatureSwitchState"
|
||||||
import { Store, UIEventSource } from "../../Logic/UIEventSource"
|
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||||
import LayerConfig from "../ThemeConfig/LayerConfig"
|
import LayerConfig from "../ThemeConfig/LayerConfig"
|
||||||
import { LastClickFeatureSource } from "../../Logic/FeatureSource/Sources/LastClickFeatureSource"
|
import { LastClickFeatureSource } from "../../Logic/FeatureSource/Sources/LastClickFeatureSource"
|
||||||
import { GeocodingUtils } from "../../Logic/Search/GeocodingProvider"
|
import { GeocodingUtils } from "../../Logic/Search/GeocodingProvider"
|
||||||
|
@ -18,6 +18,9 @@ export class WithUserRelatedState {
|
||||||
|
|
||||||
readonly osmConnection: OsmConnection
|
readonly osmConnection: OsmConnection
|
||||||
readonly userRelatedState: UserRelatedState
|
readonly userRelatedState: UserRelatedState
|
||||||
|
readonly loadReviews: Store<boolean>
|
||||||
|
|
||||||
|
|
||||||
readonly overlayLayerStates: ReadonlyMap<
|
readonly overlayLayerStates: ReadonlyMap<
|
||||||
string,
|
string,
|
||||||
{ readonly isDisplayed: UIEventSource<boolean> }
|
{ readonly isDisplayed: UIEventSource<boolean> }
|
||||||
|
@ -62,6 +65,7 @@ export class WithUserRelatedState {
|
||||||
this.featureSwitches,
|
this.featureSwitches,
|
||||||
rasterLayer
|
rasterLayer
|
||||||
)
|
)
|
||||||
|
this.loadReviews = this.constructIsLoadingReviewsAllowed()
|
||||||
|
|
||||||
if (!this.theme.official) {
|
if (!this.theme.official) {
|
||||||
// Add custom themes to the "visited custom themes"
|
// Add custom themes to the "visited custom themes"
|
||||||
|
@ -113,4 +117,31 @@ export class WithUserRelatedState {
|
||||||
}
|
}
|
||||||
return this.theme.getMatchingLayer(properties)
|
return this.theme.getMatchingLayer(properties)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private constructIsLoadingReviewsAllowed() : UIEventSource<boolean>{
|
||||||
|
const loadingAllowed = new UIEventSource(false)
|
||||||
|
|
||||||
|
const themeIsSensitive = this.theme?.enableMorePrivacy ?? false
|
||||||
|
const settings =
|
||||||
|
this?.osmConnection?.getPreference<"always" | "yes" | "ask" | "hidden">(
|
||||||
|
"reviews-allowed",
|
||||||
|
) ?? new ImmutableStore("yes")
|
||||||
|
settings.addCallbackAndRun((s) => {
|
||||||
|
if (s === "hidden") {
|
||||||
|
loadingAllowed.set(null)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (s === "always") {
|
||||||
|
loadingAllowed.set(true)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (themeIsSensitive || s === "ask") {
|
||||||
|
loadingAllowed.set(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
loadingAllowed.set(true)
|
||||||
|
})
|
||||||
|
return loadingAllowed
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
let average = reviews.average
|
let average = reviews.average
|
||||||
let allReviews: Store<
|
let allReviews: Store<
|
||||||
(Review & {
|
(Review & {
|
||||||
|
kid: string,
|
||||||
signature: string,
|
signature: string,
|
||||||
madeByLoggedInUser: Store<boolean>
|
madeByLoggedInUser: Store<boolean>
|
||||||
})[]
|
})[]
|
||||||
|
@ -32,7 +33,7 @@
|
||||||
let subject: Store<string> = reviews.subjectUri
|
let subject: Store<string> = reviews.subjectUri
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ReviewPrivacyShield {reviews} guistate={state.guistate}>
|
<ReviewPrivacyShield loadingAllowed={reviews.loadingAllowed} guistate={state.guistate}>
|
||||||
<div class="border-2 border-dashed border-gray-300 p-2 flex flex-col gap-y-2">
|
<div class="border-2 border-dashed border-gray-300 p-2 flex flex-col gap-y-2">
|
||||||
{#if $allReviews?.length > 1}
|
{#if $allReviews?.length > 1}
|
||||||
<StarsBar score={$average} />
|
<StarsBar score={$average} />
|
||||||
|
@ -43,7 +44,7 @@
|
||||||
</div>
|
</div>
|
||||||
{:else if $allReviews.length > 0}
|
{:else if $allReviews.length > 0}
|
||||||
{#each $allReviews as review}
|
{#each $allReviews as review}
|
||||||
<SingleReview {review} {state} {tags} {feature} {layer} {reviews}/>
|
<SingleReview {review} {state} {tags} {feature} {layer} {reviews} showMenu={false}/>
|
||||||
{/each}
|
{/each}
|
||||||
{:else}
|
{:else}
|
||||||
<div class="subtle m-2 italic flex justify-center">
|
<div class="subtle m-2 italic flex justify-center">
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import FeatureReviews from "../../Logic/Web/MangroveReviews"
|
import FeatureReviews from "../../Logic/Web/MangroveReviews"
|
||||||
|
import type { ReviewCollection } from "../../Logic/Web/MangroveReviews"
|
||||||
import StarsBar from "./StarsBar.svelte"
|
import StarsBar from "./StarsBar.svelte"
|
||||||
import SpecialTranslation from "../Popup/TagRendering/SpecialTranslation.svelte"
|
import SpecialTranslation from "../Popup/TagRendering/SpecialTranslation.svelte"
|
||||||
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"
|
import { ImmutableStore, Store, UIEventSource } from "../../Logic/UIEventSource"
|
||||||
|
@ -10,7 +11,7 @@
|
||||||
import Tr from "../Base/Tr.svelte"
|
import Tr from "../Base/Tr.svelte"
|
||||||
import If from "../Base/If.svelte"
|
import If from "../Base/If.svelte"
|
||||||
import Loading from "../Base/Loading.svelte"
|
import Loading from "../Base/Loading.svelte"
|
||||||
import { MangroveReviews, Review } from "mangrove-reviews-typescript"
|
import { Review } from "mangrove-reviews-typescript"
|
||||||
import { placeholder } from "../../Utils/placeholder"
|
import { placeholder } from "../../Utils/placeholder"
|
||||||
import { ExclamationTriangle } from "@babeard/svelte-heroicons/solid/ExclamationTriangle"
|
import { ExclamationTriangle } from "@babeard/svelte-heroicons/solid/ExclamationTriangle"
|
||||||
import ReviewPrivacyShield from "./ReviewPrivacyShield.svelte"
|
import ReviewPrivacyShield from "./ReviewPrivacyShield.svelte"
|
||||||
|
@ -25,9 +26,9 @@
|
||||||
* The form to create a new review.
|
* The form to create a new review.
|
||||||
* This is multi-stepped.
|
* This is multi-stepped.
|
||||||
*/
|
*/
|
||||||
export let reviews: FeatureReviews
|
export let reviews: ReviewCollection
|
||||||
export let editReview: Review & { signature: string } = undefined
|
export let editReview: Review & { signature: string } = undefined
|
||||||
let subject: Store<string> = editReview !== undefined ? new ImmutableStore(editReview.sub) : reviews.subjectUri
|
export let subject: Store<string> = editReview !== undefined ? new ImmutableStore(editReview.sub) : reviews.subjectUri
|
||||||
let score = editReview?.rating ?? 0
|
let score = editReview?.rating ?? 0
|
||||||
let confirmedScore = editReview?.rating
|
let confirmedScore = editReview?.rating
|
||||||
let isAffiliated = new UIEventSource(editReview?.metadata?.is_affiliated ?? false)
|
let isAffiliated = new UIEventSource(editReview?.metadata?.is_affiliated ?? false)
|
||||||
|
@ -49,7 +50,11 @@
|
||||||
|
|
||||||
let uploadFailed: string = undefined
|
let uploadFailed: string = undefined
|
||||||
let isTesting = state?.featureSwitchIsTesting
|
let isTesting = state?.featureSwitchIsTesting
|
||||||
|
let debug = state.featureSwitches.featureSwitchIsDebugging
|
||||||
|
|
||||||
|
/**
|
||||||
|
* only for this feature, copy upstream value to start with
|
||||||
|
*/
|
||||||
async function save() {
|
async function save() {
|
||||||
if (hasError.data) {
|
if (hasError.data) {
|
||||||
return
|
return
|
||||||
|
@ -98,11 +103,9 @@
|
||||||
_state = "done"
|
_state = "done"
|
||||||
}
|
}
|
||||||
|
|
||||||
let test = state.featureSwitches.featureSwitchIsTesting
|
|
||||||
let debug = state.featureSwitches.featureSwitchIsDebugging
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ReviewPrivacyShield hiddenIfNotAllowed {reviews} guistate={state.guistate}>
|
<ReviewPrivacyShield hiddenIfNotAllowed loadingAllowed={reviews.loadingAllowed} guistate={state.guistate}>
|
||||||
{#if uploadFailed}
|
{#if uploadFailed}
|
||||||
<div class="alert flex">
|
<div class="alert flex">
|
||||||
<ExclamationTriangle class="h-6 w-6" />
|
<ExclamationTriangle class="h-6 w-6" />
|
||||||
|
@ -188,7 +191,7 @@
|
||||||
|
|
||||||
<Tr cls="subtle mt-4" t={t.tos} />
|
<Tr cls="subtle mt-4" t={t.tos} />
|
||||||
{/if}
|
{/if}
|
||||||
{#if $debug || $test}
|
{#if $debug || $isTesting}
|
||||||
<span class="subtle self-end">{$subject}</span>
|
<span class="subtle self-end">{$subject}</span>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,29 +2,31 @@
|
||||||
/**
|
/**
|
||||||
* Due to privacy, we cannot load reviews unless allowed in the privacy policy
|
* Due to privacy, we cannot load reviews unless allowed in the privacy policy
|
||||||
*/
|
*/
|
||||||
import FeatureReviews from "../../Logic/Web/MangroveReviews"
|
|
||||||
import { MenuState } from "../../Models/MenuState"
|
import { MenuState } from "../../Models/MenuState"
|
||||||
import { ImmutableStore } from "../../Logic/UIEventSource"
|
import { UIEventSource } from "../../Logic/UIEventSource"
|
||||||
|
import Translations from "../i18n/Translations"
|
||||||
|
import Tr from "../Base/Tr.svelte"
|
||||||
|
|
||||||
export let guistate: MenuState
|
export let guistate: MenuState
|
||||||
export let reviews: FeatureReviews
|
export let loadingAllowed : UIEventSource<boolean>
|
||||||
export let hiddenIfNotAllowed: boolean = false
|
export let hiddenIfNotAllowed: boolean = false
|
||||||
let allowed = reviews?.loadingAllowed ?? new ImmutableStore(true)
|
let t = Translations.t.reviews
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
{#if $allowed}
|
{#if $loadingAllowed}
|
||||||
<slot />
|
<slot />
|
||||||
{:else if !hiddenIfNotAllowed && $allowed !== null}
|
{:else if !hiddenIfNotAllowed && $loadingAllowed !== null}
|
||||||
<div class="low-interaction mx-1 flex flex-col rounded">
|
<div class="low-interaction mx-1 flex flex-col rounded">
|
||||||
Reviews are disabled due to your privacy settings.
|
<Tr t={t.disabledForPrivacy}/>
|
||||||
<button on:click={() => reviews.loadingAllowed.set(true)} class="primary">
|
<button on:click={() => {loadingAllowed.set(true)}} class="primary">
|
||||||
Load reviews once
|
<Tr t={t.loadOnce}/>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
class="as-link self-end"
|
class="as-link self-end"
|
||||||
on:click={() => guistate.openUsersettings("mangrove-reviews-allowed")}
|
on:click={() => guistate.openUsersettings("mangrove-reviews-allowed")}
|
||||||
>
|
>
|
||||||
Edit your privacy settings
|
<Tr t={t.editPrivacySettings}/>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { SpecialVisualizationState } from "../SpecialVisualization"
|
|
||||||
import Translations from "../i18n/Translations"
|
import Translations from "../i18n/Translations"
|
||||||
import Tr from "../Base/Tr.svelte"
|
import Tr from "../Base/Tr.svelte"
|
||||||
import LoginToggle from "../Base/LoginToggle.svelte"
|
import LoginToggle from "../Base/LoginToggle.svelte"
|
||||||
|
@ -7,11 +6,14 @@
|
||||||
import SingleReview from "./SingleReview.svelte"
|
import SingleReview from "./SingleReview.svelte"
|
||||||
import Mangrove_logo from "../../assets/svg/Mangrove_logo.svelte"
|
import Mangrove_logo from "../../assets/svg/Mangrove_logo.svelte"
|
||||||
import Loading from "../Base/Loading.svelte"
|
import Loading from "../Base/Loading.svelte"
|
||||||
|
import { OsmConnection } from "../../Logic/Osm/OsmConnection"
|
||||||
|
import { MangroveIdentity } from "../../Logic/Web/MangroveReviews"
|
||||||
|
import ThemeViewState from "../../Models/ThemeViewState"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A panel showing all the reviews by the logged-in user
|
* A panel showing all the reviews by the logged-in user
|
||||||
*/
|
*/
|
||||||
export let state: SpecialVisualizationState
|
export let state: ThemeViewState & {osmConnection: OsmConnection, userRelatedState: { mangroveIdentity: MangroveIdentity }}
|
||||||
let allReviews = state.userRelatedState.mangroveIdentity.getAllReviews()
|
let allReviews = state.userRelatedState.mangroveIdentity.getAllReviews()
|
||||||
let reviews = state.userRelatedState.mangroveIdentity.getGeoReviews()
|
let reviews = state.userRelatedState.mangroveIdentity.getGeoReviews()
|
||||||
let kid = state.userRelatedState.mangroveIdentity.getKeyId()
|
let kid = state.userRelatedState.mangroveIdentity.getKeyId()
|
||||||
|
|
|
@ -17,17 +17,24 @@
|
||||||
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, { MangroveIdentity } from "../../Logic/Web/MangroveReviews"
|
import { MangroveIdentity } from "../../Logic/Web/MangroveReviews"
|
||||||
|
import type { ReviewCollection } from "../../Logic/Web/MangroveReviews"
|
||||||
|
|
||||||
import ShieldExclamation from "@babeard/svelte-heroicons/solid/ShieldExclamation"
|
import ShieldExclamation from "@babeard/svelte-heroicons/solid/ShieldExclamation"
|
||||||
import Delete_icon from "../../assets/svg/Delete_icon.svelte"
|
import Delete_icon from "../../assets/svg/Delete_icon.svelte"
|
||||||
import ValidatedInput from "../InputElement/ValidatedInput.svelte"
|
import ValidatedInput from "../InputElement/ValidatedInput.svelte"
|
||||||
|
import type { MapProperties } from "../../Models/MapProperties"
|
||||||
|
|
||||||
|
|
||||||
export let state: ThemeViewState = undefined
|
export let state: ThemeViewState & {
|
||||||
|
mapProperties?: MapProperties,
|
||||||
|
userRelatedState?: { mangroveIdentity: MangroveIdentity }
|
||||||
|
} = undefined
|
||||||
export let tags: UIEventSource<Record<string, string>> = undefined
|
export let tags: UIEventSource<Record<string, string>> = undefined
|
||||||
export let feature: Feature = undefined
|
export let feature: Feature = undefined
|
||||||
export let layer: LayerConfig = undefined
|
export let layer: LayerConfig = undefined
|
||||||
export let reviews: FeatureReviews
|
export let reviews: ReviewCollection
|
||||||
|
export let showMenu: boolean
|
||||||
|
|
||||||
export let review: Review & {
|
export let review: Review & {
|
||||||
kid: string
|
kid: string
|
||||||
|
@ -212,7 +219,7 @@
|
||||||
{date}
|
{date}
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
{#if review.signature}
|
{#if review.signature && showMenu !== undefined}
|
||||||
<div class="self-start">
|
<div class="self-start">
|
||||||
<DotMenu>
|
<DotMenu>
|
||||||
{#if $byLoggedInUser}
|
{#if $byLoggedInUser}
|
||||||
|
@ -232,7 +239,7 @@
|
||||||
{/if}
|
{/if}
|
||||||
</DotMenu>
|
</DotMenu>
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{#if review.opinion}
|
{#if review.opinion}
|
||||||
|
|
|
@ -40,7 +40,6 @@
|
||||||
import DrawerLeft from "./Base/DrawerLeft.svelte"
|
import DrawerLeft from "./Base/DrawerLeft.svelte"
|
||||||
import DrawerRight from "./Base/DrawerRight.svelte"
|
import DrawerRight from "./Base/DrawerRight.svelte"
|
||||||
import SearchResults from "./Search/SearchResults.svelte"
|
import SearchResults from "./Search/SearchResults.svelte"
|
||||||
import Hash from "../Logic/Web/Hash"
|
|
||||||
import Searchbar from "./Base/Searchbar.svelte"
|
import Searchbar from "./Base/Searchbar.svelte"
|
||||||
import ChevronRight from "@babeard/svelte-heroicons/mini/ChevronRight"
|
import ChevronRight from "@babeard/svelte-heroicons/mini/ChevronRight"
|
||||||
import { Drawer } from "flowbite-svelte"
|
import { Drawer } from "flowbite-svelte"
|
||||||
|
@ -67,7 +66,6 @@
|
||||||
let selectedElement: UIEventSource<Feature> = new UIEventSource<Feature>(undefined)
|
let selectedElement: UIEventSource<Feature> = new UIEventSource<Feature>(undefined)
|
||||||
let compass = Orientation.singleton.alpha
|
let compass = Orientation.singleton.alpha
|
||||||
let compassLoaded = Orientation.singleton.gotMeasurement
|
let compassLoaded = Orientation.singleton.gotMeasurement
|
||||||
let hash = Hash.hash
|
|
||||||
let addNewFeatureMode = state.userRelatedState.addNewFeatureMode
|
let addNewFeatureMode = state.userRelatedState.addNewFeatureMode
|
||||||
let gpsAvailable = state.geolocation.geolocationState.gpsAvailable
|
let gpsAvailable = state.geolocation.geolocationState.gpsAvailable
|
||||||
let gpsButtonAriaLabel = state.geolocation.geolocationState.gpsStateExplanation
|
let gpsButtonAriaLabel = state.geolocation.geolocationState.gpsStateExplanation
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue