improving events page
This commit is contained in:
parent
181be8c902
commit
d0389ee84c
@ -0,0 +1,31 @@
|
|||||||
|
import { HiSignal } from "react-icons/hi2";
|
||||||
|
import Feed from "@/containers/Feed";
|
||||||
|
|
||||||
|
type AnnouncementsContainerProps = {
|
||||||
|
eventReference: string;
|
||||||
|
};
|
||||||
|
export default function AnnouncementsContainer({
|
||||||
|
eventReference,
|
||||||
|
}: AnnouncementsContainerProps) {
|
||||||
|
return (
|
||||||
|
<div className="overflow-hidden rounded-[1rem] border bg-muted p-[0.5rem]">
|
||||||
|
<div className="flex items-center gap-x-3 px-2 pb-2">
|
||||||
|
<HiSignal className="h-5 w-5" />
|
||||||
|
<h3 className="text-lg font-semibold">Announcements</h3>
|
||||||
|
</div>
|
||||||
|
<div className="w-full space-y-3">
|
||||||
|
<Feed
|
||||||
|
filter={{
|
||||||
|
kinds: [1],
|
||||||
|
["#a"]: [eventReference],
|
||||||
|
}}
|
||||||
|
empty={() => (
|
||||||
|
<div className="py-5 text-center text-muted-foreground">
|
||||||
|
<p>No Announcements yet</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
23
app/(app)/event/[naddr]/_components/AttendeesContainer.tsx
Normal file
23
app/(app)/event/[naddr]/_components/AttendeesContainer.tsx
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
import { HiOutlineUserGroup } from "react-icons/hi2";
|
||||||
|
|
||||||
|
import UserRow from "./UserRow";
|
||||||
|
type AttendeesContainerProps = {
|
||||||
|
attendees: string[];
|
||||||
|
};
|
||||||
|
export default function AttendeesContainer({
|
||||||
|
attendees,
|
||||||
|
}: AttendeesContainerProps) {
|
||||||
|
return (
|
||||||
|
<div className="overflow-hidden rounded-[1rem] border bg-muted p-[0.5rem]">
|
||||||
|
<div className="flex items-center gap-x-3 px-2 pb-2">
|
||||||
|
<HiOutlineUserGroup className="h-5 w-5" />
|
||||||
|
<h3 className="text-lg font-semibold">Attendees</h3>
|
||||||
|
</div>
|
||||||
|
<ul className="max-h-[200px] overflow-hidden">
|
||||||
|
{attendees.map((pubkey) => (
|
||||||
|
<UserRow key={pubkey} pubkey={pubkey} />
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
@ -27,7 +27,7 @@ import { formatDate } from "@/lib/utils/dates";
|
|||||||
import SmallCalendarIcon from "@/components/EventIcons/DateIcon";
|
import SmallCalendarIcon from "@/components/EventIcons/DateIcon";
|
||||||
import LocationIcon from "@/components/EventIcons/LocationIcon";
|
import LocationIcon from "@/components/EventIcons/LocationIcon";
|
||||||
|
|
||||||
const EditEventModal = dynamic(() => import("@/components/Modals/EditEvent"), {
|
const RSVPButton = dynamic(() => import("./RSVPButton"), {
|
||||||
ssr: false,
|
ssr: false,
|
||||||
});
|
});
|
||||||
const CreateListEvent = dynamic(
|
const CreateListEvent = dynamic(
|
||||||
@ -48,7 +48,7 @@ export default function Header({ event }: { event: NDKEvent }) {
|
|||||||
const [hasValidPayment, setHasValidPayment] = useState(false);
|
const [hasValidPayment, setHasValidPayment] = useState(false);
|
||||||
const { pubkey, tags } = event;
|
const { pubkey, tags } = event;
|
||||||
const { profile } = useProfile(pubkey);
|
const { profile } = useProfile(pubkey);
|
||||||
|
const eventReference = event.encode();
|
||||||
const title = getTagValues("name", tags) ?? "Untitled";
|
const title = getTagValues("name", tags) ?? "Untitled";
|
||||||
const image =
|
const image =
|
||||||
getTagValues("image", tags) ??
|
getTagValues("image", tags) ??
|
||||||
@ -170,35 +170,7 @@ export default function Header({ event }: { event: NDKEvent }) {
|
|||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
)} */}
|
)} */}
|
||||||
<Button
|
<RSVPButton eventReference={eventReference} />
|
||||||
// onClick={() =>
|
|
||||||
// modal?.show(
|
|
||||||
// <ConfirmModal
|
|
||||||
// title={`Subscribe to ${title}`}
|
|
||||||
// onConfirm={handleSendZap}
|
|
||||||
// ctaBody={
|
|
||||||
// <>
|
|
||||||
// <span>Zap to Subscribe</span>
|
|
||||||
// <HiOutlineLightningBolt className="h-4 w-4" />
|
|
||||||
// </>
|
|
||||||
// }
|
|
||||||
// >
|
|
||||||
// <p className="text-muted-forground">
|
|
||||||
// {`Pay ${priceInBTC} BTC (${formatNumber(
|
|
||||||
// btcToSats(priceInBTC),
|
|
||||||
// )} sats) for year long access until ${formatDate(
|
|
||||||
// new Date(
|
|
||||||
// new Date().setFullYear(new Date().getFullYear() + 1),
|
|
||||||
// ),
|
|
||||||
// "MMM Do, YYYY",
|
|
||||||
// )}`}
|
|
||||||
// </p>
|
|
||||||
// </ConfirmModal>,
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
>
|
|
||||||
RSVP
|
|
||||||
</Button>
|
|
||||||
{/* {!isMember &&
|
{/* {!isMember &&
|
||||||
(hasValidPayment ? (
|
(hasValidPayment ? (
|
||||||
<Button variant={"outline"}>Pending Sync</Button>
|
<Button variant={"outline"}>Pending Sync</Button>
|
||||||
@ -240,7 +212,7 @@ export default function Header({ event }: { event: NDKEvent }) {
|
|||||||
<div className="flex flex-col gap-x-6 gap-y-3 pt-1 @md:pt-2 @xl:flex-row">
|
<div className="flex flex-col gap-x-6 gap-y-3 pt-1 @md:pt-2 @xl:flex-row">
|
||||||
<div className="flex-1">
|
<div className="flex-1">
|
||||||
{!!description && (
|
{!!description && (
|
||||||
<p className="line-clamp-3 text-sm text-muted-foreground @md:text-sm">
|
<p className="text-sm text-muted-foreground @md:text-sm">
|
||||||
{description}
|
{description}
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
|
21
app/(app)/event/[naddr]/_components/HostsContainer.tsx
Normal file
21
app/(app)/event/[naddr]/_components/HostsContainer.tsx
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { HiOutlineUsers } from "react-icons/hi2";
|
||||||
|
|
||||||
|
import UserRow from "./UserRow";
|
||||||
|
type HostsContainerProps = {
|
||||||
|
hosts: string[];
|
||||||
|
};
|
||||||
|
export default function HostsContainer({ hosts }: HostsContainerProps) {
|
||||||
|
return (
|
||||||
|
<div className="overflow-hidden rounded-[1rem] border bg-muted p-[0.5rem]">
|
||||||
|
<div className="flex items-center gap-x-3 px-2 pb-2">
|
||||||
|
<HiOutlineUsers className="h-5 w-5" />
|
||||||
|
<h3 className="text-lg font-semibold">Hosts</h3>
|
||||||
|
</div>
|
||||||
|
<ul>
|
||||||
|
{hosts.map((pubkey) => (
|
||||||
|
<UserRow key={pubkey} pubkey={pubkey} />
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
26
app/(app)/event/[naddr]/_components/LocationContainer.tsx
Normal file
26
app/(app)/event/[naddr]/_components/LocationContainer.tsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import LocationBoxRaw from "@/components/LocationPreview/LocationBoxRaw";
|
||||||
|
import { HiOutlineMapPin, HiCheckBadge, HiOutlineUsers } from "react-icons/hi2";
|
||||||
|
|
||||||
|
type LocationContainerProps = {
|
||||||
|
address: string;
|
||||||
|
geohash: string;
|
||||||
|
};
|
||||||
|
export default function LocationContainer({
|
||||||
|
address,
|
||||||
|
geohash,
|
||||||
|
}: LocationContainerProps) {
|
||||||
|
return (
|
||||||
|
<div className="overflow-hidden rounded-[1rem] border bg-muted p-[0.5rem] @container">
|
||||||
|
<div className="flex items-center gap-x-3 px-2 pb-2">
|
||||||
|
<HiOutlineMapPin className="h-5 w-5" />
|
||||||
|
<h3 className="text-lg font-semibold">Location</h3>
|
||||||
|
</div>
|
||||||
|
<div className="h-[150px] overflow-hidden rounded-lg">
|
||||||
|
<LocationBoxRaw geohash={geohash} address={address} />
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center @lg:px-2 @lg:pt-1">
|
||||||
|
<p className="pt-1.5 text-xs text-muted-foreground">{address}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
19
app/(app)/event/[naddr]/_components/RSVPButton.tsx
Normal file
19
app/(app)/event/[naddr]/_components/RSVPButton.tsx
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { useModal } from "@/app/_providers/modal/provider";
|
||||||
|
import RSVPModal from "@/components/Modals/RSVP";
|
||||||
|
|
||||||
|
type RSVPButtonProps = {
|
||||||
|
eventReference: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function RSVPButton({ eventReference }: RSVPButtonProps) {
|
||||||
|
const modal = useModal();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
onClick={() => modal?.show(<RSVPModal eventReference={eventReference} />)}
|
||||||
|
>
|
||||||
|
RSVP
|
||||||
|
</Button>
|
||||||
|
);
|
||||||
|
}
|
51
app/(app)/event/[naddr]/_components/UserRow.tsx
Normal file
51
app/(app)/event/[naddr]/_components/UserRow.tsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import Link from "next/link";
|
||||||
|
import { HiOutlineMapPin, HiCheckBadge, HiOutlineUsers } from "react-icons/hi2";
|
||||||
|
import { Avatar, AvatarImage, AvatarFallback } from "@/components/ui/avatar";
|
||||||
|
import useProfile from "@/lib/hooks/useProfile";
|
||||||
|
import { getTwoLetters, getNameToShow } from "@/lib/utils";
|
||||||
|
import { nip19 } from "nostr-tools";
|
||||||
|
|
||||||
|
export default function UserRow({ pubkey }: { pubkey: string }) {
|
||||||
|
const npub = nip19.npubEncode(pubkey);
|
||||||
|
const { profile } = useProfile(pubkey);
|
||||||
|
return (
|
||||||
|
<li className="flex items-center">
|
||||||
|
<Link href={`/${pubkey}`} className="center group gap-x-3">
|
||||||
|
<Avatar className="center h-9 w-9 overflow-hidden rounded-sm bg-muted @md:h-10 @md:w-10">
|
||||||
|
<AvatarImage src={profile?.image} alt={profile?.displayName} />
|
||||||
|
<AvatarFallback className="text-xs">
|
||||||
|
{getTwoLetters({ npub, profile })}
|
||||||
|
</AvatarFallback>
|
||||||
|
</Avatar>
|
||||||
|
{profile?.displayName || profile?.name ? (
|
||||||
|
<div className="flex flex-col gap-0">
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<span className="text-sm font-medium text-foreground group-hover:underline">
|
||||||
|
{getNameToShow({ npub, profile })}
|
||||||
|
</span>
|
||||||
|
{!!profile?.nip05 && (
|
||||||
|
<HiCheckBadge className="h-4 w-4 text-primary" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
{!!profile.nip05 && (
|
||||||
|
<span className="text-[11px] text-muted-foreground">
|
||||||
|
{profile.nip05}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="flex items-center gap-1">
|
||||||
|
<span className="text-sm uppercase text-foreground group-hover:underline">
|
||||||
|
{getNameToShow({ npub, profile })}
|
||||||
|
</span>
|
||||||
|
{!!profile?.nip05 && (
|
||||||
|
<HiCheckBadge className="h-4 w-4 text-primary" />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
);
|
||||||
|
}
|
@ -1,17 +1,23 @@
|
|||||||
"use client";
|
"use client";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import Image from "next/image";
|
import Image from "next/image";
|
||||||
|
import Link from "next/link";
|
||||||
import { nip19 } from "nostr-tools";
|
import { nip19 } from "nostr-tools";
|
||||||
import useEvents from "@/lib/hooks/useEvents";
|
import useEvents from "@/lib/hooks/useEvents";
|
||||||
import Spinner from "@/components/spinner";
|
import Spinner from "@/components/spinner";
|
||||||
import {
|
import {
|
||||||
getTagAllValues,
|
getTagAllValues,
|
||||||
getTagValues,
|
getTagValues,
|
||||||
|
getTagsAllValues,
|
||||||
getTagsValues,
|
getTagsValues,
|
||||||
} from "@/lib/nostr/utils";
|
} from "@/lib/nostr/utils";
|
||||||
import Feed from "@/containers/Feed";
|
|
||||||
import Header from "./_components/Header";
|
import Header from "./_components/Header";
|
||||||
import LocationPreview from "@/components/LocationPreview";
|
import LocationPreview from "@/components/LocationPreview";
|
||||||
|
import HostsContainer from "./_components/HostsContainer";
|
||||||
|
import LocationContainer from "./_components/LocationContainer";
|
||||||
|
import AnnouncementsContainer from "./_components/AnnouncementsContainer";
|
||||||
|
import AttendeesContainer from "./_components/AttendeesContainer";
|
||||||
|
|
||||||
export default function EventPage({
|
export default function EventPage({
|
||||||
params: { naddr },
|
params: { naddr },
|
||||||
@ -42,35 +48,37 @@ export default function EventPage({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
const noteIds = getTagsValues("e", event.tags).filter(Boolean);
|
const { tags } = event;
|
||||||
const location = getTagAllValues("location", event.tags)[0]
|
const eventReference = event.encode();
|
||||||
? getTagAllValues("location", event.tags)
|
const noteIds = getTagsValues("e", tags).filter(Boolean);
|
||||||
: getTagAllValues("address", event.tags);
|
const location = getTagAllValues("location", tags)[0]
|
||||||
const geohash = getTagValues("g", event.tags);
|
? getTagAllValues("location", tags)
|
||||||
|
: getTagAllValues("address", tags);
|
||||||
|
const geohash = getTagValues("g", tags);
|
||||||
|
const hosts = getTagsAllValues("p", tags)
|
||||||
|
.filter(([pubkey, relay, role]) => role === "host")
|
||||||
|
.map(([pubkey]) => pubkey)
|
||||||
|
.filter(Boolean);
|
||||||
|
const attendees = getTagsAllValues("p", tags)
|
||||||
|
.map(([pubkey]) => pubkey)
|
||||||
|
.filter(Boolean);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="relative mx-auto max-w-5xl space-y-4 p-2 sm:p-4">
|
<div className="relative mx-auto max-w-5xl space-y-4 p-2 @container sm:p-4">
|
||||||
<Header event={event} />
|
<Header event={event} />
|
||||||
<div className="relative overflow-hidden rounded-[1rem] border bg-muted p-[0.5rem] @container">
|
<div className="flex flex-col gap-4 @2xl:flex-row-reverse">
|
||||||
<div className="flex flex-col gap-3 @xl:flex-row-reverse">
|
<div className="flex min-w-[250px] flex-1 flex-col gap-4">
|
||||||
{!!location && !!geohash && (
|
{!!location && !!geohash && (
|
||||||
<LocationPreview
|
<LocationContainer
|
||||||
geohash={geohash}
|
|
||||||
address={location[0] as string}
|
address={location[0] as string}
|
||||||
|
geohash={geohash}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<div className="flex-1 space-y-3 overflow-hidden rounded-[0.5rem] p-0">
|
<HostsContainer hosts={hosts} />
|
||||||
<Feed
|
<AttendeesContainer attendees={attendees} />
|
||||||
filter={{
|
</div>
|
||||||
ids: noteIds,
|
<div className="max-w-2xl grow">
|
||||||
}}
|
<AnnouncementsContainer eventReference={eventReference} />
|
||||||
empty={() => (
|
|
||||||
<div className="py-5 text-center text-muted-foreground">
|
|
||||||
<p>No Announcements yet</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
58
components/LocationPreview/LocationBoxRaw.tsx
Normal file
58
components/LocationPreview/LocationBoxRaw.tsx
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
"use client";
|
||||||
|
|
||||||
|
import { useLoadScript, GoogleMap } from "@react-google-maps/api";
|
||||||
|
import type { NextPage } from "next";
|
||||||
|
import { useMemo } from "react";
|
||||||
|
import {
|
||||||
|
Card,
|
||||||
|
CardContent,
|
||||||
|
CardFooter,
|
||||||
|
CardHeader,
|
||||||
|
CardTitle,
|
||||||
|
} from "@/components/ui/card";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import Geohash from "latlon-geohash";
|
||||||
|
import { HiMapPin } from "react-icons/hi2";
|
||||||
|
|
||||||
|
type LocationPreviewProps = {
|
||||||
|
geohash: string;
|
||||||
|
address: string;
|
||||||
|
className?: string;
|
||||||
|
};
|
||||||
|
export default function LocationBoxRaw({
|
||||||
|
geohash,
|
||||||
|
address,
|
||||||
|
className,
|
||||||
|
}: LocationPreviewProps) {
|
||||||
|
const libraries = useMemo(() => ["places"], []);
|
||||||
|
const { lat, lon } = Geohash.decode(geohash);
|
||||||
|
const mapCenter = useMemo(() => ({ lat, lng: lon }), []);
|
||||||
|
|
||||||
|
const mapOptions = useMemo<google.maps.MapOptions>(
|
||||||
|
() => ({
|
||||||
|
disableDefaultUI: true,
|
||||||
|
clickableIcons: true,
|
||||||
|
scrollwheel: false,
|
||||||
|
}),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
|
||||||
|
const { isLoaded } = useLoadScript({
|
||||||
|
googleMapsApiKey: process.env.NEXT_PUBLIC_GOOGLE_MAPS_KEY as string,
|
||||||
|
libraries: libraries as any,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!isLoaded) {
|
||||||
|
return <div className="h-full w-full bg-muted"></div>;
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<GoogleMap
|
||||||
|
options={mapOptions}
|
||||||
|
zoom={14}
|
||||||
|
center={mapCenter}
|
||||||
|
mapTypeId={google.maps.MapTypeId.ROADMAP}
|
||||||
|
mapContainerStyle={{ width: "100%", height: "100%" }}
|
||||||
|
onLoad={() => console.log("Map Component Loaded...")}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
@ -98,6 +98,7 @@ export default function CreateCalendarEventModal() {
|
|||||||
["start", toUnix(convertToTimezone(startDate, timezone)).toString()],
|
["start", toUnix(convertToTimezone(startDate, timezone)).toString()],
|
||||||
["end", toUnix(convertToTimezone(endDate, timezone)).toString()],
|
["end", toUnix(convertToTimezone(endDate, timezone)).toString()],
|
||||||
["start_tzid", timezone],
|
["start_tzid", timezone],
|
||||||
|
["p", currentUser.pubkey, "", "host"],
|
||||||
];
|
];
|
||||||
|
|
||||||
if (location) {
|
if (location) {
|
||||||
|
92
components/Modals/RSVP.tsx
Normal file
92
components/Modals/RSVP.tsx
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
"use client";
|
||||||
|
import { useState } from "react";
|
||||||
|
import Template from "./Template";
|
||||||
|
import { Button } from "@/components/ui/button";
|
||||||
|
import { toast } from "sonner";
|
||||||
|
import { useModal } from "@/app/_providers/modal/provider";
|
||||||
|
import { randomId } from "@/lib/nostr";
|
||||||
|
import { unixTimeNowInSeconds } from "@/lib/nostr/dates";
|
||||||
|
// import { useKeys } from "@/app/_providers/keysProvider";
|
||||||
|
import useCurrentUser from "@/lib/hooks/useCurrentUser";
|
||||||
|
import { createEvent } from "@/lib/actions/create";
|
||||||
|
import { useNDK } from "@/app/_providers/ndk";
|
||||||
|
|
||||||
|
type RSVPModalProps = {
|
||||||
|
eventReference: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
const statusMap = {
|
||||||
|
accept: "accepted",
|
||||||
|
maybe: "tentative",
|
||||||
|
decline: "declined",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default function RSVPModal({ eventReference }: RSVPModalProps) {
|
||||||
|
const modal = useModal();
|
||||||
|
const { ndk } = useNDK();
|
||||||
|
const { currentUser } = useCurrentUser();
|
||||||
|
const [loading, setLoading] = useState({
|
||||||
|
accept: false,
|
||||||
|
maybe: false,
|
||||||
|
decline: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
async function handleRSVP(type: "accept" | "maybe" | "decline") {
|
||||||
|
if (!ndk || !currentUser) return;
|
||||||
|
setLoading((prev) => ({ ...prev, [type]: true }));
|
||||||
|
|
||||||
|
try {
|
||||||
|
const random = randomId();
|
||||||
|
const tags: string[][] = [
|
||||||
|
["d", random],
|
||||||
|
["a", eventReference],
|
||||||
|
["L", "status"],
|
||||||
|
["l", statusMap[type], "status"],
|
||||||
|
];
|
||||||
|
const event = await createEvent(ndk, {
|
||||||
|
content: "",
|
||||||
|
kind: 31925,
|
||||||
|
tags,
|
||||||
|
});
|
||||||
|
if (event) {
|
||||||
|
toast.success("Event Created!");
|
||||||
|
modal?.hide();
|
||||||
|
} else {
|
||||||
|
toast.error("An error occured");
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.log("Err", err);
|
||||||
|
} finally {
|
||||||
|
setLoading({ accept: false, maybe: false, decline: false });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Template title="RSVP to Event" className="md:max-w-[400px]">
|
||||||
|
<div className="flex flex-col gap-y-5">
|
||||||
|
<Button
|
||||||
|
loading={loading.accept}
|
||||||
|
onClick={() => handleRSVP("accept")}
|
||||||
|
className="w-full gap-x-1"
|
||||||
|
>
|
||||||
|
<span>Accept</span>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
loading={loading.maybe}
|
||||||
|
onClick={() => handleRSVP("maybe")}
|
||||||
|
variant={"outline"}
|
||||||
|
className="w-full gap-x-1"
|
||||||
|
>
|
||||||
|
<span>Maybe</span>
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
loading={loading.decline}
|
||||||
|
onClick={() => handleRSVP("decline")}
|
||||||
|
variant={"destructive"}
|
||||||
|
className="w-full gap-x-1"
|
||||||
|
>
|
||||||
|
<span>Decline</span>
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
</Template>
|
||||||
|
);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user