added edit profile modal
This commit is contained in:
parent
6fb452f56b
commit
b0017440a0
@ -11,7 +11,9 @@ import ProfileFeed from "./_components/Feed";
|
|||||||
import Subscriptions from "./_components/Subscriptions";
|
import Subscriptions from "./_components/Subscriptions";
|
||||||
import { nip19 } from "nostr-tools";
|
import { nip19 } from "nostr-tools";
|
||||||
import useLists from "@/lib/hooks/useLists";
|
import useLists from "@/lib/hooks/useLists";
|
||||||
|
import EditProfileModal from "@/components/Modals/EditProfile";
|
||||||
|
import { useModal } from "@/app/_providers/modal/provider";
|
||||||
|
import useCurrentUser from "@/lib/hooks/useCurrentUser";
|
||||||
export default function ProfilePage({
|
export default function ProfilePage({
|
||||||
params: { npub },
|
params: { npub },
|
||||||
}: {
|
}: {
|
||||||
@ -19,10 +21,9 @@ export default function ProfilePage({
|
|||||||
npub: string;
|
npub: string;
|
||||||
};
|
};
|
||||||
}) {
|
}) {
|
||||||
|
const modal = useModal();
|
||||||
|
const { currentUser, follows } = useCurrentUser();
|
||||||
const [activeTab, setActiveTab] = useState("feed");
|
const [activeTab, setActiveTab] = useState("feed");
|
||||||
if (npub === "service-worker.js") {
|
|
||||||
throw new Error("Invalid list");
|
|
||||||
}
|
|
||||||
const { type, data } = nip19.decode(npub);
|
const { type, data } = nip19.decode(npub);
|
||||||
|
|
||||||
if (type !== "npub") {
|
if (type !== "npub") {
|
||||||
@ -72,10 +73,26 @@ export default function ProfilePage({
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
<Button size={"sm"} className="rounded-sm px-5 sm:hidden">
|
<div className="flex items-center gap-3">
|
||||||
Follow
|
{currentUser?.pubkey === pubkey && (
|
||||||
</Button>
|
<Button
|
||||||
<Button className="rounded-sm px-5 max-sm:hidden">Follow</Button>
|
onClick={() => modal?.show(<EditProfileModal />)}
|
||||||
|
variant={"outline"}
|
||||||
|
className="rounded-sm px-5 max-sm:h-8 max-sm:text-xs"
|
||||||
|
>
|
||||||
|
Edit
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
{!follows.includes(pubkey) && (
|
||||||
|
<Button
|
||||||
|
onClick={() => modal?.show(<EditProfileModal />)}
|
||||||
|
variant={"default"}
|
||||||
|
className="rounded-sm px-5 max-sm:h-8 max-sm:text-xs"
|
||||||
|
>
|
||||||
|
Follow
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="mx-auto max-w-[800px] space-y-1 px-4">
|
<div className="mx-auto max-w-[800px] space-y-1 px-4">
|
||||||
<div className="flex items-center gap-x-1.5 lg:gap-x-2.5">
|
<div className="flex items-center gap-x-1.5 lg:gap-x-2.5">
|
||||||
|
121
components/Modals/EditProfile.tsx
Normal file
121
components/Modals/EditProfile.tsx
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
import { useEffect, useState } from "react";
|
||||||
|
import FormModal from "./FormModal";
|
||||||
|
import { z } from "zod";
|
||||||
|
import useEvents from "@/lib/hooks/useEvents";
|
||||||
|
import { createEvent } 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 useCurrentUser from "@/lib/hooks/useCurrentUser";
|
||||||
|
|
||||||
|
const EditProfileSchema = z.object({
|
||||||
|
display_name: z.string().optional(),
|
||||||
|
name: z.string().optional(),
|
||||||
|
image: z.string().optional(),
|
||||||
|
about: z.string().optional(),
|
||||||
|
banner: z.string().optional(),
|
||||||
|
website: z.string().optional(),
|
||||||
|
nip05: z.string().optional(),
|
||||||
|
lud16: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
|
type EditProfileType = z.infer<typeof EditProfileSchema>;
|
||||||
|
|
||||||
|
export default function EditProfileModal() {
|
||||||
|
const modal = useModal();
|
||||||
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [sent, setSent] = useState(false);
|
||||||
|
const { ndk } = useNDK();
|
||||||
|
const { currentUser, updateUser } = useCurrentUser();
|
||||||
|
const { events } = useEvents({
|
||||||
|
filter: {
|
||||||
|
kinds: [0],
|
||||||
|
authors: [currentUser?.pubkey ?? ""],
|
||||||
|
since: unixTimeNowInSeconds() - 10,
|
||||||
|
limit: 1,
|
||||||
|
},
|
||||||
|
enabled: sent,
|
||||||
|
});
|
||||||
|
useEffect(() => {
|
||||||
|
if (events.length) {
|
||||||
|
console.log("Done!");
|
||||||
|
setIsLoading(false);
|
||||||
|
toast.success("Profile Updated!");
|
||||||
|
modal?.hide();
|
||||||
|
}
|
||||||
|
}, [events]);
|
||||||
|
|
||||||
|
async function handleSubmit(userData: EditProfileType) {
|
||||||
|
setIsLoading(true);
|
||||||
|
const content = JSON.stringify(userData);
|
||||||
|
const result = await createEvent(ndk!, {
|
||||||
|
content,
|
||||||
|
kind: 0,
|
||||||
|
tags: [],
|
||||||
|
});
|
||||||
|
if (result) {
|
||||||
|
updateUser(JSON.stringify({ ...userData, npub: currentUser?.npub }));
|
||||||
|
}
|
||||||
|
setSent(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FormModal
|
||||||
|
title="Edit List"
|
||||||
|
fields={[
|
||||||
|
{
|
||||||
|
label: "Display name",
|
||||||
|
type: "input",
|
||||||
|
slug: "display_name",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Name",
|
||||||
|
type: "input",
|
||||||
|
slug: "name",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Image",
|
||||||
|
type: "input",
|
||||||
|
slug: "image",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "About",
|
||||||
|
type: "text-area",
|
||||||
|
slug: "about",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Banner",
|
||||||
|
type: "input",
|
||||||
|
slug: "banner",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Website",
|
||||||
|
type: "input",
|
||||||
|
slug: "website",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "NIP-05",
|
||||||
|
type: "input",
|
||||||
|
slug: "nip05",
|
||||||
|
placeholder: "name@example.com",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: "Bitcoin lightning address (lud16)",
|
||||||
|
type: "input",
|
||||||
|
slug: "lud16",
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
defaultValues={{
|
||||||
|
...currentUser?.profile,
|
||||||
|
display_name: currentUser?.profile?.displayName,
|
||||||
|
}}
|
||||||
|
formSchema={EditProfileSchema}
|
||||||
|
onSubmit={handleSubmit}
|
||||||
|
isSubmitting={isLoading}
|
||||||
|
cta={{
|
||||||
|
text: "Save Changes",
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
@ -10,6 +10,17 @@ import useCurrentUser from "@/lib/hooks/useCurrentUser";
|
|||||||
import { HiOutlineLightningBolt } from "react-icons/hi";
|
import { HiOutlineLightningBolt } from "react-icons/hi";
|
||||||
import { RiSubtractFill, RiAddFill } from "react-icons/ri";
|
import { RiSubtractFill, RiAddFill } from "react-icons/ri";
|
||||||
import { formatCount } from "@/lib/utils";
|
import { formatCount } from "@/lib/utils";
|
||||||
|
import { Textarea } from "@/components/ui/textarea";
|
||||||
|
import {
|
||||||
|
Form,
|
||||||
|
FormControl,
|
||||||
|
FormDescription,
|
||||||
|
FormField,
|
||||||
|
FormItem,
|
||||||
|
FormLabel,
|
||||||
|
FormMessage,
|
||||||
|
} from "@/components/ui/form";
|
||||||
|
|
||||||
const intervals = [
|
const intervals = [
|
||||||
10, 25, 50, 75, 100, 150, 200, 250, 350, 500, 750, 1000, 1250, 1500, 2_000,
|
10, 25, 50, 75, 100, 150, 200, 250, 350, 500, 750, 1000, 1250, 1500, 2_000,
|
||||||
2_500, 3_000, 3_500, 4_000, 5_000, 6_000, 7_500, 10_000, 12_500, 15_000,
|
2_500, 3_000, 3_500, 4_000, 5_000, 6_000, 7_500, 10_000, 12_500, 15_000,
|
||||||
@ -20,6 +31,7 @@ export default function ZapPicker() {
|
|||||||
const { loginWithNip07 } = useNDK();
|
const { loginWithNip07 } = useNDK();
|
||||||
const { loginWithPubkey, currentUser } = useCurrentUser();
|
const { loginWithPubkey, currentUser } = useCurrentUser();
|
||||||
const [isLoading, setIsLoading] = useState(false);
|
const [isLoading, setIsLoading] = useState(false);
|
||||||
|
const [note, setNote] = useState("");
|
||||||
const modal = useModal();
|
const modal = useModal();
|
||||||
const [sats, setSats] = useState(2000);
|
const [sats, setSats] = useState(2000);
|
||||||
|
|
||||||
@ -59,6 +71,15 @@ export default function ZapPicker() {
|
|||||||
Satoshis
|
Satoshis
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="">
|
||||||
|
<FormLabel>Note</FormLabel>
|
||||||
|
<Textarea
|
||||||
|
placeholder="Add a note..."
|
||||||
|
onChange={(e) => setNote(e.target.value)}
|
||||||
|
value={note}
|
||||||
|
className="auto-sizing"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
size="icon"
|
size="icon"
|
||||||
|
@ -19,7 +19,7 @@ const UserSchema = z.object({
|
|||||||
name: z.string().optional(),
|
name: z.string().optional(),
|
||||||
username: z.string().optional(),
|
username: z.string().optional(),
|
||||||
display_name: z.string().optional(),
|
display_name: z.string().optional(),
|
||||||
picture: z.string().optional(),
|
image: z.string().optional(),
|
||||||
banner: z.string().optional(),
|
banner: z.string().optional(),
|
||||||
about: z.string().optional(),
|
about: z.string().optional(),
|
||||||
website: z.string().optional(),
|
website: z.string().optional(),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user