Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions app/components/header.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,15 @@
export default function Header() {
import type { HeaderProps } from '@/types/header.types';
import UserProfileDropdown from './header/user-profile-dropdown';

export default function Header({ headerType }: HeaderProps) {
return (
<header className="container-padding-x bg-background text-foreground flex flex-1 justify-between py-4">
<div className="text-center text-2xl font-extrabold">EquiBoard </div>
{/* <div>User Section</div> */}
{headerType === 'user-section' && (
<div>
<UserProfileDropdown />
</div>
)}
</header>
);
}
45 changes: 45 additions & 0 deletions app/components/header/user-profile-dropdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import * as DropdownMenu from '@radix-ui/react-dropdown-menu';
import * as Avatar from '@radix-ui/react-avatar';
import { LogOut, Settings, User } from 'lucide-react';

export default function UserProfileDropdown() {
return (
<DropdownMenu.Root>
{/* Trigger */}
<DropdownMenu.Trigger asChild>
<button className="focus:ring-ring flex items-center gap-2 rounded-full focus:ring-2 focus:outline-none" aria-label="User menu">
<Avatar.Root className="bg-muted h-9 w-9 overflow-hidden rounded-full">
<Avatar.Image src="/avatar.png" alt="User avatar" className="h-full w-full object-cover" />
<Avatar.Fallback className="flex h-full w-full items-center justify-center text-sm font-medium">U</Avatar.Fallback>
</Avatar.Root>
</button>
</DropdownMenu.Trigger>

{/* Dropdown */}
<DropdownMenu.Portal>
<DropdownMenu.Content
align="end"
sideOffset={8}
className="bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=open]:fade-in-0 data-[state=closed]:fade-out-0 data-[state=open]:zoom-in-95 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[180px] rounded-md border p-1 shadow-md"
>
<DropdownMenu.Item className="hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-2 text-sm outline-none">
<User size={16} />
Profile
</DropdownMenu.Item>

<DropdownMenu.Item className="hover:bg-muted flex cursor-pointer items-center gap-2 rounded px-2 py-2 text-sm outline-none">
<Settings size={16} />
Settings
</DropdownMenu.Item>

<DropdownMenu.Separator className="bg-border my-1 h-px" />

<DropdownMenu.Item className="flex cursor-pointer items-center gap-2 rounded px-2 py-2 text-sm text-red-600 outline-none hover:bg-red-50">
<LogOut size={16} />
Logout
</DropdownMenu.Item>
</DropdownMenu.Content>
</DropdownMenu.Portal>
</DropdownMenu.Root>
);
}
25 changes: 18 additions & 7 deletions app/components/org-card.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
import type { JSX } from 'react';
import type { IOrgCard } from '@/types/org-card.types';

export default function orgCard({ cardProps, addClass }: { cardProps: IOrgCard; addClass: string }): JSX.Element {
interface OrgCardProps {
cardProps: IOrgCard;
onViewDetails?: () => void;
}

export default function OrgCard({ cardProps, onViewDetails }: OrgCardProps) {
return (
<div className={`flex flex-col justify-center border-1 border-white p-4 ${addClass}`}>
<div>{cardProps.OrgName}</div>
<div>{cardProps.Equity}</div>
<div>{cardProps.Members}</div>
<button>{cardProps.ButtonLabel}</button>
<div className="bg-background flex flex-col justify-between rounded-lg border p-4 shadow-sm transition-shadow hover:shadow-md">
<div className="space-y-1">
<h3 className="text-lg font-semibold">{cardProps.OrgName}</h3>

<p className="text-muted-foreground text-sm">Your equity: {cardProps.Equity}%</p>

<p className="text-muted-foreground text-sm">Members: {cardProps.Members}</p>
</div>

<button onClick={onViewDetails} className="hover:bg-muted mt-4 w-fit rounded-md border px-3 py-1.5 text-sm font-medium transition-colors">
{cardProps.ButtonLabel ?? 'View Details'}
</button>
</div>
);
}
85 changes: 85 additions & 0 deletions app/routes/userprofile.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import Header from '@/components/header';
import OrgCard from '@/components/org-card';

export default function userprofile() {
const orgs = [
{
OrgName: 'Googil',
Equity: '40',
Members: '3',
ButtonLabel: 'Click here',
},
{
OrgName: 'Aapil',
Equity: '60',
Members: '10',
ButtonLabel: 'Click here',
},
];

const recentActivities = [
{
id: '1',
message: 'John D. submitted time contribution in TechStartup',
timestamp: '2h ago',
},
{
id: '2',
message: 'Sarah M. voted on your expertise criteria in DesignCo',
timestamp: '5h ago',
},
{
id: '3',
message: 'New member invitation sent to mark@example.com',
timestamp: '1d ago',
},
{
id: '4',
message: 'Equity configuration completed for AI Solutions',
timestamp: '2d ago',
},
];

return (
<div>
<Header headerType="user-section" />
<div className="container-padding-x">
<div className="flex items-center justify-between gap-4 py-2">
<h1 className="text-lg font-semibold tracking-tight">My Organizations</h1>

<button type="button" className="hover:bg-muted focus:ring-ring rounded-md border px-4 py-2 text-sm font-medium transition-colors focus:ring-2 focus:outline-none">
Create New Organization
</button>
</div>
<div className="flex py-4">
<div className="grid grid-cols-1 gap-6 md:grid-cols-2">
{orgs.map((org) => (
<OrgCard
key={org.OrgName}
cardProps={org}
onViewDetails={() => {
console.log('View details for:', org.OrgName);
}}
/>
))}
</div>
</div>

<div className="bg-background rounded-lg border p-4">
<h2 className="text-muted-foreground mb-3 text-sm font-semibold tracking-wide uppercase">Recent Activity</h2>

<ul className="space-y-3">
{recentActivities.map((activity) => (
<li className="text-muted-foreground flex items-start gap-2 text-sm" key={activity.id}>
<span className="bg-foreground mt-1 h-1.5 w-1.5 shrink-0 rounded-full" />
<span>
{activity.message} <span className="text-muted-foreground text-xs">({activity.timestamp})</span>
</span>
</li>
))}
</ul>
</div>
</div>
</div>
);
}
3 changes: 3 additions & 0 deletions app/types/header.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export interface HeaderProps {
headerType?: string;
}
6 changes: 6 additions & 0 deletions app/types/user.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,9 @@ import type { UserSchema } from '@/service/database/schema/user.schema';
import type { InferSchemaType } from 'mongoose';

export type IUser = InferSchemaType<typeof UserSchema>;

export interface IRecentActivity {
id: string;
message: string;
timestamp: string;
}