your personal website on atproto - mirror
blento.app
1<script lang="ts">
2 import { Alert, Button, Input, Subheading } from '@foxui/core';
3 import Modal from '$lib/components/modal/Modal.svelte';
4 import type { CreationModalComponentProps } from '../../types';
5 import { getRecord } from '$lib/atproto/methods';
6 import type { Did } from '@atcute/lexicons';
7
8 const EVENT_COLLECTION = 'community.lexicon.calendar.event';
9
10 let { item = $bindable(), oncreate, oncancel }: CreationModalComponentProps = $props();
11
12 let isValidating = $state(false);
13 let errorMessage = $state('');
14 let eventUrl = $state('');
15
16 function parseEventUrl(url: string): { did: string; rkey: string } | null {
17 // Match smokesignal.events URLs: https://smokesignal.events/{did}/{rkey}
18 const smokesignalMatch = url.match(/^https?:\/\/smokesignal\.events\/(did:[^/]+)\/([^/?#]+)/);
19 if (smokesignalMatch) {
20 return { did: smokesignalMatch[1], rkey: smokesignalMatch[2] };
21 }
22
23 // Match AT URIs: at://{did}/community.lexicon.calendar.event/{rkey}
24 const atUriMatch = url.match(/^at:\/\/(did:[^/]+)\/([^/]+)\/([^/?#]+)/);
25 if (atUriMatch && atUriMatch[2] === EVENT_COLLECTION) {
26 return { did: atUriMatch[1], rkey: atUriMatch[3] };
27 }
28
29 return null;
30 }
31
32 async function validateAndCreate() {
33 errorMessage = '';
34 isValidating = true;
35
36 try {
37 const parsed = parseEventUrl(eventUrl.trim());
38
39 if (!parsed) {
40 throw new Error('Invalid URL format');
41 }
42
43 // Validate the event exists by fetching the record directly
44 const record = await getRecord({
45 did: parsed.did as Did,
46 collection: EVENT_COLLECTION,
47 rkey: parsed.rkey
48 });
49
50 if (!record?.value) {
51 throw new Error('Event not found');
52 }
53
54 // Store as AT URI
55 item.cardData.uri = `at://${parsed.did}/${EVENT_COLLECTION}/${parsed.rkey}`;
56
57 return true;
58 } catch (err) {
59 errorMessage =
60 err instanceof Error && err.message === 'Event not found'
61 ? "Couldn't find that event. Please check the URL and try again."
62 : 'Invalid URL. Please enter a valid event AT URI or smokesignal.events URL.';
63 return false;
64 } finally {
65 isValidating = false;
66 }
67 }
68</script>
69
70<Modal open={true} closeButton={false}>
71 <form
72 onsubmit={async () => {
73 if (await validateAndCreate()) oncreate();
74 }}
75 class="flex flex-col gap-2"
76 >
77 <Subheading>Enter an event URL</Subheading>
78 <Input
79 bind:value={eventUrl}
80 placeholder="at://did:.../community.lexicon.calendar.event/..."
81 class="mt-4"
82 />
83
84 {#if errorMessage}
85 <Alert type="error" title="Failed to create event card"><span>{errorMessage}</span></Alert>
86 {/if}
87
88 <p class="text-base-500 dark:text-base-400 mt-2 text-xs">
89 Paste an AT URI for a calendar event or a smokesignal.events URL.
90 </p>
91
92 <div class="mt-4 flex justify-end gap-2">
93 <Button onclick={oncancel} variant="ghost">Cancel</Button>
94 <Button type="submit" disabled={isValidating || !eventUrl.trim()}
95 >{isValidating ? 'Creating...' : 'Create'}</Button
96 >
97 </div>
98 </form>
99</Modal>