Compare commits
10 Commits
3fa54dea99
...
b2dfaa18d1
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b2dfaa18d1 | ||
![]() |
173d5e2bf3 | ||
![]() |
d820d33af0 | ||
![]() |
ff6ebb349e | ||
![]() |
866628501c | ||
![]() |
fe66367c1b | ||
![]() |
6719fef9e9 | ||
![]() |
c0ac236a5f | ||
![]() |
401d7cdcfe | ||
![]() |
753210b6b2 |
@ -1,18 +1,31 @@
|
||||
import type { Metadata, ResolvingMetadata } from "next";
|
||||
import { get } from "@/lib/server-actions/events/cache";
|
||||
import { getEvent } from "@/lib/server-actions/meta/event";
|
||||
import { nip19 } from "nostr-tools";
|
||||
import { getTagValues } from "@/lib/nostr/utils";
|
||||
|
||||
export async function generateMetadata(
|
||||
{ params }: { params: { naddr: string } },
|
||||
parent: ResolvingMetadata,
|
||||
): Promise<Metadata> {
|
||||
const previousImages = (await parent).openGraph?.images || [];
|
||||
|
||||
// read route params
|
||||
const identifier = params.naddr;
|
||||
const { data, type } = nip19.decode(identifier);
|
||||
if (type !== "naddr") {
|
||||
return {
|
||||
title: "Flockstr Calendar",
|
||||
openGraph: {
|
||||
images: previousImages,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// fetch data
|
||||
const event = await get(identifier);
|
||||
const event = await getEvent(data.kind, data.pubkey, data.identifier);
|
||||
|
||||
// optionally access and extend (rather than replace) parent metadata
|
||||
const previousImages = (await parent).openGraph?.images || [];
|
||||
if (!event) {
|
||||
return {
|
||||
title: "Flockstr Calendar",
|
||||
@ -21,21 +34,24 @@ export async function generateMetadata(
|
||||
},
|
||||
};
|
||||
}
|
||||
const title = `${event.name} | Flockstr`;
|
||||
const images = event.image
|
||||
? [event.image, ...previousImages]
|
||||
: previousImages;
|
||||
|
||||
const title = `${getTagValues("name", event.tags as string[][])} | Flockstr`;
|
||||
const images =
|
||||
getTagValues("image", event.tags as string[][]) ??
|
||||
getTagValues("banner", event.tags as string[][]) ??
|
||||
"";
|
||||
|
||||
return {
|
||||
title: title,
|
||||
description: event.description,
|
||||
description: event.content,
|
||||
openGraph: {
|
||||
title: title,
|
||||
description: event.description,
|
||||
description: event.content,
|
||||
images: images,
|
||||
},
|
||||
twitter: {
|
||||
title: title,
|
||||
description: event.description,
|
||||
description: event.content,
|
||||
images: images,
|
||||
card: "summary_large_image",
|
||||
},
|
||||
|
@ -45,7 +45,7 @@ export default function Header({ event }: { event: NDKEvent }) {
|
||||
const { pubkey, tags } = event;
|
||||
const { profile } = useProfile(pubkey);
|
||||
const eventReference = event.tagId();
|
||||
const title = getTagValues("name", tags) ?? "Untitled";
|
||||
const title = getTagValues("title", tags) ?? "Untitled";
|
||||
const image =
|
||||
getTagValues("image", tags) ??
|
||||
getTagValues("picture", tags) ??
|
||||
|
@ -29,7 +29,7 @@ export default function RSVPButton({ event }: RSVPButtonProps) {
|
||||
const { currentUser } = useCurrentUser();
|
||||
const { ndk } = useNDK();
|
||||
const eventReference = event.tagId();
|
||||
const name = getTagValues("name", event.tags);
|
||||
const name = getTagValues("title", event.tags);
|
||||
const tickets = getTagValues("tickets", event.tags);
|
||||
const price = getTagAllValues("price", event.tags);
|
||||
const priceInBTC = parseFloat(getTagValues("price", event.tags) ?? "0");
|
||||
@ -88,13 +88,14 @@ export default function RSVPButton({ event }: RSVPButtonProps) {
|
||||
|
||||
if (!tickets) {
|
||||
if (rsvpEvent) {
|
||||
const rsvpResponse = getTagValues("l", rsvpEvent.tags);
|
||||
const rsvpResponse = getTagValues("status", rsvpEvent.tags);
|
||||
const rsvpResponseDeprecated = getTagValues("l", rsvpEvent.tags);
|
||||
return (
|
||||
<div className="flex items-center gap-2">
|
||||
<Button disabled>
|
||||
{rsvpResponse === "accepted"
|
||||
{rsvpResponse === "accepted" || rsvpResponseDeprecated === "accepted"
|
||||
? "Going"
|
||||
: rsvpResponse === "tentative"
|
||||
: rsvpResponse === "tentative" || rsvpResponseDeprecated === "tentative"
|
||||
? "Tentative"
|
||||
: "Not Going"}
|
||||
</Button>
|
||||
|
@ -1,18 +1,29 @@
|
||||
import type { Metadata, ResolvingMetadata } from "next";
|
||||
import { get } from "@/lib/server-actions/events/cache";
|
||||
import { getEvent } from "@/lib/server-actions/meta/event";
|
||||
import { nip19 } from "nostr-tools";
|
||||
import { getTagValues } from "@/lib/nostr/utils";
|
||||
|
||||
export async function generateMetadata(
|
||||
{ params }: { params: { naddr: string } },
|
||||
parent: ResolvingMetadata,
|
||||
): Promise<Metadata> {
|
||||
const previousImages = (await parent).openGraph?.images || [];
|
||||
// read route params
|
||||
const identifier = params.naddr;
|
||||
const { data, type } = nip19.decode(identifier);
|
||||
if (type !== "naddr") {
|
||||
return {
|
||||
title: "Flockstr Event",
|
||||
openGraph: {
|
||||
images: previousImages,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
// fetch data
|
||||
const event = await get(identifier);
|
||||
const event = await getEvent(data.kind, data.pubkey, data.identifier);
|
||||
|
||||
// optionally access and extend (rather than replace) parent metadata
|
||||
const previousImages = (await parent).openGraph?.images || [];
|
||||
if (!event) {
|
||||
return {
|
||||
title: "Flockstr Event",
|
||||
@ -21,22 +32,25 @@ export async function generateMetadata(
|
||||
},
|
||||
};
|
||||
}
|
||||
const title = `${event.name} | Flockstr`;
|
||||
const images = event.image
|
||||
? [event.image, ...previousImages]
|
||||
: previousImages;
|
||||
|
||||
const title = `${getTagValues("title", event.tags as string[][])} | Flockstr`;
|
||||
const images =
|
||||
getTagValues("image", event.tags as string[][]) ??
|
||||
getTagValues("banner", event.tags as string[][]) ??
|
||||
"";
|
||||
|
||||
return {
|
||||
title: title,
|
||||
description: event.description,
|
||||
description: event.content,
|
||||
openGraph: {
|
||||
title: title,
|
||||
description: event.description,
|
||||
images: images,
|
||||
description: event.content,
|
||||
images: [images],
|
||||
},
|
||||
twitter: {
|
||||
title: title,
|
||||
description: event.description,
|
||||
images: images,
|
||||
description: event.content,
|
||||
images: [images],
|
||||
card: "summary_large_image",
|
||||
},
|
||||
};
|
||||
|
@ -44,7 +44,7 @@ export default function EventPage({
|
||||
useEffect(() => {
|
||||
if (event) {
|
||||
const { tags, content } = event;
|
||||
const name = getTagValues("name", tags) ?? "Untitled";
|
||||
const name = getTagValues("title", tags) ?? "Untitled";
|
||||
const image =
|
||||
getTagValues("image", tags) ??
|
||||
getTagValues("picture", tags) ??
|
||||
|
@ -57,7 +57,7 @@ export default function CreateCalendarEventModal() {
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
setError("Please add a title");
|
||||
setError("Please add a name");
|
||||
return;
|
||||
}
|
||||
setIsLoading(true);
|
||||
|
@ -120,7 +120,7 @@ export default function CreateCalendarEventModal({
|
||||
const random = randomId();
|
||||
const tags: string[][] = [
|
||||
["d", random],
|
||||
["name", title],
|
||||
["title", title],
|
||||
["description", description],
|
||||
["start", toUnix(convertToTimezone(startDate, timezone)).toString()],
|
||||
["end", toUnix(convertToTimezone(endDate, timezone)).toString()],
|
||||
|
@ -41,8 +41,7 @@ export default function RSVPModal({ eventReference }: RSVPModalProps) {
|
||||
const tags: string[][] = [
|
||||
["d", random],
|
||||
["a", eventReference],
|
||||
["L", "status"],
|
||||
["l", statusMap[type], "status"],
|
||||
["status", statusMap[type]],
|
||||
];
|
||||
const event = await createEvent(ndk, {
|
||||
content: "",
|
||||
|
@ -44,8 +44,8 @@ export default function AvatarStack({
|
||||
}
|
||||
|
||||
function User({ pubkey, className }: { pubkey: string; className: string }) {
|
||||
const { profile } = useProfile(pubkey);
|
||||
const npub = nip19.npubEncode(pubkey);
|
||||
const { profile, npub } = useProfile(pubkey);
|
||||
// const npub = profilenip19.npubEncode(pubkey);
|
||||
|
||||
return (
|
||||
<Avatar
|
||||
|
11
db/client.ts
Normal file
11
db/client.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { PrismaClient } from "@prisma/client";
|
||||
|
||||
declare global {
|
||||
var prisma: PrismaClient | undefined;
|
||||
}
|
||||
|
||||
const prisma = global.prisma || new PrismaClient();
|
||||
|
||||
if (process.env.NODE_ENV === "development") global.prisma = prisma;
|
||||
|
||||
export default prisma;
|
@ -7,7 +7,7 @@ import { type NDKUserProfile } from "@nostr-dev-kit/ndk";
|
||||
|
||||
export default function useProfile(key: string) {
|
||||
const { ndk, getProfile } = useNDK();
|
||||
|
||||
const npub = key.length === 64 ? nip19.npubEncode(key) : key;
|
||||
useEffect(() => {
|
||||
if (!ndk) return;
|
||||
if (NOSTR_BECH32_REGEXP.test(key)) {
|
||||
@ -20,5 +20,5 @@ export default function useProfile(key: string) {
|
||||
};
|
||||
}, [key, ndk]);
|
||||
|
||||
return { profile: getProfile(key) };
|
||||
return { profile: getProfile(key), npub: npub };
|
||||
}
|
||||
|
12
lib/server-actions/meta/event.ts
Normal file
12
lib/server-actions/meta/event.ts
Normal file
@ -0,0 +1,12 @@
|
||||
"use server";
|
||||
import prisma from "@/db/client";
|
||||
|
||||
export async function getEvent(kind: number, pubkey: string, d: string) {
|
||||
return await prisma.nostrEvent.findFirst({
|
||||
where: {
|
||||
kind,
|
||||
pubkey,
|
||||
d,
|
||||
},
|
||||
});
|
||||
}
|
@ -4,7 +4,7 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"build": "prisma generate && next build",
|
||||
"start": "next start",
|
||||
"lint": "next lint"
|
||||
},
|
||||
@ -17,6 +17,7 @@
|
||||
"@nostr-dev-kit/ndk": "^2.0.0",
|
||||
"@nostr-dev-kit/ndk-cache-dexie": "^2.0.3",
|
||||
"@nostr-dev-kit/ndk-react": "^0.1.1",
|
||||
"@prisma/client": "^5.7.1",
|
||||
"@radix-ui/react-aspect-ratio": "^1.0.3",
|
||||
"@radix-ui/react-avatar": "^1.0.4",
|
||||
"@radix-ui/react-dialog": "^1.0.5",
|
||||
@ -88,6 +89,7 @@
|
||||
"postcss": "^8",
|
||||
"prettier": "^3.0.3",
|
||||
"prettier-plugin-tailwindcss": "^0.5.6",
|
||||
"prisma": "^5.7.1",
|
||||
"tailwindcss": "^3",
|
||||
"typescript": "^5",
|
||||
"webln": "^0.3.2"
|
||||
|
33
prisma/schema.prisma
Normal file
33
prisma/schema.prisma
Normal file
@ -0,0 +1,33 @@
|
||||
// This is your Prisma schema file,
|
||||
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
||||
|
||||
// datasource db {
|
||||
// provider = "postgresql"
|
||||
// url = env("POSTGRES_PRISMA_URL") // uses connection pooling
|
||||
// directUrl = env("POSTGRES_URL_NON_POOLING") // uses a direct connection
|
||||
// }
|
||||
|
||||
// generator client {
|
||||
// provider = "prisma-client-js"
|
||||
// }
|
||||
datasource db {
|
||||
provider = "mysql"
|
||||
url = env("DATABASE_URL")
|
||||
relationMode = "prisma"
|
||||
}
|
||||
|
||||
generator client {
|
||||
provider = "prisma-client-js"
|
||||
}
|
||||
|
||||
model NostrEvent {
|
||||
key Int @id @default(autoincrement())
|
||||
id String
|
||||
kind Int
|
||||
content String @db.Text
|
||||
created_at Int
|
||||
pubkey String
|
||||
tags Json @default("[]")
|
||||
sig String
|
||||
d String?
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user