mirror of
https://github.com/AustinKelsay/plebdevs.git
synced 2025-06-06 18:31:00 +00:00
Basic layout for profile card mobile
This commit is contained in:
parent
c04a42eeb7
commit
600ddadbb4
@ -157,7 +157,7 @@ const ActivityContributionChart = ({ session }) => {
|
|||||||
const weekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
const weekDays = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full mx-2 bg-gray-800 rounded-lg border border-gray-700 shadow-md">
|
<div className="w-full mx-2 bg-gray-800 rounded-lg border border-gray-700 shadow-md h-[330px] max-lap:mx-0 max-lap:mt-2">
|
||||||
<div className="flex flex-row justify-between items-center p-4">
|
<div className="flex flex-row justify-between items-center p-4">
|
||||||
<h1 className="text-2xl font-bold text-gray-200">Activity</h1>
|
<h1 className="text-2xl font-bold text-gray-200">Activity</h1>
|
||||||
<i className="pi pi-question-circle text-2xl cursor-pointer text-gray-200"
|
<i className="pi pi-question-circle text-2xl cursor-pointer text-gray-200"
|
||||||
|
@ -181,7 +181,7 @@ const CombinedContributionChart = ({ session }) => {
|
|||||||
}, [calendar]);
|
}, [calendar]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full mx-2 bg-gray-800 rounded-lg border border-gray-700 shadow-md">
|
<div className="w-full mx-2 bg-gray-800 rounded-lg border border-gray-700 shadow-md h-[330px] max-lap:mx-0 max-lap:mt-2">
|
||||||
<div className="flex flex-row justify-between items-center p-4">
|
<div className="flex flex-row justify-between items-center p-4">
|
||||||
<h1 className="text-2xl font-bold text-gray-200">Activity</h1>
|
<h1 className="text-2xl font-bold text-gray-200">Activity</h1>
|
||||||
<i className="pi pi-question-circle text-2xl cursor-pointer text-gray-200"
|
<i className="pi pi-question-circle text-2xl cursor-pointer text-gray-200"
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import React from "react";
|
import React from "react";
|
||||||
import { DataTable } from "primereact/datatable";
|
import { DataTable } from "primereact/datatable";
|
||||||
import { Column } from "primereact/column";
|
import { Column } from "primereact/column";
|
||||||
import { classNames } from "primereact/utils";
|
import useWindowWidth from "@/hooks/useWindowWidth";
|
||||||
import ProgressListItem from "@/components/content/lists/ProgressListItem";
|
import ProgressListItem from "@/components/content/lists/ProgressListItem";
|
||||||
import { formatDateTime } from "@/utils/time";
|
import { formatDateTime } from "@/utils/time";
|
||||||
import { ProgressSpinner } from "primereact/progressspinner";
|
import { ProgressSpinner } from "primereact/progressspinner";
|
||||||
|
|
||||||
const UserProgressTable = ({ session, ndk, windowWidth }) => {
|
const UserProgressTable = ({ session, ndk }) => {
|
||||||
|
const windowWidth = useWindowWidth();
|
||||||
const prepareProgressData = () => {
|
const prepareProgressData = () => {
|
||||||
if (!session?.user?.userCourses) return [];
|
if (!session?.user?.userCourses) return [];
|
||||||
|
|
||||||
@ -129,7 +130,8 @@ const UserProgressTable = ({ session, ndk, windowWidth }) => {
|
|||||||
emptyMessage="No Courses or Milestones completed"
|
emptyMessage="No Courses or Milestones completed"
|
||||||
value={prepareProgressData()}
|
value={prepareProgressData()}
|
||||||
header={header}
|
header={header}
|
||||||
style={{ margin: 8, width: "100%", borderRadius: "8px", border: "1px solid #333", boxShadow: "0 0 10px 0 rgba(0, 0, 0, 0.1)" }}
|
className="m-2 max-lap:m-0"
|
||||||
|
style={{ width: "100%", borderRadius: "8px", border: "1px solid #333", boxShadow: "0 0 10px 0 rgba(0, 0, 0, 0.1)" }}
|
||||||
pt={{
|
pt={{
|
||||||
wrapper: {
|
wrapper: {
|
||||||
className: "rounded-b-lg shadow-md"
|
className: "rounded-b-lg shadow-md"
|
||||||
|
@ -53,7 +53,8 @@ const UserPurchaseTable = ({ session, windowWidth }) => {
|
|||||||
emptyMessage="No purchases"
|
emptyMessage="No purchases"
|
||||||
value={session.user?.purchased}
|
value={session.user?.purchased}
|
||||||
header={purchasesHeader}
|
header={purchasesHeader}
|
||||||
style={{ margin: 8, width: "100%", borderRadius: "8px", border: "1px solid #333", boxShadow: "0 0 10px 0 rgba(0, 0, 0, 0.1)" }}
|
className="m-2 max-lap:m-0"
|
||||||
|
style={{ width: "100%", borderRadius: "8px", border: "1px solid #333", boxShadow: "0 0 10px 0 rgba(0, 0, 0, 0.1)" }}
|
||||||
pt={{
|
pt={{
|
||||||
wrapper: {
|
wrapper: {
|
||||||
className: "rounded-b-lg shadow-md"
|
className: "rounded-b-lg shadow-md"
|
||||||
|
@ -37,10 +37,9 @@ const UserProfile = () => {
|
|||||||
<h1 className="text-3xl font-bold mb-6">Profile</h1>
|
<h1 className="text-3xl font-bold mb-6">Profile</h1>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
<div className="w-full flex flex-row">
|
<div className="w-full flex flex-row max-lap:flex-col">
|
||||||
<UserProfileCard user={user} />
|
<UserProfileCard user={user} />
|
||||||
<div className="w-full flex flex-col justify-center mx-auto">
|
<div className="w-full flex flex-col justify-center mx-auto">
|
||||||
|
|
||||||
{account && account?.provider === "github" ? (
|
{account && account?.provider === "github" ? (
|
||||||
<CombinedContributionChart session={session} />
|
<CombinedContributionChart session={session} />
|
||||||
) : (
|
) : (
|
||||||
|
@ -1,15 +1,20 @@
|
|||||||
import React, { useRef } from 'react';
|
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 { 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 useWindowWidth from '@/hooks/useWindowWidth';
|
||||||
|
|
||||||
const UserProfileCard = ({ user }) => {
|
const UserProfileCard = ({ user }) => {
|
||||||
|
const [showBadges, setShowBadges] = 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 copyToClipboard = (text) => {
|
const copyToClipboard = (text) => {
|
||||||
navigator.clipboard.writeText(text);
|
navigator.clipboard.writeText(text);
|
||||||
showToast("success", "Copied", "Copied to clipboard");
|
showToast("success", "Copied", "Copied to clipboard");
|
||||||
@ -40,9 +45,96 @@ const UserProfileCard = ({ user }) => {
|
|||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
return (
|
const MobileProfileCard = () => (
|
||||||
<div className="lg:w-1/4 bg-gray-800 rounded-lg p-4 border border-gray-700 shadow-md">
|
<div className="w-full bg-gray-800 rounded-lg p-2 py-1 border border-gray-700 shadow-md h-[330px] flex flex-col justify-center">
|
||||||
<div className="flex flex-row gap-4">
|
<div className="flex flex-col gap-2 pt-4 w-full relative">
|
||||||
|
<div className="absolute top-8 right-[10px]">
|
||||||
|
<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>
|
||||||
|
<Image
|
||||||
|
alt="user's avatar"
|
||||||
|
src={returnImageProxy(user.avatar, user?.pubkey || "")}
|
||||||
|
width={100}
|
||||||
|
height={100}
|
||||||
|
className="rounded-full mt-2 mx-auto"
|
||||||
|
/>
|
||||||
|
<h3 className="text-center">
|
||||||
|
{user.username || user?.name || user?.email || "Anon"}
|
||||||
|
</h3>
|
||||||
|
<div className="flex flex-col gap-2 justify-center">
|
||||||
|
{
|
||||||
|
user?.pubkey && (
|
||||||
|
<div className="flex flex-row gap-2 justify-center">
|
||||||
|
<p className="truncate">
|
||||||
|
{nip19.npubEncode(user.pubkey)}
|
||||||
|
</p>
|
||||||
|
<Tooltip target=".pubkey-tooltip" content={"this is your account pubkey"} />
|
||||||
|
<i className="pi pi-question-circle pubkey-tooltip text-xs cursor-pointer" />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
{user?.createdAt && (
|
||||||
|
<p className="truncate text-center">
|
||||||
|
Joined: {new Date(user.createdAt).toLocaleDateString()}
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className='w-full flex flex-row justify-between'>
|
||||||
|
<div className="flex flex-col justify-between gap-4 my-2">
|
||||||
|
{user?.lightningAddress ? (
|
||||||
|
<h4 className="bg-gray-900 rounded-lg p-3 max-lap:w-fit min-w-[240px]">
|
||||||
|
<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")} />
|
||||||
|
</h4>
|
||||||
|
) : (
|
||||||
|
<div className="flex flex-row justify-between bg-gray-900 rounded-lg p-3 max-lap:w-fit min-w-[240px]">
|
||||||
|
<h4 >
|
||||||
|
<span className="font-bold">Lightning Address:</span> None
|
||||||
|
</h4>
|
||||||
|
{/* todo: add tooltip */}
|
||||||
|
<Tooltip target=".lightning-address-tooltip" content={"this is your account lightning address"} />
|
||||||
|
<i className="pi pi-question-circle lightning-address-tooltip text-xs cursor-pointer" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{user?.nip05 ? (
|
||||||
|
<h4 className="bg-gray-900 rounded-lg p-3 max-lap:w-fit min-w-[240px]">
|
||||||
|
<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")} />
|
||||||
|
</h4>
|
||||||
|
) : (
|
||||||
|
<div className="flex flex-row justify-between bg-gray-900 rounded-lg p-3 max-lap:w-fit min-w-[240px]">
|
||||||
|
<h4>
|
||||||
|
<span className="font-bold">NIP-05:</span> None
|
||||||
|
</h4>
|
||||||
|
{/* todo: add tooltip */}
|
||||||
|
<Tooltip target=".nip05-tooltip" content={"this is your account nip05"} />
|
||||||
|
<i className="pi pi-question-circle nip05-tooltip text-xs cursor-pointer" />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<div className="flex flex-col justify-center min-w-[140px] px-2">
|
||||||
|
<button
|
||||||
|
className="w-full py-3 bg-gradient-to-r from-blue-500 to-purple-600 text-white rounded-full font-semibold"
|
||||||
|
onClick={() => setShowBadges(true)}
|
||||||
|
>
|
||||||
|
View Badges
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
const DesktopProfileCard = () => (
|
||||||
|
<div className="w-1/4 bg-gray-800 rounded-lg p-2 py-1 border border-gray-700 shadow-md h-[330px]">
|
||||||
|
<div className="flex flex-row w-full justify-around">
|
||||||
<Image
|
<Image
|
||||||
alt="user's avatar"
|
alt="user's avatar"
|
||||||
src={returnImageProxy(user.avatar, user?.pubkey || "")}
|
src={returnImageProxy(user.avatar, user?.pubkey || "")}
|
||||||
@ -50,9 +142,8 @@ const UserProfileCard = ({ user }) => {
|
|||||||
height={100}
|
height={100}
|
||||||
className="rounded-full my-4"
|
className="rounded-full my-4"
|
||||||
/>
|
/>
|
||||||
|
<div className="flex flex-col gap-2 pt-4 w-fit relative">
|
||||||
<div className="flex flex-col gap-2 pt-4 w-full relative">
|
<div className="absolute top-[-4px] right-[-10px]">
|
||||||
<div className="absolute top-0 right-0">
|
|
||||||
<i
|
<i
|
||||||
className="pi pi-ellipsis-h text-2xl cursor-pointer"
|
className="pi pi-ellipsis-h text-2xl cursor-pointer"
|
||||||
onClick={(e) => menu.current.toggle(e)}
|
onClick={(e) => menu.current.toggle(e)}
|
||||||
@ -85,13 +176,13 @@ const UserProfileCard = ({ user }) => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-col gap-2">
|
<div className="flex flex-col justify-between gap-4 my-2">
|
||||||
{user?.lightningAddress ? (
|
{user?.lightningAddress ? (
|
||||||
<h4 className="my-2 bg-gray-900 rounded-lg p-4">
|
<h4 className="bg-gray-900 rounded-lg p-3 max-lap:w-fit min-w-[240px]">
|
||||||
<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")} />
|
<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")} />
|
||||||
</h4>
|
</h4>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-row justify-between my-2 bg-gray-900 rounded-lg p-4">
|
<div className="flex flex-row justify-between bg-gray-900 rounded-lg p-3 max-lap:w-fit min-w-[240px]">
|
||||||
<h4 >
|
<h4 >
|
||||||
<span className="font-bold">Lightning Address:</span> None
|
<span className="font-bold">Lightning Address:</span> None
|
||||||
</h4>
|
</h4>
|
||||||
@ -101,11 +192,11 @@ const UserProfileCard = ({ user }) => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{user?.nip05 ? (
|
{user?.nip05 ? (
|
||||||
<h4 className="my-2 bg-gray-900 rounded-lg p-4">
|
<h4 className="bg-gray-900 rounded-lg p-3 max-lap:w-fit min-w-[240px]">
|
||||||
<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")} />
|
<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")} />
|
||||||
</h4>
|
</h4>
|
||||||
) : (
|
) : (
|
||||||
<div className="flex flex-row justify-between my-2 bg-gray-900 rounded-lg p-4">
|
<div className="flex flex-row justify-between bg-gray-900 rounded-lg p-3 max-lap:w-fit min-w-[240px]">
|
||||||
<h4>
|
<h4>
|
||||||
<span className="font-bold">NIP-05:</span> None
|
<span className="font-bold">NIP-05:</span> None
|
||||||
</h4>
|
</h4>
|
||||||
@ -114,9 +205,26 @@ const UserProfileCard = ({ user }) => {
|
|||||||
<i className="pi pi-question-circle nip05-tooltip text-xs cursor-pointer" />
|
<i className="pi pi-question-circle nip05-tooltip text-xs cursor-pointer" />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
<button
|
||||||
|
className="w-full py-3 bg-gradient-to-r from-blue-500 to-purple-600 text-white rounded-full font-semibold max-lap:w-fit min-w-[140px]"
|
||||||
|
onClick={() => setShowBadges(true)}
|
||||||
|
>
|
||||||
|
View Badges
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 1440px is the max-lap breakpoint from tailwind config
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{windowWidth <= 1440 ? <MobileProfileCard /> : <DesktopProfileCard />}
|
||||||
|
<UserBadges
|
||||||
|
visible={showBadges}
|
||||||
|
onHide={() => setShowBadges(false)}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default UserProfileCard;
|
export default UserProfileCard;
|
||||||
|
@ -4,7 +4,6 @@ import { Accordion, AccordionTab } from 'primereact/accordion';
|
|||||||
import { useSession, signIn, getSession } from 'next-auth/react';
|
import { useSession, signIn, getSession } from 'next-auth/react';
|
||||||
import { useRouter } from 'next/router';
|
import { useRouter } from 'next/router';
|
||||||
import GenericButton from '@/components/buttons/GenericButton';
|
import GenericButton from '@/components/buttons/GenericButton';
|
||||||
import UserBadges from '@/components/profile/UserBadges';
|
|
||||||
import UserProgressFlow from './UserProgressFlow';
|
import UserProgressFlow from './UserProgressFlow';
|
||||||
import { Tooltip } from 'primereact/tooltip';
|
import { Tooltip } from 'primereact/tooltip';
|
||||||
|
|
||||||
@ -56,7 +55,6 @@ const UserProgress = () => {
|
|||||||
const [expandedItems, setExpandedItems] = useState({});
|
const [expandedItems, setExpandedItems] = useState({});
|
||||||
const [completedCourses, setCompletedCourses] = useState([]);
|
const [completedCourses, setCompletedCourses] = useState([]);
|
||||||
const [tasks, setTasks] = useState([]);
|
const [tasks, setTasks] = useState([]);
|
||||||
const [showBadges, setShowBadges] = useState(false);
|
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -177,7 +175,7 @@ const UserProgress = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="bg-gray-800 rounded-lg p-4 m-2 w-full border border-gray-700 shadow-md">
|
<div className="bg-gray-800 rounded-lg p-4 pb-0 m-2 w-full border border-gray-700 shadow-md max-lap:mx-0">
|
||||||
<div className="flex flex-row justify-between items-center">
|
<div className="flex flex-row justify-between items-center">
|
||||||
<h1 className="text-3xl font-bold text-white mb-2">Dev Journey</h1>
|
<h1 className="text-3xl font-bold text-white mb-2">Dev Journey</h1>
|
||||||
<i className="pi pi-question-circle text-2xl cursor-pointer text-gray-200"
|
<i className="pi pi-question-circle text-2xl cursor-pointer text-gray-200"
|
||||||
@ -209,8 +207,8 @@ const UserProgress = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex gap-6 mb-6">
|
<div className="flex max-sidebar:flex-col gap-6 mb-6">
|
||||||
<div className="w-1/2">
|
<div className="w-1/2 max-sidebar:w-full">
|
||||||
<ul className="space-y-6 pt-2">
|
<ul className="space-y-6 pt-2">
|
||||||
{tasks.map((task, index) => (
|
{tasks.map((task, index) => (
|
||||||
<li key={index}>
|
<li key={index}>
|
||||||
@ -291,7 +289,7 @@ const UserProgress = () => {
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="w-1/2">
|
<div className="w-1/2 max-sidebar:w-full">
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<div className="h-[400px] bg-gray-800 rounded-3xl flex items-center justify-center">
|
<div className="h-[400px] bg-gray-800 rounded-3xl flex items-center justify-center">
|
||||||
<i className="pi pi-spin pi-spinner text-4xl text-gray-600"></i>
|
<i className="pi pi-spin pi-spinner text-4xl text-gray-600"></i>
|
||||||
@ -301,18 +299,6 @@ const UserProgress = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
|
||||||
className="w-full py-3 bg-gradient-to-r from-blue-500 to-purple-600 text-white rounded-full font-semibold"
|
|
||||||
onClick={() => setShowBadges(true)}
|
|
||||||
>
|
|
||||||
View Badges
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<UserBadges
|
|
||||||
visible={showBadges}
|
|
||||||
onHide={() => setShowBadges(false)}
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user