You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
355 lines
8.4 KiB
355 lines
8.4 KiB
<script lang="ts"> |
|
import { nostrClient } from '../../services/nostr/nostr-client.js'; |
|
import { relayManager } from '../../services/nostr/relay-manager.js'; |
|
import { cacheEvent } from '../../services/cache/event-cache.js'; |
|
import { sessionManager } from '../../services/auth/session-manager.js'; |
|
import PublicationStatusModal from './PublicationStatusModal.svelte'; |
|
import type { NostrEvent } from '../../types/nostr.js'; |
|
|
|
interface Props { |
|
open?: boolean; |
|
event: NostrEvent; |
|
onClose: () => void; |
|
} |
|
|
|
let { open = $bindable(false), event, onClose }: Props = $props(); |
|
|
|
let reason = $state(''); |
|
let publishing = $state(false); |
|
let publicationModalOpen = $state(false); |
|
let publicationResults = $state<{ success: string[]; failed: Array<{ relay: string; error: string }> } | null>(null); |
|
|
|
function close() { |
|
open = false; |
|
reason = ''; |
|
publicationModalOpen = false; |
|
publicationResults = null; |
|
} |
|
|
|
async function sendReport() { |
|
if (!reason.trim()) { |
|
alert('Please enter a reason for reporting this event.'); |
|
return; |
|
} |
|
|
|
const session = sessionManager.getSession(); |
|
if (!session) { |
|
alert('You must be logged in to report an event.'); |
|
return; |
|
} |
|
|
|
publishing = true; |
|
|
|
try { |
|
const eventTemplate = { |
|
kind: 1984, |
|
pubkey: session.pubkey, |
|
created_at: Math.floor(Date.now() / 1000), |
|
tags: [ |
|
['e', event.id], // Tag the reported event |
|
['p', event.pubkey] // Tag the event author |
|
], |
|
content: reason.trim() |
|
}; |
|
|
|
const signedEvent = await session.signer(eventTemplate); |
|
await cacheEvent(signedEvent); |
|
|
|
const relays = relayManager.getPublishRelays( |
|
relayManager.getProfileReadRelays(), |
|
true |
|
); |
|
|
|
const results = await nostrClient.publish(signedEvent, { relays }); |
|
publicationResults = results; |
|
publicationModalOpen = true; |
|
|
|
if (results.success.length > 0) { |
|
// Clear the form after successful publication |
|
reason = ''; |
|
// Close the modal after a delay |
|
setTimeout(() => { |
|
close(); |
|
}, 2000); |
|
} |
|
} catch (error) { |
|
console.error('Error publishing report:', error); |
|
publicationResults = { |
|
success: [], |
|
failed: [{ relay: 'Unknown', error: error instanceof Error ? error.message : 'Unknown error' }] |
|
}; |
|
publicationModalOpen = true; |
|
} finally { |
|
publishing = false; |
|
} |
|
} |
|
</script> |
|
|
|
{#if open} |
|
<div |
|
class="modal-overlay" |
|
onclick={(e) => { |
|
if (e.target === e.currentTarget) close(); |
|
}} |
|
onkeydown={(e) => { |
|
if (e.key === 'Escape') close(); |
|
}} |
|
role="dialog" |
|
aria-modal="true" |
|
aria-labelledby="report-modal-title" |
|
tabindex="-1" |
|
> |
|
<div class="modal-content"> |
|
<div class="modal-header"> |
|
<h2 id="report-modal-title">Report Event</h2> |
|
<button onclick={close} class="close-button" aria-label="Close">×</button> |
|
</div> |
|
|
|
<div class="modal-body"> |
|
<p class="modal-description"> |
|
Please provide a reason for reporting this event. This will create a kind 1984 event. |
|
</p> |
|
|
|
<div class="form-group"> |
|
<label for="report-reason" class="form-label">Reason</label> |
|
<textarea |
|
id="report-reason" |
|
bind:value={reason} |
|
class="reason-input" |
|
rows="6" |
|
placeholder="Enter the reason for reporting this event..." |
|
disabled={publishing} |
|
></textarea> |
|
</div> |
|
|
|
<div class="form-actions"> |
|
<button |
|
class="cancel-button" |
|
onclick={close} |
|
disabled={publishing} |
|
> |
|
Cancel |
|
</button> |
|
<button |
|
class="send-button" |
|
onclick={sendReport} |
|
disabled={publishing || !reason.trim()} |
|
> |
|
{publishing ? 'Sending...' : 'Send Report'} |
|
</button> |
|
</div> |
|
</div> |
|
</div> |
|
</div> |
|
{/if} |
|
|
|
<PublicationStatusModal bind:open={publicationModalOpen} bind:results={publicationResults} /> |
|
|
|
<style> |
|
.modal-overlay { |
|
position: fixed; |
|
top: 0; |
|
left: 0; |
|
right: 0; |
|
bottom: 0; |
|
background: rgba(0, 0, 0, 0.5); |
|
z-index: 2000; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
padding: 1rem; |
|
} |
|
|
|
:global(.dark) .modal-overlay { |
|
background: rgba(0, 0, 0, 0.7); |
|
} |
|
|
|
.modal-content { |
|
position: relative; |
|
background: var(--fog-post, #ffffff); |
|
border: 1px solid var(--fog-border, #e5e7eb); |
|
border-radius: 0.5rem; |
|
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2); |
|
max-width: 500px; |
|
width: 100%; |
|
max-height: 90vh; |
|
display: flex; |
|
flex-direction: column; |
|
overflow: hidden; |
|
} |
|
|
|
:global(.dark) .modal-content { |
|
background: var(--fog-dark-post, #1f2937); |
|
border-color: var(--fog-dark-border, #374151); |
|
} |
|
|
|
.modal-header { |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: center; |
|
padding: 1rem; |
|
border-bottom: 1px solid var(--fog-border, #e5e7eb); |
|
} |
|
|
|
:global(.dark) .modal-header { |
|
border-bottom-color: var(--fog-dark-border, #374151); |
|
} |
|
|
|
.modal-header h2 { |
|
margin: 0; |
|
font-size: 1.25rem; |
|
font-weight: 600; |
|
color: var(--fog-text, #1f2937); |
|
} |
|
|
|
:global(.dark) .modal-header h2 { |
|
color: var(--fog-dark-text, #f9fafb); |
|
} |
|
|
|
.close-button { |
|
background: transparent; |
|
border: none; |
|
font-size: 1.5rem; |
|
line-height: 1; |
|
cursor: pointer; |
|
color: var(--fog-text-light, #52667a); |
|
padding: 0.25rem 0.5rem; |
|
border-radius: 0.25rem; |
|
transition: background 0.2s; |
|
} |
|
|
|
.close-button:hover { |
|
background: var(--fog-highlight, #f3f4f6); |
|
color: var(--fog-text, #1f2937); |
|
} |
|
|
|
:global(.dark) .close-button { |
|
color: var(--fog-dark-text-light, #a8b8d0); |
|
} |
|
|
|
:global(.dark) .close-button:hover { |
|
background: var(--fog-dark-highlight, #374151); |
|
color: var(--fog-dark-text, #f9fafb); |
|
} |
|
|
|
.modal-body { |
|
padding: 1rem; |
|
overflow-y: auto; |
|
flex: 1; |
|
} |
|
|
|
.modal-description { |
|
margin: 0 0 1rem 0; |
|
color: var(--fog-text-light, #52667a); |
|
font-size: 0.875rem; |
|
} |
|
|
|
:global(.dark) .modal-description { |
|
color: var(--fog-dark-text-light, #a8b8d0); |
|
} |
|
|
|
.form-group { |
|
display: flex; |
|
flex-direction: column; |
|
gap: 0.5rem; |
|
margin-bottom: 1rem; |
|
} |
|
|
|
.form-label { |
|
font-weight: 500; |
|
color: var(--fog-text, #1f2937); |
|
font-size: 0.875rem; |
|
} |
|
|
|
:global(.dark) .form-label { |
|
color: var(--fog-dark-text, #f9fafb); |
|
} |
|
|
|
.reason-input { |
|
padding: 0.75rem; |
|
border: 1px solid var(--fog-border, #e5e7eb); |
|
border-radius: 0.25rem; |
|
background: var(--fog-post, #ffffff); |
|
color: var(--fog-text, #1f2937); |
|
font-size: 0.875rem; |
|
font-family: inherit; |
|
resize: vertical; |
|
width: 100%; |
|
box-sizing: border-box; |
|
} |
|
|
|
:global(.dark) .reason-input { |
|
border-color: var(--fog-dark-border, #374151); |
|
background: var(--fog-dark-post, #1f2937); |
|
color: var(--fog-dark-text, #f9fafb); |
|
} |
|
|
|
.reason-input:focus { |
|
outline: none; |
|
border-color: var(--fog-accent, #64748b); |
|
} |
|
|
|
:global(.dark) .reason-input:focus { |
|
border-color: var(--fog-dark-accent, #94a3b8); |
|
} |
|
|
|
.reason-input:disabled { |
|
opacity: 0.6; |
|
cursor: not-allowed; |
|
} |
|
|
|
.form-actions { |
|
display: flex; |
|
gap: 0.5rem; |
|
justify-content: flex-end; |
|
} |
|
|
|
.cancel-button, |
|
.send-button { |
|
padding: 0.5rem 1rem; |
|
border-radius: 0.25rem; |
|
font-size: 0.875rem; |
|
font-weight: 500; |
|
cursor: pointer; |
|
transition: all 0.2s; |
|
} |
|
|
|
.cancel-button { |
|
background: var(--fog-highlight, #f3f4f6); |
|
color: var(--fog-text, #1f2937); |
|
border: 1px solid var(--fog-border, #e5e7eb); |
|
} |
|
|
|
:global(.dark) .cancel-button { |
|
background: var(--fog-dark-highlight, #374151); |
|
color: var(--fog-dark-text, #f9fafb); |
|
border-color: var(--fog-dark-border, #475569); |
|
} |
|
|
|
.cancel-button:hover:not(:disabled) { |
|
background: var(--fog-border, #e5e7eb); |
|
} |
|
|
|
:global(.dark) .cancel-button:hover:not(:disabled) { |
|
background: var(--fog-dark-border, #475569); |
|
} |
|
|
|
.send-button { |
|
background: var(--fog-accent, #64748b); |
|
color: white; |
|
border: none; |
|
} |
|
|
|
:global(.dark) .send-button { |
|
background: var(--fog-dark-accent, #94a3b8); |
|
} |
|
|
|
.send-button:hover:not(:disabled) { |
|
opacity: 0.9; |
|
} |
|
|
|
.send-button:disabled { |
|
opacity: 0.6; |
|
cursor: not-allowed; |
|
} |
|
</style>
|
|
|