mirror of
https://github.com/AustinKelsay/plebdevs.git
synced 2025-05-20 08:52:03 +00:00
Consolidate profile and settings tabs, fix some styles
This commit is contained in:
parent
ffa57f9455
commit
3a59114683
@ -3,7 +3,7 @@ import { Dialog } from 'primereact/dialog';
|
|||||||
import { Tooltip } from 'primereact/tooltip';
|
import { Tooltip } from 'primereact/tooltip';
|
||||||
import useWindowWidth from '@/hooks/useWindowWidth';
|
import useWindowWidth from '@/hooks/useWindowWidth';
|
||||||
|
|
||||||
const MoreInfo = ({ tooltip, modalTitle, modalBody, className = '' }) => {
|
const MoreInfo = ({ tooltip, modalTitle, modalBody, className = '', tooltipPosition = 'right' }) => {
|
||||||
const [visible, setVisible] = useState(false);
|
const [visible, setVisible] = useState(false);
|
||||||
const windowWidth = useWindowWidth();
|
const windowWidth = useWindowWidth();
|
||||||
const isMobile = windowWidth < 768;
|
const isMobile = windowWidth < 768;
|
||||||
@ -14,11 +14,9 @@ const MoreInfo = ({ tooltip, modalTitle, modalBody, className = '' }) => {
|
|||||||
className={`pi pi-question-circle cursor-pointer ${className}`}
|
className={`pi pi-question-circle cursor-pointer ${className}`}
|
||||||
onClick={() => setVisible(true)}
|
onClick={() => setVisible(true)}
|
||||||
data-pr-tooltip={tooltip}
|
data-pr-tooltip={tooltip}
|
||||||
data-pr-position="right"
|
data-pr-position={tooltipPosition}
|
||||||
data-pr-at="right+5 top"
|
|
||||||
data-pr-my="left center-2"
|
|
||||||
/>
|
/>
|
||||||
{!isMobile && <Tooltip target=".pi-question-circle" />}
|
{!isMobile && <Tooltip target=".pi-question-circle" position={tooltipPosition} />}
|
||||||
|
|
||||||
<Dialog
|
<Dialog
|
||||||
header={modalTitle}
|
header={modalTitle}
|
||||||
|
@ -1,20 +1,19 @@
|
|||||||
import React, { useState, useRef, useEffect } from 'react';
|
import React, { useState, useRef, useEffect } from 'react';
|
||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import UserAvatar from './user/UserAvatar';
|
import UserAvatar from './user/UserAvatar';
|
||||||
import { Menubar } from 'primereact/menubar';
|
|
||||||
import { Menu } from 'primereact/menu';
|
import { Menu } from 'primereact/menu';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import SearchBar from '../search/SearchBar';
|
import SearchBar from '../search/SearchBar';
|
||||||
|
import { useSession } from 'next-auth/react';
|
||||||
import 'primereact/resources/primereact.min.css';
|
import 'primereact/resources/primereact.min.css';
|
||||||
import 'primeicons/primeicons.css';
|
import 'primeicons/primeicons.css';
|
||||||
import { useNDKContext } from '@/context/NDKContext';
|
|
||||||
import useWindowWidth from '@/hooks/useWindowWidth';
|
import useWindowWidth from '@/hooks/useWindowWidth';
|
||||||
|
|
||||||
const Navbar = () => {
|
const Navbar = () => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const windowWidth = useWindowWidth();
|
const windowWidth = useWindowWidth();
|
||||||
const navbarHeight = '60px';
|
const navbarHeight = '60px';
|
||||||
const { ndk } = useNDKContext();
|
const { data: session } = useSession();
|
||||||
const [isHovered, setIsHovered] = useState(false);
|
const [isHovered, setIsHovered] = useState(false);
|
||||||
const [showMobileSearch, setShowMobileSearch] = useState(false);
|
const [showMobileSearch, setShowMobileSearch] = useState(false);
|
||||||
const menu = useRef(null);
|
const menu = useRef(null);
|
||||||
@ -47,7 +46,7 @@ const Navbar = () => {
|
|||||||
{
|
{
|
||||||
label: 'Subscribe',
|
label: 'Subscribe',
|
||||||
icon: 'pi pi-star',
|
icon: 'pi pi-star',
|
||||||
command: () => router.push('/about')
|
command: () => session?.user ? router.push('/profile?tab=subscribe') : router.push('/about')
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'About',
|
label: 'About',
|
||||||
@ -62,7 +61,7 @@ const Navbar = () => {
|
|||||||
<div className='px-10 py-8 bg-gray-800 border-t-0 border-l-0 border-r-0 rounded-none fixed z-10 w-[100vw] max-tab:px-[5%] max-mob:px-[5%] flex justify-between' style={{ height: navbarHeight }}>
|
<div className='px-10 py-8 bg-gray-800 border-t-0 border-l-0 border-r-0 rounded-none fixed z-10 w-[100vw] max-tab:px-[5%] max-mob:px-[5%] flex justify-between' style={{ height: navbarHeight }}>
|
||||||
{/* Left section */}
|
{/* Left section */}
|
||||||
<div className='flex items-center flex-1'>
|
<div className='flex items-center flex-1'>
|
||||||
<div onClick={() => router.push('/')} className="flex flex-row items-center justify-center cursor-pointer">
|
<div onClick={() => router.push('/')} className="flex flex-row items-center justify-center cursor-pointer hover:opacity-80">
|
||||||
<Image
|
<Image
|
||||||
alt="logo"
|
alt="logo"
|
||||||
src="/images/plebdevs-icon.png"
|
src="/images/plebdevs-icon.png"
|
||||||
|
@ -58,10 +58,10 @@ const UserRelaysTable = ({ ndk, userRelays, setUserRelays, reInitializeNDK }) =>
|
|||||||
<div className="text-[#f8f8ff]">
|
<div className="text-[#f8f8ff]">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-xl font-bold">Relays</h2>
|
|
||||||
<p className="text-gray-400">Manage your connected relays</p>
|
<p className="text-gray-400">Manage your connected relays</p>
|
||||||
</div>
|
</div>
|
||||||
<GenericButton
|
<GenericButton
|
||||||
|
outlined
|
||||||
icon="pi pi-plus"
|
icon="pi pi-plus"
|
||||||
label="Add Relay"
|
label="Add Relay"
|
||||||
severity="success"
|
severity="success"
|
||||||
@ -78,7 +78,7 @@ const UserRelaysTable = ({ ndk, userRelays, setUserRelays, reInitializeNDK }) =>
|
|||||||
className="flex-1"
|
className="flex-1"
|
||||||
/>
|
/>
|
||||||
<GenericButton
|
<GenericButton
|
||||||
label="Add"
|
label="+"
|
||||||
severity="success"
|
severity="success"
|
||||||
outlined
|
outlined
|
||||||
onClick={addRelay}
|
onClick={addRelay}
|
||||||
@ -122,7 +122,7 @@ const UserRelaysTable = ({ ndk, userRelays, setUserRelays, reInitializeNDK }) =>
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-gray-800 rounded-lg border border-gray-700 w-full">
|
<div className="w-full">
|
||||||
<DataTable
|
<DataTable
|
||||||
value={userRelays}
|
value={userRelays}
|
||||||
className="border-none"
|
className="border-none"
|
||||||
|
@ -10,6 +10,7 @@ import UserProgress from "@/components/profile/progress/UserProgress";
|
|||||||
import UserProgressTable from '@/components/profile/DataTables/UserProgressTable';
|
import UserProgressTable from '@/components/profile/DataTables/UserProgressTable';
|
||||||
import UserPurchaseTable from '@/components/profile/DataTables/UserPurchaseTable';
|
import UserPurchaseTable from '@/components/profile/DataTables/UserPurchaseTable';
|
||||||
import BitcoinLightningCard from '@/components/profile/BitcoinLightningCard';
|
import BitcoinLightningCard from '@/components/profile/BitcoinLightningCard';
|
||||||
|
import UserAccountLinking from "@/components/profile/UserAccountLinking";
|
||||||
|
|
||||||
const UserProfile = () => {
|
const UserProfile = () => {
|
||||||
const windowWidth = useWindowWidth();
|
const windowWidth = useWindowWidth();
|
||||||
@ -42,6 +43,7 @@ const UserProfile = () => {
|
|||||||
<div className="w-[22%] h-full max-lap:w-full">
|
<div className="w-[22%] h-full max-lap:w-full">
|
||||||
{user && <UserProfileCard user={user} />}
|
{user && <UserProfileCard user={user} />}
|
||||||
<BitcoinLightningCard />
|
<BitcoinLightningCard />
|
||||||
|
{user && <UserAccountLinking session={session} />}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-[78%] flex flex-col justify-center mx-auto max-lap:w-full">
|
<div className="w-[78%] flex flex-col justify-center mx-auto max-lap:w-full">
|
||||||
|
@ -2,19 +2,24 @@ import React, { useRef, useState } from 'react';
|
|||||||
import Image from 'next/image';
|
import Image from 'next/image';
|
||||||
import { Menu } from 'primereact/menu';
|
import { Menu } from 'primereact/menu';
|
||||||
import { Tooltip } from 'primereact/tooltip';
|
import { Tooltip } from 'primereact/tooltip';
|
||||||
|
import { Dialog } from 'primereact/dialog';
|
||||||
import { nip19 } from 'nostr-tools';
|
import { nip19 } from 'nostr-tools';
|
||||||
import { useImageProxy } from '@/hooks/useImageProxy';
|
import { useImageProxy } from '@/hooks/useImageProxy';
|
||||||
import { useToast } from '@/hooks/useToast';
|
import { useToast } from '@/hooks/useToast';
|
||||||
import UserBadges from '@/components/profile/UserBadges';
|
import UserBadges from '@/components/profile/UserBadges';
|
||||||
import useWindowWidth from '@/hooks/useWindowWidth';
|
import useWindowWidth from '@/hooks/useWindowWidth';
|
||||||
import MoreInfo from '@/components/MoreInfo';
|
import MoreInfo from '@/components/MoreInfo';
|
||||||
|
import UserRelaysTable from '@/components/profile/DataTables/UserRelaysTable';
|
||||||
|
import { useNDKContext } from "@/context/NDKContext";
|
||||||
|
|
||||||
const UserProfileCard = ({ user }) => {
|
const UserProfileCard = ({ user }) => {
|
||||||
const [showBadges, setShowBadges] = useState(false);
|
const [showBadges, setShowBadges] = useState(false);
|
||||||
|
const [showRelaysModal, setShowRelaysModal] = useState(false);
|
||||||
const menu = useRef(null);
|
const menu = useRef(null);
|
||||||
const { showToast } = useToast();
|
const { showToast } = useToast();
|
||||||
const { returnImageProxy } = useImageProxy();
|
const { returnImageProxy } = useImageProxy();
|
||||||
const windowWidth = useWindowWidth();
|
const windowWidth = useWindowWidth();
|
||||||
|
const { ndk, userRelays, setUserRelays, reInitializeNDK } = useNDKContext();
|
||||||
|
|
||||||
const copyToClipboard = (text) => {
|
const copyToClipboard = (text) => {
|
||||||
navigator.clipboard.writeText(text);
|
navigator.clipboard.writeText(text);
|
||||||
@ -43,6 +48,11 @@ const UserProfileCard = ({ user }) => {
|
|||||||
label: 'Open Nostr Profile',
|
label: 'Open Nostr Profile',
|
||||||
icon: 'pi pi-external-link',
|
icon: 'pi pi-external-link',
|
||||||
command: () => window.open(`https://nostr.com/${nip19.npubEncode(user?.pubkey)}`, '_blank')
|
command: () => window.open(`https://nostr.com/${nip19.npubEncode(user?.pubkey)}`, '_blank')
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Manage Relays',
|
||||||
|
icon: 'pi pi-server',
|
||||||
|
command: () => setShowRelaysModal(true)
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -282,6 +292,20 @@ const UserProfileCard = ({ user }) => {
|
|||||||
visible={showBadges}
|
visible={showBadges}
|
||||||
onHide={() => setShowBadges(false)}
|
onHide={() => setShowBadges(false)}
|
||||||
/>
|
/>
|
||||||
|
<Dialog
|
||||||
|
visible={showRelaysModal}
|
||||||
|
onHide={() => setShowRelaysModal(false)}
|
||||||
|
header="Manage Relays"
|
||||||
|
className="w-[90vw] max-w-[800px]"
|
||||||
|
modal
|
||||||
|
>
|
||||||
|
<UserRelaysTable
|
||||||
|
ndk={ndk}
|
||||||
|
userRelays={userRelays}
|
||||||
|
setUserRelays={setUserRelays}
|
||||||
|
reInitializeNDK={reInitializeNDK}
|
||||||
|
/>
|
||||||
|
</Dialog>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
@ -1,47 +0,0 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
|
||||||
import UserProfileCard from "@/components/profile/UserProfileCard";
|
|
||||||
import { useSession } from 'next-auth/react';
|
|
||||||
import { useNDKContext } from "@/context/NDKContext";
|
|
||||||
import useWindowWidth from "@/hooks/useWindowWidth";
|
|
||||||
import UserRelaysTable from "@/components/profile/DataTables/UserRelaysTable";
|
|
||||||
import UserAccountLinking from "@/components/profile/UserAccountLinking";
|
|
||||||
const UserSettings = () => {
|
|
||||||
const [user, setUser] = useState(null);
|
|
||||||
const { ndk, userRelays, setUserRelays, reInitializeNDK } = useNDKContext();
|
|
||||||
const { data: session } = useSession();
|
|
||||||
const windowWidth = useWindowWidth();
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (session?.user) {
|
|
||||||
setUser(session.user);
|
|
||||||
}
|
|
||||||
}, [session]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
user && (
|
|
||||||
<div className="py-4 px-1">
|
|
||||||
{windowWidth < 768 && (
|
|
||||||
<h1 className="text-3xl font-bold mb-6">Settings</h1>
|
|
||||||
)}
|
|
||||||
<div className="w-full flex flex-row max-lap:flex-col">
|
|
||||||
<div className="w-[22%] h-full max-lap:w-full">
|
|
||||||
<UserProfileCard user={user} />
|
|
||||||
|
|
||||||
{user && <UserAccountLinking session={session} />}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="w-[78%] flex flex-col justify-center mx-2 max-lap:mx-0 max-lap:w-full">
|
|
||||||
<UserRelaysTable
|
|
||||||
ndk={ndk}
|
|
||||||
userRelays={userRelays}
|
|
||||||
setUserRelays={setUserRelays}
|
|
||||||
reInitializeNDK={reInitializeNDK}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default UserSettings;
|
|
@ -117,7 +117,7 @@ const UserSubscription = () => {
|
|||||||
{!subscribed && (
|
{!subscribed && (
|
||||||
<Card
|
<Card
|
||||||
title="Subscribe to PlebDevs"
|
title="Subscribe to PlebDevs"
|
||||||
className="mb-2 max-lap:h-auto border border-gray-700"
|
className="max-lap:h-auto border border-gray-700"
|
||||||
pt={{
|
pt={{
|
||||||
body: { className: 'py-2' },
|
body: { className: 'py-2' },
|
||||||
content: { className: 'pt-0' }
|
content: { className: 'pt-0' }
|
||||||
@ -190,7 +190,7 @@ const UserSubscription = () => {
|
|||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Card title="Frequently Asked Questions" className="border border-gray-700 rounded-lg">
|
<Card title="Frequently Asked Questions" className="mt-2 border border-gray-700 rounded-lg">
|
||||||
<div className="flex flex-col gap-4">
|
<div className="flex flex-col gap-4">
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg font-semibold">How does the subscription work?</h3>
|
<h3 className="text-lg font-semibold">How does the subscription work?</h3>
|
||||||
|
@ -9,7 +9,7 @@ const appConfig = {
|
|||||||
"wss://purplerelay.com/",
|
"wss://purplerelay.com/",
|
||||||
"wss://relay.devs.tools/"
|
"wss://relay.devs.tools/"
|
||||||
],
|
],
|
||||||
authorPubkeys: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741", "c67cd3e1a83daa56cff16f635db2fdb9ed9619300298d4701a58e68e84098345"],
|
authorPubkeys: ["f33c8a9617cb15f705fc70cd461cfd6eaf22f9e24c33eabad981648e5ec6f741", "c67cd3e1a83daa56cff16f635db2fdb9ed9619300298d4701a58e68e84098345", "6260f29fa75c91aaa292f082e5e87b438d2ab4fdf96af398567b01802ee2fcd4"],
|
||||||
customLightningAddresses: [
|
customLightningAddresses: [
|
||||||
{
|
{
|
||||||
// todo remove need for lowercase
|
// todo remove need for lowercase
|
||||||
|
@ -211,6 +211,7 @@ const AboutPage = () => {
|
|||||||
<h2 className="text-xl font-bold m-0">Subscribe to PlebDevs</h2>
|
<h2 className="text-xl font-bold m-0">Subscribe to PlebDevs</h2>
|
||||||
<MoreInfo
|
<MoreInfo
|
||||||
tooltip="Subscription FAQ"
|
tooltip="Subscription FAQ"
|
||||||
|
tooltipPosition='top'
|
||||||
modalTitle="Frequently Asked Questions"
|
modalTitle="Frequently Asked Questions"
|
||||||
modalBody={faqContent}
|
modalBody={faqContent}
|
||||||
className="text-gray-400 hover:text-white"
|
className="text-gray-400 hover:text-white"
|
||||||
|
@ -116,8 +116,6 @@ export default function Home() {
|
|||||||
const [selectedTopic, setSelectedTopic] = useState('Top');
|
const [selectedTopic, setSelectedTopic] = useState('Top');
|
||||||
const [filteredContent, setFilteredContent] = useState([]);
|
const [filteredContent, setFilteredContent] = useState([]);
|
||||||
|
|
||||||
const memoizedFilteredContent = useMemo(() => filteredContent, [filteredContent]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (documents && !documentsLoading) {
|
if (documents && !documentsLoading) {
|
||||||
const processedDocuments = documents.map(document => ({...parseEvent(document), type: 'document'}));
|
const processedDocuments = documents.map(document => ({...parseEvent(document), type: 'document'}));
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import React, { useState, useEffect } from "react";
|
import React, { useState, useEffect } from "react";
|
||||||
import { TabView, TabPanel } from "primereact/tabview";
|
import { TabView, TabPanel } from "primereact/tabview";
|
||||||
import UserProfile from "@/components/profile/UserProfile";
|
import UserProfile from "@/components/profile/UserProfile";
|
||||||
import UserSettings from "@/components/profile/UserSettings";
|
|
||||||
import UserContent from "@/components/profile/UserContent";
|
import UserContent from "@/components/profile/UserContent";
|
||||||
import UserSubscription from "@/components/profile/subscription/UserSubscription";
|
import UserSubscription from "@/components/profile/subscription/UserSubscription";
|
||||||
import { useRouter } from "next/router";
|
import { useRouter } from "next/router";
|
||||||
@ -16,7 +15,7 @@ const Profile = () => {
|
|||||||
const [activeTab, setActiveTab] = useState(0);
|
const [activeTab, setActiveTab] = useState(0);
|
||||||
const {isAdmin, isLoading} = useIsAdmin();
|
const {isAdmin, isLoading} = useIsAdmin();
|
||||||
|
|
||||||
const tabs = ["profile", "settings", "content", "subscribe"];
|
const tabs = ["profile", "content", "subscribe"];
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const { tab } = router.query;
|
const { tab } = router.query;
|
||||||
@ -74,13 +73,6 @@ const Profile = () => {
|
|||||||
}}>
|
}}>
|
||||||
<UserProfile />
|
<UserProfile />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
<TabPanel header="Settings" pt={{
|
|
||||||
headerAction: {
|
|
||||||
className: "bg-transparent"
|
|
||||||
},
|
|
||||||
}}>
|
|
||||||
<UserSettings />
|
|
||||||
</TabPanel>
|
|
||||||
{isAdmin && (
|
{isAdmin && (
|
||||||
<TabPanel header="Content" pt={{
|
<TabPanel header="Content" pt={{
|
||||||
headerAction: {
|
headerAction: {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user