adding short note creation

This commit is contained in:
zmeyer44 2023-10-18 12:23:39 -04:00
parent b7590b8ca2
commit d8f9ea6d40
9 changed files with 245 additions and 64 deletions

4
.env
View File

@ -1,7 +1,7 @@
# S3 data storage
S3_BUCKET_NAME="flockstr"
MY_AWS_ACCESS_KEY="AKIAT2UDOJMC6K25RFFN"
MY_AWS_SECRET_KEY="secret"
MY_AWS_ACCESS_KEY="AKIAT2UDOJMC4RSXQO5Y"
MY_AWS_SECRET_KEY="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"
REGION="us-east-1"
S3_BUCKET_URL="https://flockstr.s3.amazonaws.com"
NEXT_PUBLIC_S3_BUCKET_URL="https://flockstr.s3.amazonaws.com"

2
.gitignore vendored
View File

@ -26,7 +26,7 @@ yarn-error.log*
# local env files
.env*.local
# .env
.env
# vercel
.vercel

View File

@ -47,7 +47,6 @@ export default function LiveStreamingSection() {
if (bParticipants) return 1;
return -1;
});
console.log(processedEvents);
return (
<Section className="max-sm:-mx-5">
<SectionHeader>

View File

@ -228,9 +228,15 @@ export default function FormModal<TSchema extends FieldValues>({
{fieldProps.options?.map((o) => (
<CommandItem
key={o.value}
onClick={() =>
console.log("Captured", o.value)
}
onSelect={() => {
setValue(
field.name,
o.value as PathValue<
TSchema,
Path<TSchema>
>,
);
}}
className="teamaspace-y-1 flex flex-col items-start px-4 py-2"
>
<p>{o.label}</p>

View File

@ -2,17 +2,19 @@ import { useEffect, useState } from "react";
import FormModal from "./FormModal";
import { z } from "zod";
import useEvents from "@/lib/hooks/useEvents";
import { updateList } from "@/lib/actions/create";
import { createEventHandler } from "@/lib/actions/create";
import { unixTimeNowInSeconds } from "@/lib/nostr/dates";
import { useModal } from "@/app/_providers/modal/provider";
import { toast } from "sonner";
import { useNDK } from "@/app/_providers/ndk";
import { NostrEvent } from "@nostr-dev-kit/ndk";
import { useSigner, type SignerStoreItem } from "@/app/_providers/signer";
import { getTagValues } from "@/lib/nostr/utils";
import useCurrentUser from "@/lib/hooks/useCurrentUser";
import { saveEphemeralSigner } from "@/lib/actions/ephemeral";
import useLists from "@/lib/hooks/useLists";
const ShortTextNoteSchema = z.object({
content: z.string(),
image: z.string().optional(),
list: z.string().optional(),
isPrivate: z.boolean().optional(),
});
@ -21,18 +23,19 @@ type ShortTextNoteType = z.infer<typeof ShortTextNoteSchema>;
export default function ShortTextNoteModal() {
const modal = useModal();
const { lists, init } = useLists();
const [isLoading, setIsLoading] = useState(false);
const { currentUser } = useCurrentUser();
const [sent, setSent] = useState(false);
const { ndk } = useNDK();
// const { events } = useEvents({
// filter: {
// kinds: [listEvent.kind as number],
// authors: [listEvent.pubkey],
// since: unixTimeNowInSeconds() - 10,
// limit: 1,
// },
// enabled: sent,
// });
const { getSigner } = useSigner()!;
useEffect(() => {
if (currentUser) {
void init(currentUser.pubkey);
}
}, [currentUser]);
// useEffect(() => {
// if (events.length) {
// console.log("Done!");
@ -42,11 +45,69 @@ export default function ShortTextNoteModal() {
// }
// }, [events]);
async function handleSubmit(listData: ShortTextNoteType) {
async function handleSubmit(data: ShortTextNoteType) {
setIsLoading(true);
const newTags = Object.entries(listData);
setSent(true);
// const result = await updateList(ndk!, listEvent, newTags);
if (!ndk) {
toast.error("Error connecting");
return;
}
if (data.list) {
const list = lists.find((l) => getTagValues("d", l.tags) === data.list);
if (!list) {
toast.error("No list found");
return;
}
let listSigner: SignerStoreItem | undefined = undefined;
if (data.isPrivate) {
listSigner = await getSigner(list);
if (!listSigner?.signer) {
toast.error("Error creating signer");
return;
}
if (!listSigner?.saved) {
console.log("Saving delegate...");
await saveEphemeralSigner(ndk!, listSigner.signer, {
associatedEvent: list,
keyProfile: {
name: listSigner.title,
picture: currentUser?.profile?.image,
lud06: currentUser?.profile?.lud06,
lud16: currentUser?.profile?.lud16,
},
});
}
}
const result = await createEventHandler(
ndk,
{
content: data.content,
kind: 1,
tags: [],
},
data.isPrivate,
list,
listSigner?.signer,
);
if (result) {
toast.success("Note added!");
modal?.hide();
}
} else {
const result = await createEventHandler(
ndk,
{
content: data.content,
kind: 1,
tags: [],
},
data.isPrivate,
);
if (result) {
toast.success("Note added!");
modal?.hide();
}
}
}
return (
@ -63,20 +124,23 @@ export default function ShortTextNoteModal() {
type: "select-search",
placeholder: "Search your lists",
slug: "list",
options: [
{
label: "Spicy Takes 🌶️",
value: "325grg ",
},
{
label: "Public reading list",
value: "grherh ",
},
{
label: "Radnosm other",
value: "grhfaggferh ",
},
],
options: lists
.map((l) => {
console.log("MApping", l);
const title =
getTagValues("title", l.tags) ??
getTagValues("name", l.tags) ??
"Untitled";
const description = getTagValues("description", l.tags);
const value = getTagValues("d", l.tags);
if (!value) return;
return {
label: title,
description,
value: value,
};
})
.filter(Boolean),
},
{
label: "Private",

View File

@ -41,6 +41,90 @@ export async function createEvent(
return false;
}
}
export async function createEventHandler(
ndk: NDK,
event: {
content: string;
kind: number;
tags: string[][];
},
isPrivate?: boolean,
list?: NDKList,
delegateSigner?: NDKPrivateKeySigner,
) {
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", "ordstr"]],
pubkey,
created_at: unixTimeNowInSeconds(),
} as NostrEvent);
await eventToPublish.sign();
let publishedEvent: NDKEvent | null = null;
// Check if is private event
if (isPrivate) {
const rawEventString = JSON.stringify(eventToPublish.rawEvent());
const passphrase = generateRandomString();
const encryptedRawEventString = await encryptMessage(
rawEventString,
passphrase,
);
const signer = delegateSigner ?? ndk.signer!;
const user = await signer.user();
const newEvent = new NDKEvent(ndk, {
content: encryptedRawEventString,
kind: 3745,
tags: [
["kind", event.kind.toString()],
["client", "ordstr"],
],
pubkey: user.pubkey,
} as NostrEvent);
await newEvent.sign(signer);
await newEvent.publish();
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", "ordstr"],
],
pubkey: user.pubkey,
} as NostrEvent);
await messageEvent.encrypt(
new NDKUser({ hexpubkey: subscriber }),
signer,
);
await messageEvent.sign(signer);
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;
}
export async function createEncryptedEventOnPrivateList(
ndk: NDK,
event: {
@ -64,7 +148,6 @@ export async function createEncryptedEventOnPrivateList(
await eventToPublish.sign();
const rawEventString = JSON.stringify(eventToPublish.rawEvent());
const passphrase = generateRandomString();
// const passphrase = "test";
const encryptedRawEventString = await encryptMessage(
rawEventString,
passphrase,
@ -79,7 +162,7 @@ export async function createEncryptedEventOnPrivateList(
["kind", event.kind.toString()],
["client", "ordstr"],
],
pubkey: user.hexpubkey,
pubkey: user.pubkey,
} as NostrEvent);
await newEvent.sign(signer);

View File

@ -5,7 +5,7 @@ import currentUserStore from "@/lib/stores/currentUser";
import { UserSchema } from "@/types";
import { useNDK } from "@/app/_providers/ndk";
import { nip19 } from "nostr-tools";
import useLists from "./useLists";
export default function useCurrentUser() {
const {
currentUser,
@ -15,30 +15,7 @@ export default function useCurrentUser() {
follows,
} = currentUserStore();
const { loginWithNip07, getProfile, ndk } = useNDK();
// const {
// events: contactList,
// isLoading,
// onEvent,
// } = useEvents({
// filter: {
// kinds: [3],
// authors: [currentUser?.pubkey ?? ""],
// limit: 1,
// },
// enabled: !!currentUser,
// });
// onEvent((event) => {
// console.log("EVENT", event);
// const foundFollows = event.tags
// .filter(([key]) => key === "p")
// .map(([key, pubkey]) => pubkey);
// console.log("Found follows", foundFollows);
// if (follows.length !== foundFollows.length) {
// setFollows(follows);
// }
// });
const { init } = useLists();
async function attemptLogin() {
try {
const shouldReconnect = localStorage.getItem("shouldReconnect");
@ -86,6 +63,7 @@ export default function useCurrentUser() {
console.log("user", user);
await user.fetchProfile();
setCurrentUser(user);
void init(user.pubkey);
}
return {

33
lib/hooks/useLists.ts Normal file
View File

@ -0,0 +1,33 @@
"use client";
import listsStore from "@/lib/stores/lists";
import { useNDK } from "@/app/_providers/ndk";
import { useState } from "react";
import { NDKList } from "@nostr-dev-kit/ndk";
export default function useLists() {
const [isLoading, setIsLoading] = useState(false);
const { lists, setLists, follows } = listsStore();
const { fetchEvents, ndk } = useNDK();
async function init(pubkey: string) {
setIsLoading(true);
try {
const listEvents = await fetchEvents({
kinds: [30001],
authors: [pubkey],
});
setLists(listEvents.map((l) => new NDKList(ndk, l.rawEvent())));
} catch (err) {
console.log("error in init", err);
} finally {
setIsLoading(false);
}
}
return {
lists,
isLoading,
init,
follows,
};
}

18
lib/stores/lists.ts Normal file
View File

@ -0,0 +1,18 @@
import { create } from "zustand";
import { type NDKList } from "@nostr-dev-kit/ndk";
interface CurrentUserState {
lists: NDKList[];
follows: string[];
setLists: (lists: NDKList[]) => void;
setFollows: (follows: string[]) => void;
}
const listsStore = create<CurrentUserState>()((set) => ({
lists: [],
follows: [],
setLists: (lists) => set((state) => ({ ...state, lists: lists })),
setFollows: (follows) => set((state) => ({ ...state, follows: follows })),
}));
export default listsStore;