diff --git a/src/components/profile/DataTables/UserProgressTable.js b/src/components/profile/DataTables/UserProgressTable.js index 13cf250..e804b22 100644 --- a/src/components/profile/DataTables/UserProgressTable.js +++ b/src/components/profile/DataTables/UserProgressTable.js @@ -107,12 +107,18 @@ const UserProgressTable = ({ session, ndk, windowWidth }) => { </div> ); - const dateTemplate = (rowData) => ( - <div className="flex items-center gap-2"> - <i className="pi pi-calendar text-gray-400"></i> - <span>{formatDateTime(rowData.date)}</span> - </div> - ); + const dateTemplate = (rowData) => { + // Adjust for timezone offset like in the contribution chart + const date = new Date(rowData.date); + const adjustedDate = new Date(date.getTime() - date.getTimezoneOffset() * 60000); + + return ( + <div className="flex items-center gap-2"> + <i className="pi pi-calendar text-gray-400"></i> + <span>{formatDateTime(adjustedDate)}</span> + </div> + ); + }; if (!session || !session?.user || !ndk) { return <div className='w-full h-full flex items-center justify-center'><ProgressSpinner /></div>; diff --git a/src/components/profile/DataTables/UserPurchaseTable.js b/src/components/profile/DataTables/UserPurchaseTable.js index bdac7d8..db764b1 100644 --- a/src/components/profile/DataTables/UserPurchaseTable.js +++ b/src/components/profile/DataTables/UserPurchaseTable.js @@ -34,12 +34,18 @@ const UserPurchaseTable = ({ session, windowWidth }) => { </div> ); - const dateTemplate = (rowData) => ( - <div className="flex items-center gap-2"> - <i className="pi pi-calendar text-gray-400"></i> - <span>{formatDateTime(rowData?.createdAt)}</span> - </div> - ); + const dateTemplate = (rowData) => { + // Adjust for timezone offset like in the contribution chart + const date = new Date(rowData?.createdAt); + const adjustedDate = new Date(date.getTime() - date.getTimezoneOffset() * 60000); + + return ( + <div className="flex items-center gap-2"> + <i className="pi pi-calendar text-gray-400"></i> + <span>{formatDateTime(adjustedDate)}</span> + </div> + ); + }; return ( session && session?.user && ( diff --git a/src/components/profile/UserProfile.js b/src/components/profile/UserProfile.js index 6963822..ff7c437 100644 --- a/src/components/profile/UserProfile.js +++ b/src/components/profile/UserProfile.js @@ -1,19 +1,11 @@ -import React, { useRef, useState, useEffect } from "react"; -import { Menu } from "primereact/menu"; -import { useImageProxy } from "@/hooks/useImageProxy"; +import React, { useState, useEffect } from "react"; import { useSession } from 'next-auth/react'; import { useNDKContext } from "@/context/NDKContext"; -import { formatDateTime } from "@/utils/time"; -import { Tooltip } from "primereact/tooltip"; -import { nip19 } from "nostr-tools"; -import Image from "next/image"; +import UserProfileCard from "@/components/profile/UserProfileCard"; import CombinedContributionChart from "@/components/charts/CombinedContributionChart"; -import GithubContributionChart from "@/components/charts/GithubContributionChart"; import ActivityContributionChart from "@/components/charts/ActivityContributionChart"; -import GithubContributionChartDisabled from "@/components/charts/GithubContributionChartDisabled"; import useCheckCourseProgress from "@/hooks/tracking/useCheckCourseProgress"; import useWindowWidth from "@/hooks/useWindowWidth"; -import { useToast } from "@/hooks/useToast"; import UserProgress from "@/components/profile/progress/UserProgress"; import UserProgressTable from '@/components/profile/DataTables/UserProgressTable'; import UserPurchaseTable from '@/components/profile/DataTables/UserPurchaseTable'; @@ -23,17 +15,9 @@ const UserProfile = () => { const [user, setUser] = useState(null); const [account, setAccount] = useState(null); const { data: session } = useSession(); - const { returnImageProxy } = useImageProxy(); const { ndk, addSigner } = useNDKContext(); - const { showToast } = useToast(); - const menu = useRef(null); useCheckCourseProgress(); - const copyToClipboard = (text) => { - navigator.clipboard.writeText(text); - showToast("success", "Copied", "Copied to clipboard"); - }; - useEffect(() => { if (session?.user) { console.log("Session", session) @@ -45,43 +29,6 @@ const UserProfile = () => { } }, [session]); - const header = ( - <div className="flex flex-wrap align-items-center justify-content-between gap-2"> - <span className="text-xl text-900 font-bold text-[#f8f8ff]">Progress</span> - </div> - ); - - const purchasesHeader = ( - <div className="flex flex-wrap align-items-center justify-content-between gap-2"> - <span className="text-xl text-900 font-bold text-[#f8f8ff]">Purchases</span> - </div> - ); - - const menuItems = [ - ...(user?.privkey ? [{ - label: 'Copy nsec', - icon: 'pi pi-key', - command: () => { - const privkeyBuffer = Buffer.from(user.privkey, 'hex'); - copyToClipboard(nip19.nsecEncode(privkeyBuffer)); - } - }] : []), - { - label: 'Copy npub', - icon: 'pi pi-user', - command: () => { - if (user.pubkey) { - copyToClipboard(nip19.npubEncode(user?.pubkey)); - } - } - }, - { - label: 'Open Nostr Profile', - icon: 'pi pi-external-link', - command: () => window.open(`https://nostr.com/${nip19.npubEncode(user?.pubkey)}`, '_blank') - } - ]; - return ( user && ( <div className="p-4"> @@ -91,48 +38,7 @@ const UserProfile = () => { ) } <div className="w-full flex flex-col justify-center mx-auto"> - <div className="relative flex w-full items-center justify-center"> - <Image - alt="user's avatar" - src={returnImageProxy(user.avatar, user?.pubkey || "")} - width={100} - height={100} - className="rounded-full my-4" - /> - <div className="absolute top-8 right-80 max-tab:right-20 max-mob:left-0"> - <i - className="pi pi-ellipsis-h text-2xl cursor-pointer" - onClick={(e) => menu.current.toggle(e)} - /> - <Menu - model={menuItems} - popup - ref={menu} - id="profile-options-menu" - /> - </div> - </div> - - - <h1 className="text-center text-2xl my-2"> - {user.username || user?.name || user?.email || "Anon"} - </h1> - {user.pubkey && ( - <h2 className="text-center text-xl my-2 truncate max-tab:px-4 max-mob:px-4"> - <Tooltip target=".pubkey-tooltip" content={"this is your nostr npub"} /> - {nip19.npubEncode(user.pubkey)} <i className="pi pi-question-circle text-xl pubkey-tooltip" /> - </h2> - )} - {user?.lightningAddress && ( - <h3 className="w-fit mx-auto text-center text-xl my-2 bg-gray-800 rounded-lg p-4"> - <span className="font-bold">Lightning Address:</span> {user.lightningAddress.name}@plebdevs.com <i className="pi pi-copy cursor-pointer hover:text-gray-400" onClick={() => copyToClipboard(user.lightningAddress.name + "@plebdevs.com")} /> - </h3> - )} - {user?.nip05 && ( - <h3 className="w-fit mx-auto text-center text-xl my-2 bg-gray-800 rounded-lg p-4"> - <span className="font-bold">NIP-05:</span> {user.nip05.name}@plebdevs.com <i className="pi pi-copy cursor-pointer hover:text-gray-400" onClick={() => copyToClipboard(user.nip05.name + "@plebdevs.com")} /> - </h3> - )} + <UserProfileCard user={user} /> {account && account?.provider === "github" ? ( <CombinedContributionChart session={session} /> ) : ( diff --git a/src/components/profile/UserProfileCard.js b/src/components/profile/UserProfileCard.js new file mode 100644 index 0000000..aced8f0 --- /dev/null +++ b/src/components/profile/UserProfileCard.js @@ -0,0 +1,91 @@ +import React, { useRef } from 'react'; +import Image from 'next/image'; +import { Menu } from 'primereact/menu'; +import { Tooltip } from 'primereact/tooltip'; +import { nip19 } from 'nostr-tools'; +import { useImageProxy } from '@/hooks/useImageProxy'; +import { useToast } from '@/hooks/useToast'; + +const UserProfileCard = ({ user }) => { + const menu = useRef(null); + const { showToast } = useToast(); + const { returnImageProxy } = useImageProxy(); + const copyToClipboard = (text) => { + navigator.clipboard.writeText(text); + showToast("success", "Copied", "Copied to clipboard"); + }; + + const menuItems = [ + ...(user?.privkey ? [{ + label: 'Copy nsec', + icon: 'pi pi-key', + command: () => { + const privkeyBuffer = Buffer.from(user.privkey, 'hex'); + copyToClipboard(nip19.nsecEncode(privkeyBuffer)); + } + }] : []), + { + label: 'Copy npub', + icon: 'pi pi-user', + command: () => { + if (user.pubkey) { + copyToClipboard(nip19.npubEncode(user?.pubkey)); + } + } + }, + { + label: 'Open Nostr Profile', + icon: 'pi pi-external-link', + command: () => window.open(`https://nostr.com/${nip19.npubEncode(user?.pubkey)}`, '_blank') + } + ]; + + return ( + <> + <div className="relative flex w-full items-center justify-center"> + <Image + alt="user's avatar" + src={returnImageProxy(user.avatar, user?.pubkey || "")} + width={100} + height={100} + className="rounded-full my-4" + /> + <div className="absolute top-8 right-80 max-tab:right-20 max-mob:left-0"> + <i + className="pi pi-ellipsis-h text-2xl cursor-pointer" + onClick={(e) => menu.current.toggle(e)} + /> + <Menu + model={menuItems} + popup + ref={menu} + id="profile-options-menu" + /> + </div> + </div> + + + <h1 className="text-center text-2xl my-2"> + {user.username || user?.name || user?.email || "Anon"} + </h1> + {user.pubkey && ( + <h2 className="text-center text-xl my-2 truncate max-tab:px-4 max-mob:px-4"> + <Tooltip target=".pubkey-tooltip" content={"this is your nostr npub"} /> + {nip19.npubEncode(user.pubkey)} <i className="pi pi-question-circle text-xl pubkey-tooltip" /> + </h2> + )} + {user?.lightningAddress && ( + <h3 className="w-fit mx-auto text-center text-xl my-2 bg-gray-800 rounded-lg p-4"> + <span className="font-bold">Lightning Address:</span> {user.lightningAddress.name}@plebdevs.com <i className="pi pi-copy cursor-pointer hover:text-gray-400" onClick={() => copyToClipboard(user.lightningAddress.name + "@plebdevs.com")} /> + </h3> + )} + {user?.nip05 && ( + <h3 className="w-fit mx-auto text-center text-xl my-2 bg-gray-800 rounded-lg p-4"> + <span className="font-bold">NIP-05:</span> {user.nip05.name}@plebdevs.com <i className="pi pi-copy cursor-pointer hover:text-gray-400" onClick={() => copyToClipboard(user.nip05.name + "@plebdevs.com")} /> + </h3> + )} + </> + ); +}; + +export default UserProfileCard;