diff --git a/bun.lockb b/bun.lockb
index e4f644c..3917105 100755
Binary files a/bun.lockb and b/bun.lockb differ
diff --git a/components/KindCard/3745.tsx b/components/KindCard/3745.tsx
index 5f40704..a4d20a0 100644
--- a/components/KindCard/3745.tsx
+++ b/components/KindCard/3745.tsx
@@ -9,7 +9,7 @@ import { useNDK } from "@/app/_providers/ndk";
import { RiArrowRightLine, RiLockLine } from "react-icons/ri";
import { HiOutlineLockOpen } from "react-icons/hi";
import { decryptMessage } from "@/lib/nostr";
-import { NDKUser } from "@nostr-dev-kit/ndk";
+import { NDKFilter, NDKUser } from "@nostr-dev-kit/ndk";
import { log } from "@/lib/utils";
import { EventSchema } from "@/types";
import KindCard from "@/components/KindCard";
@@ -24,9 +24,10 @@ import {
import useCurrentUser from "@/lib/hooks/useCurrentUser";
import { unlockEvent } from "@/lib/actions/create";
import { type KindCardProps } from "./";
+import { getTagValues } from "@/lib/nostr/utils";
export default function Kind3745(props: KindCardProps) {
- const { pubkey, content, id } = props;
+ const { pubkey, content, id, tags } = props;
const { currentUser } = useCurrentUser();
const [error, setError] = useState("");
const [passphrase, setPassphrase] = useState("");
@@ -44,11 +45,16 @@ export default function Kind3745(props: KindCardProps) {
log("func", `handleFetchEvent()`);
setFetchingEvent(true);
try {
- const directMessageEvent = await ndk.fetchEvent({
+ const delegate = getTagValues("delegate", tags);
+ const filter: NDKFilter = {
kinds: [4],
["#e"]: [id],
["#p"]: [currentUser.pubkey],
- });
+ };
+ if (delegate) {
+ filter.authors = [delegate];
+ }
+ const directMessageEvent = await ndk.fetchEvent(filter);
if (directMessageEvent) {
log("info", "direct msg decryption");
if (!signer) return;
diff --git a/components/ui/calendar.tsx b/components/ui/calendar.tsx
new file mode 100644
index 0000000..6c08e3a
--- /dev/null
+++ b/components/ui/calendar.tsx
@@ -0,0 +1,71 @@
+"use client"
+
+import * as React from "react"
+import { ChevronLeftIcon, ChevronRightIcon } from "@radix-ui/react-icons"
+import { DayPicker } from "react-day-picker"
+
+import { cn } from "@/lib/utils"
+import { buttonVariants } from "@/components/ui/button"
+
+export type CalendarProps = React.ComponentProps
+
+function Calendar({
+ className,
+ classNames,
+ showOutsideDays = true,
+ ...props
+}: CalendarProps) {
+ return (
+ .day-range-end)]:rounded-r-md [&:has(>.day-range-start)]:rounded-l-md first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md"
+ : "[&:has([aria-selected])]:rounded-md"
+ ),
+ day: cn(
+ buttonVariants({ variant: "ghost" }),
+ "h-8 w-8 p-0 font-normal aria-selected:opacity-100"
+ ),
+ day_range_start: "day-range-start",
+ day_range_end: "day-range-end",
+ day_selected:
+ "bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground",
+ day_today: "bg-accent text-accent-foreground",
+ day_outside: "text-muted-foreground opacity-50",
+ day_disabled: "text-muted-foreground opacity-50",
+ day_range_middle:
+ "aria-selected:bg-accent aria-selected:text-accent-foreground",
+ day_hidden: "invisible",
+ ...classNames,
+ }}
+ components={{
+ IconLeft: ({ ...props }) => ,
+ IconRight: ({ ...props }) => ,
+ }}
+ {...props}
+ />
+ )
+}
+Calendar.displayName = "Calendar"
+
+export { Calendar }
diff --git a/lib/actions/create.ts b/lib/actions/create.ts
index 1facef3..215c921 100644
--- a/lib/actions/create.ts
+++ b/lib/actions/create.ts
@@ -309,3 +309,91 @@ export async function follow(
const newContacts = await createEvent(ndk, newEvent);
return newContacts;
}
+export async function createCalendarEvent(
+ ndk: NDK,
+ event: {
+ content: string;
+ kind: number;
+ tags: string[][];
+ },
+ isPrivate?: boolean,
+ list?: NDKList,
+ delegateSigner?: NDKPrivateKeySigner,
+) {
+ log("func", "createEventHandler");
+ const pubkey = await window.nostr?.getPublicKey();
+ if (!pubkey || !window.nostr) {
+ throw new Error("No public key provided!");
+ }
+ const eventToPublish = new NDKEvent(ndk, {
+ ...event,
+ tags: [...event.tags, ["client", "flockstr"]],
+ pubkey,
+ created_at: unixTimeNowInSeconds(),
+ } as NostrEvent);
+
+ await eventToPublish.sign();
+
+ let publishedEvent: NDKEvent | null = null;
+ // Check if is private event
+ if (isPrivate) {
+ log("info", "isPrivate");
+ const rawEventString = JSON.stringify(eventToPublish.rawEvent());
+ const passphrase = generateRandomString();
+ const encryptedRawEventString = await encryptMessage(
+ rawEventString,
+ passphrase,
+ );
+ const newEvent = new NDKEvent(ndk, {
+ content: encryptedRawEventString,
+ kind: 3745,
+ tags: [
+ ["kind", event.kind.toString()],
+ ["client", "flockstr"],
+ ],
+ pubkey,
+ } as NostrEvent);
+ await newEvent.sign();
+ await newEvent.publish();
+
+ const messenger = delegateSigner ?? ndk.signer!;
+ const user = await messenger.user();
+ log("info", "Signer", user.toString());
+
+ if (list) {
+ // Send DMs to subscribers
+ const subscribers = getTagsValues("p", list.tags);
+ for (const subscriber of subscribers) {
+ const messageEvent = new NDKEvent(ndk, {
+ content: passphrase,
+ kind: 4,
+ tags: [
+ ["p", subscriber],
+ ["e", newEvent.id],
+ ["client", "flockstr"],
+ ],
+ pubkey: user.pubkey,
+ } as NostrEvent);
+ await messageEvent.encrypt(
+ new NDKUser({ hexpubkey: subscriber }),
+ messenger,
+ );
+ await messageEvent.sign(messenger);
+ await messageEvent.publish();
+ }
+ }
+ publishedEvent = newEvent;
+ } else {
+ await eventToPublish.publish();
+ publishedEvent = eventToPublish;
+ }
+ if (list) {
+ const tag = publishedEvent.tagReference();
+ if (!tag) return;
+ // Add event to list
+ await list.addItem(tag, undefined, false);
+ await list.sign();
+ await list.publish();
+ }
+ return true;
+}
diff --git a/package.json b/package.json
index 7d2cda3..00c341c 100644
--- a/package.json
+++ b/package.json
@@ -37,6 +37,7 @@
"cmdk": "^0.2.0",
"crypto": "^1.0.1",
"crypto-js": "^4.1.1",
+ "date-fns": "^2.30.0",
"dayjs": "^1.11.10",
"dexie": "^3.2.4",
"dexie-react-hooks": "^1.1.6",
@@ -49,6 +50,7 @@
"nostr-tools": "^1.16.0",
"ramda": "^0.29.1",
"react": "^18",
+ "react-day-picker": "^8.9.1",
"react-dom": "^18",
"react-hook-form": "^7.47.0",
"react-icons": "^4.11.0",