adding events

This commit is contained in:
zmeyer44 2023-10-23 23:49:20 -04:00
parent f952f4d456
commit 6b13cfee0a
5 changed files with 301 additions and 34 deletions

View File

@ -0,0 +1,84 @@
"use client";
import {
Section,
SectionHeader,
SectionTitle,
SectionContent,
} from "@/containers/PageSection";
import { Button } from "@/components/ui/button";
import { RiArrowRightLine } from "react-icons/ri";
import CalendarEventCard, {
CardLoading,
} from "@/components/Cards/CalendarEvent";
import { ScrollArea, ScrollBar } from "@/components/ui/scroll-area";
import Link from "next/link";
import useEvents from "@/lib/hooks/useEvents";
import { Event } from "nostr-tools";
import KindLoading from "@/components/KindCard/loading";
import { nip19 } from "nostr-tools";
import { getTagValues, getTagsValues } from "@/lib/nostr/utils";
import { type NDKKind } from "@nostr-dev-kit/ndk";
import { uniqBy } from "ramda";
export default function UpcomingEventsSection() {
const { events } = useEvents({
filter: {
kinds: [31923 as NDKKind],
limit: 10,
},
});
console.log("UpcomingEventsSection", events);
const processedEvents = uniqBy(
(e) => getTagValues("name", e.tags),
events,
).sort((a, b) => {
const aImage = getTagValues("image", a.tags);
const bImage = getTagValues("image", b.tags);
if (aImage && bImage) {
return 0;
}
if (bImage) return 1;
return -1;
});
return (
<Section className="max-sm:-mx-5">
<SectionHeader>
<div className="center gap-x-2 max-sm:px-5">
<SectionTitle>Upcoming Events</SectionTitle>
</div>
<Button variant={"ghost"}>
View all <RiArrowRightLine className="ml-1 h-4 w-4" />
</Button>
</SectionHeader>
<SectionContent className="relative">
<ScrollArea>
<div className="flex space-x-2 pb-4 max-sm:px-5">
{processedEvents?.length > 3 ? (
processedEvents.slice(0, 6).map((e, idx) => {
return (
<Link key={e.id} href={`/event/${e.encode()}`}>
<CalendarEventCard
event={e.rawEvent()}
className="min-w-[250px] max-w-[350px]"
/>
</Link>
);
})
) : (
<>
<CardLoading className="min-w-[250px] max-w-[350px]" />
<CardLoading className="min-w-[250px] max-w-[350px]" />
<CardLoading className="min-w-[250px] max-w-[350px]" />
<CardLoading className="min-w-[250px] max-w-[350px]" />
</>
)}
</div>
<ScrollBar orientation="horizontal" />
</ScrollArea>
</SectionContent>
</Section>
);
}

View File

