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

<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>