adding short note creation
This commit is contained in:
parent
b7590b8ca2
commit
d8f9ea6d40
4
.env
4
.env
@ -1,7 +1,7 @@
|
|||||||
# S3 data storage
|
# S3 data storage
|
||||||
S3_BUCKET_NAME="flockstr"
|
S3_BUCKET_NAME="flockstr"
|
||||||
MY_AWS_ACCESS_KEY="AKIAT2UDOJMC6K25RFFN"
|
MY_AWS_ACCESS_KEY="AKIAT2UDOJMC4RSXQO5Y"
|
||||||
MY_AWS_SECRET_KEY="secret"
|
MY_AWS_SECRET_KEY="SwS8fm1+pKlrWU8pzuRCUYqyJ5roNwu9AZRhbWMu"
|
||||||
REGION="us-east-1"
|
REGION="us-east-1"
|
||||||
S3_BUCKET_URL="https://flockstr.s3.amazonaws.com"
|
S3_BUCKET_URL="https://flockstr.s3.amazonaws.com"
|
||||||
NEXT_PUBLIC_S3_BUCKET_URL="https://flockstr.s3.amazonaws.com"
|
NEXT_PUBLIC_S3_BUCKET_URL="https://flockstr.s3.amazonaws.com"
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -26,7 +26,7 @@ yarn-error.log*
|
|||||||
|
|
||||||
# local env files
|
# local env files
|
||||||
.env*.local
|
.env*.local
|
||||||
# .env
|
.env
|
||||||
|
|
||||||
# vercel
|
# vercel
|
||||||
.vercel
|
.vercel
|
||||||
|
@ -47,7 +47,6 @@ export default function LiveStreamingSection() {
|
|||||||
if (bParticipants) return 1;
|
if (bParticipants) return 1;
|
||||||
return -1;
|
return -1;
|
||||||
});
|
});
|
||||||
console.log(processedEvents);
|
|
||||||
return (
|
return (
|
||||||
<Section className="max-sm:-mx-5">
|
<Section className="max-sm:-mx-5">
|
||||||
<SectionHeader>
|
<SectionHeader>
|
||||||
|
@ -228,9 +228,15 @@ export default function FormModal<TSchema extends FieldValues>({
|
|||||||
{fieldProps.options?.map((o) => (
|
{fieldProps.options?.map((o) => (
|
||||||
<CommandItem
|
<CommandItem
|
||||||
key={o.value}
|
key={o.value}
|
||||||
onClick={() =>
|
onSelect={() => {
|
||||||
console.log("Captured", o.value)
|
setValue(
|
||||||
}
|
field.name,
|
||||||
|
o.value as PathValue<
|
||||||
|
TSchema,
|
||||||
|
Path<TSchema>
|
||||||
|
>,
|
||||||
|
);
|
||||||
|
}}
|
||||||
className="teamaspace-y-1 flex flex-col items-start px-4 py-2"
|
className="teamaspace-y-1 flex flex-col items-start px-4 py-2"
|
||||||
>
|
>
|
||||||
<p>{o.label}</p>
|
<p>{o.label}</p>
|
||||||
|
@ -2,17 +2,19 @@ import { useEffect, useState } from "react";
|
|||||||
import FormModal from "./FormModal";
|
import FormModal from "./FormModal";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import useEvents from "@/lib/hooks/useEvents";
|
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 { unixTimeNowInSeconds } from "@/lib/nostr/dates";
|
||||||
import { useModal } from "@/app/_providers/modal/provider";
|
import { useModal } from "@/app/_providers/modal/provider";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { useNDK } from "@/app/_providers/ndk";
|
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 { 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({
|
const ShortTextNoteSchema = z.object({
|
||||||
content: z.string(),
|
content: z.string(),
|
||||||
image: z.string().optional(),
|
|
||||||
list: z.string().optional(),
|
list: z.string().optional(),
|
||||||
isPrivate: z.boolean().optional(),
|
isPrivate: z.boolean().optional(),
|
||||||
});
|
});
|
||||||
@ -21,18 +23,19 @@ type ShortTextNoteType = z.infer<typeof ShortTextNoteSchema>;
|
|||||||
|
|
||||||
export default function ShortTextNoteModal() {
|
export default function ShortTextNoteModal() {
|
||||||
const modal = useModal();
|
const modal = useModal();
|
||||||
|
const { lists, init } = useLists();
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const { currentUser } = useCurrentUser();
|
||||||
const [sent, setSent] = useState(false);
|
const [sent, setSent] = useState(false);
|
||||||
const { ndk } = useNDK();
|
const { ndk } = useNDK();
|
||||||
// const { events } = useEvents({
|
const { getSigner } = useSigner()!;
|
||||||
// filter: {
|
|
||||||
// kinds: [listEvent.kind as number],
|
useEffect(() => {
|
||||||
// authors: [listEvent.pubkey],
|
if (currentUser) {
|
||||||
// since: unixTimeNowInSeconds() - 10,
|
void init(currentUser.pubkey);
|
||||||
// limit: 1,
|
}
|
||||||
// },
|
}, [currentUser]);
|
||||||
// enabled: sent,
|
|
||||||
// });
|
|
||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
// if (events.length) {
|
// if (events.length) {
|
||||||
// console.log("Done!");
|
// console.log("Done!");
|
||||||
@ -42,11 +45,69 @@ export default function ShortTextNoteModal() {
|
|||||||
// }
|
// }
|
||||||
// }, [events]);
|
// }, [events]);
|
||||||
|
|
||||||
async function handleSubmit(listData: ShortTextNoteType) {
|
async function handleSubmit(data: ShortTextNoteType) {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
const newTags = Object.entries(listData);
|
if (!ndk) {
|
||||||
setSent(true);
|
toast.error("Error connecting");
|
||||||
// const result = await updateList(ndk!, listEvent, newTags);
|
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 (
|
return (
|
||||||
@ -63,20 +124,23 @@ export default function ShortTextNoteModal() {
|
|||||||
type: "select-search",
|
type: "select-search",
|
||||||
placeholder: "Search your lists",
|
placeholder: "Search your lists",
|
||||||
slug: "list",
|
slug: "list",
|
||||||
options: [
|
options: lists
|
||||||
{
|
.map((l) => {
|
||||||
label: "Spicy Takes 🌶️",
|
console.log("MApping", l);
|
||||||
value: "325grg ",
|
const title =
|
||||||
},
|
getTagValues("title", l.tags) ??
|
||||||
{
|
getTagValues("name", l.tags) ??
|
||||||
label: "Public reading list",
|
"Untitled";
|
||||||
value: "grherh ",
|
const description = getTagValues("description", l.tags);
|
||||||
},
|
const value = getTagValues("d", l.tags);
|
||||||
{
|
if (!value) return;
|
||||||
label: "Radnosm other",
|
return {
|
||||||
value: "grhfaggferh ",
|
label: title,
|
||||||
},
|
description,
|
||||||
],
|
value: value,
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.filter(Boolean),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: "Private",
|
label: "Private",
|
||||||
|
@ -41,6 +41,90 @@ export async function createEvent(
|
|||||||
return false;
|
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(
|
export async function createEncryptedEventOnPrivateList(
|
||||||
ndk: NDK,
|
ndk: NDK,
|
||||||
event: {
|
event: {
|
||||||
@ -64,7 +148,6 @@ export async function createEncryptedEventOnPrivateList(
|
|||||||
await eventToPublish.sign();
|
await eventToPublish.sign();
|
||||||
const rawEventString = JSON.stringify(eventToPublish.rawEvent());
|
const rawEventString = JSON.stringify(eventToPublish.rawEvent());
|
||||||
const passphrase = generateRandomString();
|
const passphrase = generateRandomString();
|
||||||
// const passphrase = "test";
|
|
||||||
const encryptedRawEventString = await encryptMessage(
|
const encryptedRawEventString = await encryptMessage(
|
||||||
rawEventString,
|
rawEventString,
|
||||||
passphrase,
|
passphrase,
|
||||||
@ -79,7 +162,7 @@ export async function createEncryptedEventOnPrivateList(
|
|||||||
["kind", event.kind.toString()],
|
["kind", event.kind.toString()],
|
||||||
["client", "ordstr"],
|
["client", "ordstr"],
|
||||||
],
|
],
|
||||||
pubkey: user.hexpubkey,
|
pubkey: user.pubkey,
|
||||||
} as NostrEvent);
|
} as NostrEvent);
|
||||||
|
|
||||||
await newEvent.sign(signer);
|
await newEvent.sign(signer);
|
||||||
|
@ -5,7 +5,7 @@ import currentUserStore from "@/lib/stores/currentUser";
|
|||||||
import { UserSchema } from "@/types";
|
import { UserSchema } from "@/types";
|
||||||
import { useNDK } from "@/app/_providers/ndk";
|
import { useNDK } from "@/app/_providers/ndk";
|
||||||
import { nip19 } from "nostr-tools";
|
import { nip19 } from "nostr-tools";
|
||||||
|
import useLists from "./useLists";
|
||||||
export default function useCurrentUser() {
|
export default function useCurrentUser() {
|
||||||
const {
|
const {
|
||||||
currentUser,
|
currentUser,
|
||||||
@ -15,30 +15,7 @@ export default function useCurrentUser() {
|
|||||||
follows,
|
follows,
|
||||||
} = currentUserStore();
|
} = currentUserStore();
|
||||||
const { loginWithNip07, getProfile, ndk } = useNDK();
|
const { loginWithNip07, getProfile, ndk } = useNDK();
|
||||||
|
const { init } = useLists();
|
||||||
// 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);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
async function attemptLogin() {
|
async function attemptLogin() {
|
||||||
try {
|
try {
|
||||||
const shouldReconnect = localStorage.getItem("shouldReconnect");
|
const shouldReconnect = localStorage.getItem("shouldReconnect");
|
||||||
@ -86,6 +63,7 @@ export default function useCurrentUser() {
|
|||||||
console.log("user", user);
|
console.log("user", user);
|
||||||
await user.fetchProfile();
|
await user.fetchProfile();
|
||||||
setCurrentUser(user);
|
setCurrentUser(user);
|
||||||
|
void init(user.pubkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
33
lib/hooks/useLists.ts
Normal file
33
lib/hooks/useLists.ts
Normal 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
18
lib/stores/lists.ts
Normal 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;
|
Loading…
x
Reference in New Issue
Block a user