Skip to content
Closed
Show file tree
Hide file tree
Changes from 7 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

# dependencies
/node_modules
/.env
/.pnp
.pnp.*
.yarn/*
Expand Down
63 changes: 58 additions & 5 deletions app/dashboard/settings/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,60 @@
import React from "react";
"use client";

const Settings = () => {
return <div>Settings</div>;
};
import NotificationTab from "@/components/settings/Notification";
import ProfileTab from "@/components/settings/ProfileTab";
import SecurityTab from "@/components/settings/SecurityTab";
import { FileIcon, ShieldIcon, BellIcon, IdCardIcon } from "@/public/svg"; // example icons
import { useState } from "react";

export default Settings;
const tabs = [
{ key: "profile", label: "Account Info", icon: FileIcon },
{ key: "security", label: "Security", icon: ShieldIcon },
{ key: "notification", label: "Notification", icon: BellIcon },
{ key: "identity", label: "Identity Verification", icon: IdCardIcon },
];

export default function Settings() {
const [activeTab, setActiveTab] = useState("profile");

return (
<div className="max-w-[1086px] md:p-6 p-2 pt-6 md:pt-auto">
{/* Tabs */}
<div className="overflow-x-auto whitespace-nowrap scrollbar-hide">
<div className="flex space-x-6 border-b text-xs md:text-base border-gray-200 mb-6">
{tabs.map((tab) => {
const IconComponent = tab.icon;
return (
<button
key={tab.key}
onClick={() => setActiveTab(tab.key)}
className={`flex items-center space-x-2 pb-2 border-b-2 transition-colors ${
activeTab === tab.key
? "border-yellow-500 text-yellow-600 font-semibold"
: "border-transparent text-gray-500 hover:text-gray-700"
}`}
>
{IconComponent && <IconComponent className="w-4 h-4" />}
<span>{tab.label}</span>
</button>
);
})}
</div>
</div>

{/* Tab Content */}
<div>
{activeTab === "profile" && <ProfileTab />}
{activeTab === "security" && <SecurityTab />}
{activeTab === "notification" && <NotificationTab />}
{activeTab === "identity" && (
<div>
{/* TODO: Integrate Identity Verification API when available */}
<p className="text-gray-500">
Identity Verification UI comming soon...
</p>
</div>
)}
</div>
</div>
);
}
25 changes: 19 additions & 6 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,19 @@

@custom-variant dark (&:is(.dark *));

/* globals.css */
@layer utilities {
.scrollbar-hide {
-webkit-overflow-scrolling: touch; /* smooth scrolling on iOS */
-ms-overflow-style: none; /* Internet Explorer/Edge */
scrollbar-width: none; /* Firefox */
}
.scrollbar-hide::-webkit-scrollbar {
display: none; /* Safari and Chrome */
height: 0;
}
}

@theme inline {
--color-background: var(--background);
--color-foreground: var(--foreground);
Expand Down Expand Up @@ -47,7 +60,7 @@
--color-brand-primary: var(--brand-primary);
--color-brand-primary-hover: var(--brand-primary-hover);
--color-brand-secondary: var(--brand-secondary);
--color-brand-secondary-hover: var(--brand-secondary-hover);
--color-brand-secondary-hover: var(--brand-secondary-hover);
--color-text-primary: var(--text-primary);
--color-text-secondary: var(--text-secondary);
--color-text-tertiary: var(--text-tertiary);
Expand Down Expand Up @@ -128,7 +141,7 @@
--brand-primary: #ffd552;
--brand-primary-hover: #e6c04a;
--brand-secondary: #e9eaee;
--brand-secondary-hover: #d3d4d8;
--brand-secondary-hover: #d3d4d8;

/* Text Colors */
--text-primary: #262626;
Expand Down Expand Up @@ -160,8 +173,8 @@
--bg-dropdown-hover: rgba(224, 224, 224, 0.7);
--bg-selector-icon: rgba(183, 183, 183, 0.6);
--bg-contact-blue: #d9e9ff;
--bg-contact-yellow: #fdfcbd;
--bg-contact-orange: #E58600;
--bg-contact-yellow: #fdfcbd;
--bg-contact-orange: #e58600;

/* Border Colors */
--border-crypto-card: rgba(121, 121, 121, 0.4);
Expand All @@ -178,8 +191,8 @@
--contact-icon-yellow: #e8b300;

/* Mobile Admin Gradient Colors */
--admin-gradient-blue: #A0C3FD;
--admin-gradient-yellow: #FFE79C;
--admin-gradient-blue: #a0c3fd;
--admin-gradient-yellow: #ffe79c;
}