@ -1,5 +1,6 @@
import dynamic from "next/dynamic";
import ExploreCreators from "./_sections/ExploreCreators";
import UpcomingEvents from "./_sections/UpcomingEvents";
import LongFormContentSection from "./_sections/LongFormContent";
import BecomeACreator from "./_sections/BecomeACreator";
@ -23,6 +24,7 @@ export default function Page() {
return (
<div className="relative space-y-6 px-5 pt-5 sm:pt-7">
<ExploreCreators />
<UpcomingEvents />
<LongFormContentSection />
<BecomeACreator />
<LiveStreamingSection />

View File

@ -46,14 +46,10 @@ export default function Header({ event }: { event: NDKEvent }) {
const { ndk } = useNDK();
const [checkingPayment, setCheckingPayment] = useState(false);
const [hasValidPayment, setHasValidPayment] = useState(false);
const [syncingUsers, setSyncingUsers] = useState(false);
const { pubkey, tags } = event;
const { profile } = useProfile(pubkey);
console.log("EVENT", tags);
const noteIds = getTagsValues("e", tags).filter(Boolean);
const title = getTagValues("name", tags) ?? "Untitled";
console.log("tite", tags);
const image =
getTagValues("image", tags) ??
getTagValues("picture", tags) ??
@ -110,19 +106,7 @@ export default function Header({ event }: { event: NDKEvent }) {
setCheckingPayment(false);
}
}
async function handleSyncUsers() {
if (!event || !ndk) return;
setSyncingUsers(true);
try {
console.log("handleSyncUsers");
await updateListUsersFromZaps(ndk, event.tagId(), rawEvent);
toast.success("Users Synced!");
} catch (err) {
console.log("error syncing users", err);
} finally {
setSyncingUsers(false);
}
}
async function handleSendZap() {
try {
const result = await sendZap(
@ -163,7 +147,7 @@ export default function Header({ event }: { event: NDKEvent }) {
</div>
<div className="space-y-1 p-3 @sm:px-3.5 @sm:pb-2 @sm:pt-5">
<div className="flex items-start justify-between gap-x-1.5 @lg:gap-x-2.5">
<div className="space-y-1 @sm:space-y-2">
<div className="shrink-0 space-y-1 @sm:space-y-2">
<h2 className="font-condensed text-2xl font-semibold sm:text-3xl lg:text-4xl">
{title}
</h2>
@ -175,14 +159,7 @@ export default function Header({ event }: { event: NDKEvent }) {
{!!currentUser && currentUser.pubkey === pubkey && (
<>
<Button onClick={() => modal?.show(<CreateListEvent />)}>
Add Event
</Button>
<Button
variant={"outline"}
loading={syncingUsers}
onClick={() => void handleSyncUsers()}
>
Sync users
Invite Users
</Button>
<Button
variant="ghost"
@ -233,30 +210,30 @@ export default function Header({ event }: { event: NDKEvent }) {
))}
</div>
</div>
<div className="flex pt-1 @md:pt-2">
<div className="flex flex-col gap-x-6 gap-y-3 pt-1 @md:pt-2 @xl:flex-row">
<div className="flex-1">
{!!description && (
<p className="line-clamp-3 text-sm text-muted-foreground md:text-sm">
<p className="line-clamp-3 text-sm text-muted-foreground @md:text-sm">
{description}
</p>
)}
</div>
<div className="flex flex-1 justify-end">
<div className="flex flex-1 @xl:justify-end">
<div className="flex flex-col gap-3 pr-3">
{!!startDate && (
<div className="flex flex-1 items-center gap-3">
<SmallCalendarIcon date={startDate} />
<div className="">
<p className="text-bold text-base">
<p className="text-bold text-sm @xl:text-base">
{formatDate(startDate, "dddd, MMMM Do")}
</p>
{!!endDate ? (
<p className="text-sm text-muted-foreground">{`${formatDate(
<p className="text-xs text-muted-foreground @xl:text-sm">{`${formatDate(
startDate,
"h:mm a",
)} to ${formatDate(endDate, "h:mm a")}`}</p>
) : (
<p className="text-xs text-muted-foreground">{`${formatDate(
<p className="text-xs text-muted-foreground @xl:text-sm">{`${formatDate(
startDate,
"h:mm a",
)}`}</p>
@ -270,8 +247,10 @@ export default function Header({ event }: { event: NDKEvent }) {
<div className="">
{location.length > 2 ? (
<>
<p className="text-bold text-base">{location[1]}</p>
<p className="text-xs text-muted-foreground">
<p className="text-bold text-sm @xl:text-base">
{location[1]}
</p>
<p className="text-xs text-muted-foreground @xl:text-sm">
{location[2]}
</p>
</>

View File

@ -0,0 +1,159 @@
"use client";
import Image from "next/image";
import { cn, formatNumber } from "@/lib/utils";
import { Badge } from "@/components/ui/badge";
import { RxClock, RxCalendar } from "react-icons/rx";
import { HiOutlineUsers } from "react-icons/hi";
import { AspectRatio } from "@/components/ui/aspect-ratio";
import { Skeleton } from "@/components/ui/skeleton";
import { formatDate } from "@/lib/utils/dates";
import { NostrEvent } from "@nostr-dev-kit/ndk";
import {
getTagAllValues,
getTagValues,
getTagsValues,
} from "@/lib/nostr/utils";
import useProfile from "@/lib/hooks/useProfile";
import SmallProfileLine from "@/components/ProfileContainers/SmallProfileLine";
type CalendarEventCardProps = {
event: NostrEvent;
className?: string;
};
export default function CalendarEventCard({
className,
event,
}: CalendarEventCardProps) {
const { pubkey, tags } = event;
const { profile } = useProfile(pubkey);
const title = getTagValues("name", tags) || "Untitled";
console.log("tite", tags);
const image =
getTagValues("image", tags) ??
getTagValues("picture", tags) ??
getTagValues("banner", tags) ??
profile?.banner;
const description = event.content;
const startDate = getTagValues("start", tags)
? new Date(parseInt(getTagValues("start", tags) as string) * 1000)
: null;
const endDate = getTagValues("end", tags)
? new Date(parseInt(getTagValues("end", tags) as string) * 1000)
: null;
const getLocation = () => {
let temp = getTagAllValues("location", tags);
if (temp[0]) {
return temp;
}
return getTagAllValues("address", tags);
};
const location = getLocation();
const users = getTagsValues("p", tags);
const hashtags = getTagsValues("t", tags);
return (
<div
className={cn(
"group flex h-full flex-col rounded-[16px] p-2 hover:bg-muted",
className,
)}
>
<div className="relative overflow-hidden rounded-md">
<AspectRatio ratio={16 / 9} className="bg-muted">
<Image
src={image ?? ""}
alt={title}
width={250}
height={150}
unoptimized
className={cn(
"h-auto w-auto object-cover transition-all group-hover:scale-105",
"aspect-video",
)}
/>
</AspectRatio>
</div>
<div className="mt-3 flex-1 space-y-2 text-base">
<h3 className="line-clamp-2 font-semibold leading-5">{title}</h3>
<div className="flex flex-col items-start gap-y-1">
<div className="flex flex-col items-start gap-x-3 gap-y-1">
{!!startDate && (
<>
{startDate.getDay() === endDate?.getDay() ? (
<div className="center shrink-0 gap-x-1 text-xs text-muted-foreground">
<RxCalendar className="h-4 w-4 text-primary" />
<span>{formatDate(startDate, "ddd, MMM D")}</span>
</div>
) : (
<div className="center shrink-0 gap-x-1 text-xs text-muted-foreground">
<RxCalendar className="h-4 w-4 text-primary" />
<span>{formatDate(startDate, "ddd, MMM D")}</span>
{!!endDate && (
<>
{" "}
<span>-</span>{" "}
<span>{formatDate(endDate, "MMM D")}</span>
</>
)}
</div>
)}
<div className="center shrink-0 gap-x-1 text-xs text-muted-foreground">
<RxClock className="h-4 w-4 text-primary" />
<span>{formatDate(startDate, "h:mm a")}</span>
{!!endDate && (
<>
{" "}
<span>-</span>{" "}
<span>{formatDate(endDate, "h:mm a")}</span>
</>
)}
</div>
</>
)}
{!!users.length && (
<div className="center gap-x-1 text-xs text-muted-foreground">
<HiOutlineUsers className="h-4 w-4 text-primary" />
<span>{formatNumber(users.length)}</span>
</div>
)}
</div>
</div>
</div>
<div className="mt-1 flex">
<SmallProfileLine pubkey={pubkey} />
</div>
</div>
);
}
export function CardLoading({ className }: { className: string }) {
return (
<div
className={cn(
"group pointer-events-none flex flex-col space-y-3 rounded-[16px] p-2",
className,
)}
>
<div className="overflow-hidden rounded-md">
<AspectRatio ratio={16 / 9} className="bg-muted"></AspectRatio>
</div>
<div className="flex-1 space-y-2 text-base">
<Skeleton className="mb-2 h-4 w-1/3 bg-muted" />
<div className="flex flex-col items-start">
<div className="center gap-x-1 text-xs text-muted-foreground">
<Skeleton className="h-3 w-3 bg-muted" />
<Skeleton className="h-3 w-[50px] bg-muted" />
</div>
</div>
</div>
<div className="-mt-1 flex flex-wrap gap-2 overflow-x-hidden">
<Skeleton className="h-2 w-[50px] bg-muted" />
<Skeleton className="h-2 w-[40px] bg-muted" />
<Skeleton className="h-2 w-[30px] bg-muted" />
</div>
</div>
);
}

View File

@ -0,0 +1,43 @@
import Link from "next/link";
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
import useProfile from "@/lib/hooks/useProfile";
import { nip19 } from "nostr-tools";
import { getTwoLetters, getNameToShow } from "@/lib/utils";
import { Skeleton } from "@/components/ui/skeleton";
import { HiMiniChevronRight, HiCheckBadge } from "react-icons/hi2";
type ProfileInfoProps = {
pubkey: string;
};
export default function ProfileInfo({ pubkey }: ProfileInfoProps) {
const { profile } = useProfile(pubkey);
const npub = nip19.npubEncode(pubkey);
return (
<Link
href={`/${npub}`}
className="center group gap-x-2 rounded-sm rounded-r-full bg-background/50 pr-1 text-muted-foreground hover:shadow"
>
<Avatar className="center h-[16px] w-[16px] overflow-hidden rounded-[.25rem] bg-muted">
<AvatarImage src={profile?.image} alt={profile?.displayName} />
<AvatarFallback className="text-[8px]">
{getTwoLetters({ npub, profile })}
</AvatarFallback>
</Avatar>
<div className="flex items-center gap-1">
<span className="text-[12px]">{getNameToShow({ npub, profile })}</span>
{!!profile?.nip05 && <HiCheckBadge className="h-3 w-3 text-primary" />}
</div>
</Link>
);
}
export function LoadingProfileInfo() {
return (
<div className="center group gap-x-1">
<Avatar className="center h-[16px] w-[16px] overflow-hidden rounded-[.25rem] bg-muted @sm:h-[18px] @sm:w-[18px]"></Avatar>
<div className="space-y-1">
<Skeleton className="h-2 w-[70px] bg-muted" />
</div>
</div>
);
}