forked from coracle/flotilla
Migrate Reports dialog to ActionItems dialog, add room join requests to queue
This commit is contained in:
@@ -30,6 +30,7 @@
|
||||
import EventInfo from "@app/components/EventInfo.svelte"
|
||||
import ProfileBadges from "@app/components/ProfileBadges.svelte"
|
||||
import {pubkeyLink, deriveUserIsSpaceAdmin, deriveSpaceBannedPubkeyItems} from "@app/core/state"
|
||||
import {addSpaceMembers} from "@app/core/commands"
|
||||
import {pushModal} from "@app/util/modal"
|
||||
import {pushToast} from "@app/util/toast"
|
||||
import {makeChatPath} from "@app/util/routes"
|
||||
@@ -85,10 +86,7 @@
|
||||
})
|
||||
|
||||
const restoreMember = async () => {
|
||||
const {error} = await manageRelay(url!, {
|
||||
method: ManagementMethod.AllowPubkey,
|
||||
params: [pubkey],
|
||||
})
|
||||
const error = await addSpaceMembers(url!, [pubkey])
|
||||
|
||||
if (error) {
|
||||
pushToast({theme: "error", message: error})
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
type Props = {
|
||||
url: string
|
||||
event: TrustedEvent
|
||||
onDelete?: () => void
|
||||
onResolved?: () => void
|
||||
}
|
||||
|
||||
const {url, event, onDelete}: Props = $props()
|
||||
const {url, event, onResolved}: Props = $props()
|
||||
|
||||
const etag = getTag("e", event.tags)
|
||||
const ptag = getTag("p", event.tags)
|
||||
@@ -45,7 +45,7 @@
|
||||
{/if}
|
||||
</span>
|
||||
</div>
|
||||
<ReportMenu {url} {event} {onDelete} />
|
||||
<ReportMenu {url} {event} {onResolved} />
|
||||
</div>
|
||||
{#if event.content}
|
||||
<div class="border-l-2 border-primary pl-3">
|
||||
|
||||
@@ -208,7 +208,7 @@
|
||||
</div>
|
||||
<div class="flex items-center gap-2">
|
||||
<input type="checkbox" class="checkbox" bind:checked={values.isClosed} />
|
||||
<span class="text-sm opacity-75">Ignore requests to join</span>
|
||||
<span class="text-sm opacity-75">Membership requires approval</span>
|
||||
</div>
|
||||
</ModalBody>
|
||||
{@render footer({loading})}
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
<script lang="ts">
|
||||
import {getTagValue} from "@welshman/util"
|
||||
import type {TrustedEvent, PublishedRoomMeta} from "@welshman/util"
|
||||
import {repository} from "@welshman/app"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import ProfileName from "@app/components/ProfileName.svelte"
|
||||
import ProfileDetail from "@app/components/ProfileDetail.svelte"
|
||||
import RoomName from "@app/components/RoomName.svelte"
|
||||
import {pushModal} from "@app/util/modal"
|
||||
import {pushToast} from "@app/util/toast"
|
||||
import {deriveRoom} from "@app/core/state"
|
||||
import {addRoomMembers} from "@app/core/commands"
|
||||
|
||||
type Props = {
|
||||
url: string
|
||||
event: TrustedEvent
|
||||
onResolved?: () => void
|
||||
}
|
||||
|
||||
const {url, event, onResolved}: Props = $props()
|
||||
|
||||
const h = getTagValue("h", event.tags) || ""
|
||||
const room = deriveRoom(url, h)
|
||||
|
||||
const showProfile = () => pushModal(ProfileDetail, {pubkey: event.pubkey, url})
|
||||
|
||||
const dismiss = async () => {
|
||||
loading = true
|
||||
|
||||
try {
|
||||
const {error} = await manageRelay(url, {
|
||||
method: ManagementMethod.BanEvent,
|
||||
params: [event.id, "Join request dismissed"]
|
||||
})
|
||||
|
||||
if (error) {
|
||||
pushToast({theme: "error", message: error})
|
||||
} else {
|
||||
pushToast({message: "Join request has been dismissed."})
|
||||
repository.removeEvent(event.id)
|
||||
onResolved?.()
|
||||
}
|
||||
} finally {
|
||||
loading = false
|
||||
}
|
||||
}
|
||||
|
||||
const accept = async () => {
|
||||
loading = true
|
||||
|
||||
try {
|
||||
const error = await addRoomMembers(url, $room as PublishedRoomMeta, [event.pubkey])
|
||||
|
||||
if (error) {
|
||||
pushToast({theme: "error", message: error})
|
||||
} else {
|
||||
pushToast({message: "Member has been added to the room!"})
|
||||
onResolved?.()
|
||||
}
|
||||
} finally {
|
||||
loading = false
|
||||
}
|
||||
}
|
||||
|
||||
let loading = $state(false)
|
||||
</script>
|
||||
|
||||
<div class="column gap-4 card2 card2-sm bg-alt">
|
||||
<div class="flex justify-between gap-2">
|
||||
<div>
|
||||
<Button class="inline text-primary" onclick={showProfile}>
|
||||
<ProfileName pubkey={event.pubkey} {url} />
|
||||
</Button>
|
||||
<span>
|
||||
requested membership in #<RoomName {url} {h} />
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<Button class="btn btn-neutral btn-sm" onclick={dismiss} disabled={loading}>Dismiss</Button>
|
||||
<Button class="btn btn-primary btn-sm" onclick={accept} disabled={loading}>Accept</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -2,9 +2,8 @@
|
||||
import {onMount} from "svelte"
|
||||
import {setKey, popKey} from "@lib/implicit"
|
||||
import {sleep} from "@welshman/lib"
|
||||
import {ManagementMethod} from "@welshman/util"
|
||||
import {manageRelay} from "@welshman/app"
|
||||
import {addRoomMember, displayProfileByPubkey, waitForThunkError} from "@welshman/app"
|
||||
import {displayProfileByPubkey} from "@welshman/app"
|
||||
import type {PublishedRoomMeta} from "@welshman/util"
|
||||
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
|
||||
import Spinner from "@lib/components/Spinner.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
@@ -22,6 +21,7 @@
|
||||
import {pushToast} from "@app/util/toast"
|
||||
import {pushModal} from "@app/util/modal"
|
||||
import {deriveRoom, deriveSpaceMembers} from "@app/core/state"
|
||||
import {addRoomMembers} from "@app/core/commands"
|
||||
|
||||
interface Props {
|
||||
url: string
|
||||
@@ -42,35 +42,14 @@
|
||||
// Show loading for auto submit callback
|
||||
await sleep(500)
|
||||
|
||||
const results = await Promise.all(
|
||||
pubkeys
|
||||
.filter(pubkey => !$spaceMembers.includes(pubkey))
|
||||
.map(pubkey =>
|
||||
manageRelay(url, {
|
||||
method: ManagementMethod.AllowPubkey,
|
||||
params: [pubkey],
|
||||
}),
|
||||
),
|
||||
)
|
||||
const error = await addRoomMembers(url, $room as PublishedRoomMeta, pubkeys)
|
||||
|
||||
for (const {error} of results) {
|
||||
if (error) {
|
||||
return pushToast({theme: "error", message: error})
|
||||
}
|
||||
if (error) {
|
||||
pushToast({theme: "error", message: error})
|
||||
} else {
|
||||
pushToast({message: "Members have successfully been added!"})
|
||||
back()
|
||||
}
|
||||
|
||||
const errors = await Promise.all(
|
||||
pubkeys.map(pubkey => waitForThunkError(addRoomMember(url, $room, pubkey))),
|
||||
)
|
||||
|
||||
for (const error of errors) {
|
||||
if (error) {
|
||||
return pushToast({theme: "error", message: errors[0]})
|
||||
}
|
||||
}
|
||||
|
||||
pushToast({message: "Members have successfully been added!"})
|
||||
back()
|
||||
} finally {
|
||||
loading = false
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
<script lang="ts">
|
||||
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
import Icon from "@lib/components/Icon.svelte"
|
||||
import Modal from "@lib/components/Modal.svelte"
|
||||
import ModalBody from "@lib/components/ModalBody.svelte"
|
||||
import ModalHeader from "@lib/components/ModalHeader.svelte"
|
||||
import ModalTitle from "@lib/components/ModalTitle.svelte"
|
||||
import ModalSubtitle from "@lib/components/ModalSubtitle.svelte"
|
||||
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
||||
import ReportItem from "@app/components/ReportItem.svelte"
|
||||
import RoomJoinItem from "@app/components/RoomJoinItem.svelte"
|
||||
import RelayName from "@app/components/RelayName.svelte"
|
||||
import {REPORT} from "@welshman/util"
|
||||
import {deriveSpaceActionItems} from "@app/core/state"
|
||||
|
||||
interface Props {
|
||||
url: string
|
||||
}
|
||||
|
||||
const {url}: Props = $props()
|
||||
|
||||
const actionItems = deriveSpaceActionItems(url)
|
||||
|
||||
const back = () => history.back()
|
||||
|
||||
const onResolved = () => {
|
||||
if ($actionItems.length === 0) {
|
||||
back()
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<Modal>
|
||||
<ModalBody>
|
||||
<ModalHeader>
|
||||
<ModalTitle>Action Items</ModalTitle>
|
||||
<ModalSubtitle>on <RelayName {url} class="text-primary" /></ModalSubtitle>
|
||||
</ModalHeader>
|
||||
<div class="flex flex-col gap-2">
|
||||
{#each $actionItems as event (event.id)}
|
||||
{#if event.kind === REPORT}
|
||||
<ReportItem {url} {event} {onResolved} />
|
||||
{:else}
|
||||
<RoomJoinItem {url} {event} {onResolved} />
|
||||
{/if}
|
||||
{:else}
|
||||
<p class="py-12 text-center">No action items found.</p>
|
||||
{/each}
|
||||
</div>
|
||||
</ModalBody>
|
||||
<ModalFooter>
|
||||
<Button class="btn btn-link" onclick={back}>
|
||||
<Icon icon={AltArrowLeft} />
|
||||
Go back
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</Modal>
|
||||
@@ -1,6 +1,5 @@
|
||||
<script lang="ts">
|
||||
import {displayRelayUrl, ManagementMethod} from "@welshman/util"
|
||||
import {manageRelay} from "@welshman/app"
|
||||
import {displayRelayUrl} from "@welshman/util"
|
||||
import AltArrowLeft from "@assets/icons/alt-arrow-left.svg?dataurl"
|
||||
import Spinner from "@lib/components/Spinner.svelte"
|
||||
import Button from "@lib/components/Button.svelte"
|
||||
@@ -13,6 +12,7 @@
|
||||
import ModalSubtitle from "@lib/components/ModalSubtitle.svelte"
|
||||
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
||||
import ProfileMultiSelect from "@app/components/ProfileMultiSelect.svelte"
|
||||
import {addSpaceMembers} from "@app/core/commands"
|
||||
import {pushToast} from "@app/util/toast"
|
||||
|
||||
interface Props {
|
||||
@@ -27,23 +27,14 @@
|
||||
loading = true
|
||||
|
||||
try {
|
||||
const results = await Promise.all(
|
||||
pubkeys.map(pubkey =>
|
||||
manageRelay(url, {
|
||||
method: ManagementMethod.AllowPubkey,
|
||||
params: [pubkey],
|
||||
}),
|
||||
),
|
||||
)
|
||||
const error = await addSpaceMembers(url, pubkeys)
|
||||
|
||||
for (const {error} of results) {
|
||||
if (error) {
|
||||
return pushToast({theme: "error", message: error})
|
||||
}
|
||||
if (error) {
|
||||
pushToast({theme: "error", message: error})
|
||||
} else {
|
||||
pushToast({message: "Members have successfully been added!"})
|
||||
back()
|
||||
}
|
||||
|
||||
pushToast({message: "Members have successfully been added!"})
|
||||
back()
|
||||
} finally {
|
||||
loading = false
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
import ModalFooter from "@lib/components/ModalFooter.svelte"
|
||||
import Profile from "@app/components/Profile.svelte"
|
||||
import {deriveSpaceBannedPubkeyItems, deriveSupportedMethods} from "@app/core/state"
|
||||
import {addSpaceMembers} from "@app/core/commands"
|
||||
import {pushToast} from "@app/util/toast"
|
||||
|
||||
interface Props {
|
||||
@@ -55,10 +56,7 @@
|
||||
}
|
||||
|
||||
const restoreMember = async (pubkey: string) => {
|
||||
const {error} = await manageRelay(url, {
|
||||
method: ManagementMethod.AllowPubkey,
|
||||
params: [pubkey],
|
||||
})
|
||||
const error = await addSpaceMembers(url, [pubkey])
|
||||
|
||||
if (error) {
|
||||
pushToast({theme: "error", message: error})
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<script lang="ts">
|
||||
import {onMount} from "svelte"
|
||||
import {derived} from "svelte/store"
|
||||
import {displayRelayUrl, EVENT_TIME, ZAP_GOAL, THREAD, CLASSIFIED, REPORT} from "@welshman/util"
|
||||
import {displayRelayUrl, EVENT_TIME, ZAP_GOAL, THREAD, CLASSIFIED} from "@welshman/util"
|
||||
import {deriveRelay, createSearch, pubkey} from "@welshman/app"
|
||||
import {fly} from "@lib/transition"
|
||||
import Magnifier from "@assets/icons/magnifier.svg?dataurl"
|
||||
@@ -35,7 +35,7 @@
|
||||
import SpaceJoin from "@app/components/SpaceJoin.svelte"
|
||||
import RelayName from "@app/components/RelayName.svelte"
|
||||
import SpaceMembers from "@app/components/SpaceMembers.svelte"
|
||||
import SpaceReports from "@app/components/SpaceReports.svelte"
|
||||
import SpaceActionItems from "@app/components/SpaceActionItems.svelte"
|
||||
import RoomCreate from "@app/components/RoomCreate.svelte"
|
||||
import SpaceMenuRoomItem from "@app/components/SpaceMenuRoomItem.svelte"
|
||||
import VoiceWidget from "@app/components/VoiceWidget.svelte"
|
||||
@@ -52,6 +52,7 @@
|
||||
deriveUserCanCreateRoom,
|
||||
deriveUserIsSpaceAdmin,
|
||||
deriveEventsForUrl,
|
||||
deriveSpaceActionItems,
|
||||
notificationSettings,
|
||||
deriveShouldNotify,
|
||||
displayRoom,
|
||||
@@ -73,7 +74,7 @@
|
||||
const otherVoiceRooms = deriveOtherVoiceRooms(url)
|
||||
const members = deriveSpaceMembers(url)
|
||||
const userIsAdmin = deriveUserIsSpaceAdmin(url)
|
||||
const reports = deriveEventsForUrl(url, [{kinds: [REPORT]}])
|
||||
const actionItems = deriveSpaceActionItems(url)
|
||||
|
||||
const spaceKinds = derived(
|
||||
deriveEventsForUrl(url, [{kinds: CONTENT_KINDS}]),
|
||||
@@ -102,7 +103,7 @@
|
||||
|
||||
const showMembers = () => pushModal(SpaceMembers, {url}, {replaceState})
|
||||
|
||||
const showReports = () => pushModal(SpaceReports, {url}, {replaceState})
|
||||
const showActionItems = () => pushModal(SpaceActionItems, {url}, {replaceState})
|
||||
|
||||
const canCreateRoom = deriveUserCanCreateRoom(url)
|
||||
|
||||
@@ -140,11 +141,15 @@
|
||||
<SecondaryNavSection class="min-h-0 flex-1 flex flex-col overflow-hidden pb-0">
|
||||
<div class="flex-shrink-0">
|
||||
<Button
|
||||
class="flex w-full flex-col rounded-xl p-3 transition-all hover:bg-base-100"
|
||||
class="relative flex w-full flex-col rounded-xl p-3 transition-all hover:bg-base-100"
|
||||
onclick={openMenu}>
|
||||
<div class="flex items-center justify-between">
|
||||
<strong class="ellipsize flex items-center gap-1">
|
||||
<RelayName {url} />
|
||||
<strong class="flex items-center gap-1 relative">
|
||||
<RelayName {url} class="ellipsize" />
|
||||
<div
|
||||
class="absolute -right-3 top-0 h-2 w-2 rounded-full bg-primary transition-all opacity-0"
|
||||
class:opacity-100={$userIsAdmin && $actionItems.length > 0}>
|
||||
</div>
|
||||
{#if $notificationSettings.push && !$shouldNotify}
|
||||
<Icon icon={BellOff} size={3} class="opacity-50" />
|
||||
{/if}
|
||||
@@ -178,9 +183,12 @@
|
||||
</li>
|
||||
{#if $userIsAdmin}
|
||||
<li>
|
||||
<Button onclick={showReports}>
|
||||
<Button onclick={showActionItems}>
|
||||
<Icon icon={Danger} />
|
||||
View Reports ({$reports.length})
|
||||
Action Items ({$actionItems.length})
|
||||
{#if $actionItems.length > 0}
|
||||
<div class="h-2 w-2 rounded-full bg-primary"></div>
|
||||
{/if}
|
||||
</Button>
|
||||
</li>
|
||||
{/if}
|
||||
|
||||
Reference in New Issue
Block a user