.dark {
Expand Down
70 changes: 27 additions & 43 deletions components/header/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,49 +1,41 @@
// components/Sidebar.tsx
"use client";

import {
Home,
Wallet,
User,
ArrowDownUp,
ChevronLeft,
Copy,
Settings,
} from "lucide-react";
import { useSidebarStore } from "@/store/sidebarStore";
import { useEffect, useState } from "react";
import { useRouter } from "next/navigation";
import { useEffect } from "react";
import { usePathname, useRouter } from "next/navigation";
import Image from "next/image";

const initialMenuItems = [
{ icon: Home, label: "Dashboard", href: "/dashboard", active: true },
const menuItems = [
{ icon: Home, label: "Dashboard", href: "/dashboard" },
{ icon: ArrowDownUp, label: "Convert", href: "/dashboard/convert" },
{ icon: Wallet, label: "Transaction", href: "/dashboard/transactions" },
{ icon: User, label: "Profile", href: "/dashboard/profile" },
{ icon: Settings, label: "Setting", href: "/dashboard/settings" },
];

export default function Sidebar() {
const pathname = usePathname();
const router = useRouter();
const { isCollapsed, isMobileOpen, closeMobile, toggleCollapse } =
useSidebarStore();

const [menuItems, setMenuItems] = useState(initialMenuItems);
const router = useRouter();

const handleMenuClick = (href: string, label: string) => {
setMenuItems((prev) =>
prev.map((item) => ({
...item,
active: item.label === label,
}))
);
const handleMenuClick = (href: string) => {
router.push(href);
};

// Close mobile sidebar when clicking outside
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
const sidebar = document.getElementById("sidebar");
const target = event.target as Node;

// Also close on click of a menu item on mobile
const menuButton = (event.target as HTMLElement).closest("button");
if (
isMobileOpen &&
Expand Down Expand Up @@ -109,30 +101,27 @@ export default function Sidebar() {
>
<div className="flex items-center gap-2">
{!isCollapsed && (
<div className="">
<Image src="/logo.png" alt="Logo" width={124} height={42} />
</div>
<Image src="/logo.png" alt="Logo" width={124} height={42} />
)}
</div>
<button
onClick={toggleCollapse}
className="hidden lg:flex p-2 rounded-full hover:bg-gray-100"
>
{isCollapsed ? (
<div className="">
<Image
src="/logo-mini.svg"
alt="Logo"
width={20}
height={20}
/>
</div>
<Image
src="/logo-mini.svg"
alt="Logo"
width={20}
height={20}
/>
) : (
<ChevronLeft className="w-5 h-5 text-gray-500" />
)}
</button>
</div>
</div>

{/* User Profile Section - Mobile */}
<div className="lg:hidden p-4 rounded-lg bg-[linear-gradient(240deg,rgba(160,195,253,0.40)_-1.74%,rgba(255,231,156,0.40)_99.3%)] mb-4">
<div className="flex items-center gap-4">
Expand Down Expand Up @@ -164,15 +153,21 @@ export default function Sidebar() {
</div>
</div>

{/* Menu */}
<ul className="space-y-3 font-medium">
{menuItems.map((item, index) => {
const IconComponent = item.icon;
const isActive =
item.href === "/dashboard"
? pathname === "/dashboard" // Only exact match for dashboard
: pathname.startsWith(item.href); // Prefix match for others

return (
<li key={index}>
<button
onClick={() => handleMenuClick(item.href, item.label)}
onClick={() => handleMenuClick(item.href)}
className={`flex items-center text-text-tertiary rounded-full group ${
item.active
isActive
? "bg-brand-primary text-black"
: "bg-transparent hover:bg-brand-primary/20"
} transition-all duration-300 ${
Expand All @@ -184,25 +179,14 @@ export default function Sidebar() {
>
<IconComponent
className={`w-5 h-5 text-text-tertiary transition duration-75 group-hover:text-black ${
item.active ? "text-black" : ""
isActive ? "text-black" : ""
}`}
/>
{!isCollapsed && <span className="ml-3">{item.label}</span>}
</button>
</li>
);
})}

{/* Logout button */}
{/* <li className="pt-4 mt-4 border-t border-gray-200">
<a
href="/logout"
className="flex items-center p-2 text-gray-900 rounded-lg hover:bg-red-50 hover:text-red-600 group"
title={isCollapsed ? "Logout" : ""}>
<LogOut className="w-5 h-5 text-gray-500 transition duration-75 group-hover:text-red-600" />
{!isCollapsed && <span className="ml-3">Logout</span>}
</a>
</li> */}
</ul>
</div>
</aside>
Expand Down
83 changes: 83 additions & 0 deletions components/settings/Notification.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
"use client";

import { useState } from "react";

export default function NotificationTab() {
const [settings, setSettings] = useState({
inApp: true,
sms: false,
email: true,
transaction: true,
});

const toggle = (key: keyof typeof settings) =>
setSettings({ ...settings, [key]: !settings[key] });

return (
<div className="space-y-6">
<div className="space-y-6 border border-gray-200 p-4 rounded-md">
<h1 className="text-gray-500 font-semibold border-b pb-4">
Notification Push
</h1>
{[
{ key: "inApp", label: "In-app notification" },
{ key: "sms", label: "SMS notification" },
{ key: "email", label: "Email notification" },
{ key: "transaction", label: "Transaction Alert" },
].map((item) => (
<div
key={item.key}
className="flex justify-between items-center pb-2"
>
<div>
<h3 className="font-medium">{item.label}</h3>
<p className="text-xs md:text-sm text-gray-500">
{/* TODO: Add API integration later */}
Placeholder description for {item.label}
</p>
</div>

<label className="relative inline-flex items-center cursor-pointer">
<input
type="checkbox"
checked={settings[item.key as keyof typeof settings]}
onChange={() => toggle(item.key as keyof typeof settings)}
className="sr-only"
/>
<span
className={`w-11 h-6 flex items-center rounded-full p-1 ${
settings[item.key as keyof typeof settings]
? "bg-gradient-to-r from-[#FFA200] to-[#3B82F6]"
: "bg-gray-300"
}`}
>
<span
className={`bg-white w-4 h-4 rounded-full shadow transform duration-300 ${
settings[item.key as keyof typeof settings]
? "translate-x-5"
: ""
}`}
/>
</span>
</label>
</div>
))}{" "}
</div>

{/* Desktop Footer (visible from sm and up) */}
<div className="hidden sm:flex space-x-4 mt-6 justify-end text-sm">
<button className="bg-yellow-500 px-6 py-2 rounded">
Save Changes
</button>
<button className="border px-6 py-2 rounded">Cancel</button>
</div>

{/* Mobile Sticky Footer (only visible on xs screens) */}
<div className="sm:hidden fixed bottom-0 left-0 right-0 text-sm font-semibold p-3">
<button className="bg-yellow-500 px-6 py-3 rounded w-full">
Save Changes
</button>
</div>
</div>
);
}
Loading
Loading