Skip to content
Open

Now #910

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
13 changes: 9 additions & 4 deletions frontend/app/admin/dashboard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ import { TVLChart } from "@/components/admin/metrics/TVLChart";
import { AssetDistributionChart } from "@/components/admin/metrics/AssetDistributionChart";
import { adminAPI, AdminMetrics } from "@/app/lib/api/admin";
import { mockAdminMetrics } from "@/lib/mockAdminUsers";
import { useTranslations } from "next-intl";

export default function AdminDashboardPage() {
const t = useTranslations("admin");
const [metrics, setMetrics] = useState<AdminMetrics | null>(null);
const [loading, setLoading] = useState(true);
const [usingMock, setUsingMock] = useState(false);
Expand All @@ -31,14 +33,17 @@ export default function AdminDashboardPage() {
<DashboardLayout>
<div className="space-y-6">
<div>
<h1 className="text-2xl font-semibold text-foreground">Admin Dashboard</h1>
<p className="text-sm text-foreground/50 mt-1">Platform-wide metrics and asset overview</p>
<h1 className="text-2xl font-semibold text-foreground">{t("dashboard")}</h1>
<p className="text-sm text-foreground/50 mt-1">{t("dashboardDesc")}</p>
</div>

{usingMock && (
<div className="rounded-lg border border-yellow-500/20 bg-yellow-500/5 px-4 py-2.5 text-xs text-yellow-400/80">
Backend unavailable — showing mock data derived from local user records. In production, metrics are fetched from{" "}
<code className="font-mono">/api/admin/metrics</code>.
{t("mockDataWarning")}{" "}
<span>
In production, metrics are fetched from{" "}
<code className="font-mono">/api/admin/metrics</code>.
</span>
</div>
)}

Expand Down
12 changes: 7 additions & 5 deletions frontend/app/admin/login/page.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
"use client";
import { useState } from "react";
import { useAdminAuth } from "@/context/AdminAuthContext";
import { useTranslations } from "next-intl";

export default function AdminLoginPage() {
const { login } = useAdminAuth();
const t = useTranslations("admin");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
Expand All @@ -26,14 +28,14 @@ export default function AdminLoginPage() {
<div className="w-full max-w-sm">
<div className="mb-8 text-center">
<h1 className="text-2xl font-semibold text-foreground">InheritX</h1>
<p className="text-sm text-gray-500 mt-1">Admin Portal</p>
<p className="text-sm text-gray-500 mt-1">{t("adminPortal")}</p>
</div>
<div className="bg-white/3 border border-white/10 rounded-2xl p-6">
<h2 className="text-base font-medium text-foreground mb-6">
Sign in to continue
{t("signIn")}
</h2>
<div className="mb-4">
<label className="block text-xs text-gray-500 mb-1.5">Email address</label>
<label className="block text-xs text-gray-500 mb-1.5">{t("emailAddress")}</label>
<input
type="email"
value={email}
Expand All @@ -43,7 +45,7 @@ export default function AdminLoginPage() {
/>
</div>
<div className="mb-6">
<label className="block text-xs text-gray-500 mb-1.5">Password</label>
<label className="block text-xs text-gray-500 mb-1.5">{t("password")}</label>
<input
type="password"
value={password}
Expand All @@ -63,7 +65,7 @@ export default function AdminLoginPage() {
disabled={isLoading || !email || !password}
className="w-full py-2.5 text-sm font-medium rounded-lg bg-primary text-black hover:bg-primary/90 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
>
{isLoading ? "Signing in..." : "Sign in"}
{isLoading ? t("signingIn") : t("signInButton")}
</button>
</div>
</div>
Expand Down
25 changes: 9 additions & 16 deletions frontend/app/admin/users/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ import { AdminUser, KYCStatus } from "@/lib/adminTypes";
import { SearchFilterBar } from "@/components/admin/SearchFilterBar";
import { UserManagementTable } from "@/components/admin/UserManagementTable";
import { Pagination } from "@/components/admin/Pagination";
import { useTranslations } from "next-intl";

const PAGE_SIZE = 10;

export default function AdminUsersPage() {
const t = useTranslations("admin");
const [users, setUsers] = useState<AdminUser[]>(mockUsers);
const [search, setSearch] = useState("");
const [kycFilter, setKycFilter] = useState<KYCStatus | "all">("all");
Expand Down Expand Up @@ -71,29 +73,20 @@ export default function AdminUsersPage() {
{/* Header */}
<div className="mb-8">
<h1 className="text-2xl font-semibold text-foreground">
User Management
{t("userManagement")}
</h1>
<p className="text-sm text-gray-500 mt-1">
Manage users, KYC approvals, and active plans.
{t("userManagementDesc")}
</p>
</div>

{/* Stats row */}
<div className="grid grid-cols-2 sm:grid-cols-4 gap-4 mb-8">
{[
{ label: "Total Users", value: users.length },
{
label: "KYC Pending",
value: users.filter((u) => u.kycStatus === "pending").length,
},
{
label: "Active Users",
value: users.filter((u) => u.status === "active").length,
},
{
label: "Suspended",
value: users.filter((u) => u.status === "suspended").length,
},
{ label: t("totalUsers"), value: users.length },
{ label: t("kycPending"), value: users.filter((u) => u.kycStatus === "pending").length },
{ label: t("activeUsers"), value: users.filter((u) => u.status === "active").length },
{ label: t("suspended"), value: users.filter((u) => u.status === "suspended").length },
].map((stat) => (
<div
key={stat.label}
Expand All @@ -115,7 +108,7 @@ export default function AdminUsersPage() {

{/* Results count */}
<p className="text-xs text-gray-500 mb-3">
Showing {paginated.length} of {filtered.length} users
{t("showing")} {paginated.length} {t("of")} {filtered.length} {t("users")}
</p>

{/* Table */}
Expand Down
18 changes: 9 additions & 9 deletions frontend/app/asset-owner/page.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,36 @@
"use client";
import { useWallet } from "@/context/WalletContext";
import { formatAddress } from "@/util/address";
import { useTranslations } from "next-intl";

export default function AssetOwnerPage() {
const { isConnected, address, openModal } = useWallet();
const t = useTranslations("assetOwner");

return (
<div className="animate-fade-in">
{/* Page heading */}
<div className="mb-8">
<h1 className="text-2xl font-semibold text-foreground">Overview</h1>
<p className="text-sm text-gray-500 mt-1">
Welcome to your InheritX dashboard.
</p>
<h1 className="text-2xl font-semibold text-foreground">{t("overview")}</h1>
<p className="text-sm text-gray-500 mt-1">{t("welcomeDesc")}</p>
</div>

{/* Wallet status card */}
<div className="bg-white/3 border border-white/10 rounded-2xl p-6 max-w-md">
<p className="text-xs text-gray-500 uppercase tracking-wider mb-4">
Wallet Status
{t("walletStatus")}
</p>

{isConnected && address ? (
<div className="flex flex-col gap-3">
<div className="flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-emerald-400 shadow-[0_0_6px_#34d399]" />
<span className="text-sm text-emerald-400 font-medium">
Connected
{t("connected")}
</span>
</div>
<div className="bg-white/5 border border-white/10 rounded-lg px-4 py-3">
<p className="text-xs text-gray-500 mb-1">Wallet Address</p>
<p className="text-xs text-gray-500 mb-1">{t("walletAddress")}</p>
<p className="text-sm font-mono text-primary">
{formatAddress(address)}
</p>
Expand All @@ -40,13 +40,13 @@ export default function AssetOwnerPage() {
<div className="flex flex-col gap-4">
<div className="flex items-center gap-2">
<span className="w-2 h-2 rounded-full bg-gray-600" />
<span className="text-sm text-gray-500">Not connected</span>
<span className="text-sm text-gray-500">{t("notConnected")}</span>
</div>
<button
onClick={openModal}
className="px-4 py-2.5 text-sm font-medium rounded-lg bg-primary text-black hover:bg-primary/90 transition-colors w-fit"
>
Connect Wallet
{t("connectWallet")}
</button>
</div>
)}
Expand Down
39 changes: 22 additions & 17 deletions frontend/app/components/Navbar.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
"use client";

import React, { useState, useEffect } from "react";
import Image from "next/image";
import { ArrowDownRight, Globe, Shield, Zap, Menu, X } from "lucide-react";
import { Menu, X } from "lucide-react";
import Link from "next/link";
import { ConnectButton } from "@/components/ConnectButton";
import { LanguageSwitcher } from "@/components/LanguageSwitcher";
import { useTranslations } from "next-intl";

const Navbar = () => {
const t = useTranslations("navbar");
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
const [isScrolled, setIsScrolled] = useState(false);

Expand All @@ -18,6 +23,7 @@ const Navbar = () => {
}, []);

const closeMenu = () => setIsMobileMenuOpen(false);

return (
<header
className={`sticky top-0 z-50 backdrop-blur-xs transition-all duration-300 ${
Expand Down Expand Up @@ -48,25 +54,25 @@ const Navbar = () => {
href="/"
className="hover:text-cyan-400 transition-colors focus-visible:outline-offset-2 focus-visible:outline-2 focus-visible:outline-cyan-400 rounded-sm px-1"
>
Home
{t("home")}
</Link>
<Link
href="/how-it-works"
className="hover:text-cyan-400 transition-colors focus-visible:outline-offset-2 focus-visible:outline-2 focus-visible:outline-cyan-400 rounded-sm px-1"
>
How it Works
{t("howItWorks")}
</Link>
<Link
href="/faqs"
className="hover:text-cyan-400 transition-colors focus-visible:outline-offset-2 focus-visible:outline-2 focus-visible:outline-cyan-400 rounded-sm px-1"
>
FAQs
{t("faqs")}
</Link>
<Link
href="/contact"
className="hover:text-cyan-400 transition-colors focus-visible:outline-offset-2 focus-visible:outline-2 focus-visible:outline-cyan-400 rounded-sm px-1"
>
Contact
{t("contact")}
</Link>
</div>
</div>
Expand All @@ -92,40 +98,39 @@ const Navbar = () => {
onClick={closeMenu}
className="text-slate-300 hover:text-cyan-400 py-2 focus-visible:outline-offset-2 focus-visible:outline-2 focus-visible:outline-cyan-400 rounded-sm px-2 uppercase"
>
Home
{t("home")}
</Link>
<Link
href="/how-it-works"
onClick={closeMenu}
className="text-slate-300 hover:text-cyan-400 py-2 focus-visible:outline-offset-2 focus-visible:outline-2 focus-visible:outline-cyan-400 rounded-sm px-2 uppercase"
>
How it Works
{t("howItWorks")}
</Link>
<Link
href="/faqs"
onClick={closeMenu}
className="text-slate-300 hover:text-cyan-400 py-2 focus-visible:outline-offset-2 focus-visible:outline-2 focus-visible:outline-cyan-400 rounded-sm px-2 uppercase"
>
FAQs
{t("faqs")}
</Link>
<Link
href="/contact"
onClick={closeMenu}
className="text-slate-300 hover:text-cyan-400 py-2 focus-visible:outline-offset-2 focus-visible:outline-2 focus-visible:outline-cyan-400 rounded-sm px-2 uppercase"
>
Contact
{t("contact")}
</Link>

<button
className="flex justify-center items-center gap-4 text-[14px] border-[0.5px] border-[#33C5E03D] bg-[#161E22] px-4 py-3 rounded-lg text-slate-300 hover:border-cyan-400 transition-all w-full focus-visible:outline-offset-2 focus-visible:outline-2 focus-visible:outline-cyan-400 active:scale-95"
aria-label="Connect wallet"
>
Connect Wallet <ArrowDownRight size={16} aria-hidden={true} />
</button>
<LanguageSwitcher />
</div>
)}

<ConnectButton />
<div className="flex items-center gap-3">
<div className="hidden md:block">
<LanguageSwitcher />
</div>
<ConnectButton />
</div>
</nav>
</header>
);
Expand Down
16 changes: 9 additions & 7 deletions frontend/app/components/landing/AboutSection.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
"use client";

import Image from "next/image";
import { useTranslations } from "next-intl";

export default function AboutSection() {
const t = useTranslations("landing");

return (
<section
id="about"
Expand All @@ -10,28 +15,25 @@ export default function AboutSection() {
>
<div className="max-w-3xl mx-auto">
<h2 className="text-[#FCFFFF] uppercase tracking-[0.3em] text-[32px] mb-4 animate-slide-up">
What is InheritX?
{t("aboutTitle")}
</h2>
<h3
className="text-[#92A5A8] text-[14px] font-bold mb-6 animate-slide-up"
style={{ animationDelay: "0.1s" }}
>
Without roots, nothing grows.
{t("aboutTagline")}
</h3>
<p
className="text-[18px] text-[#FCFFFF] leading-relaxed mb-8 animate-slide-up"
style={{ animationDelay: "0.2s" }}
>
InheritX simplifies digital wealth transfer by introducing yield-generating
inheritance plans with multi-beneficiary allocations. Your locked assets accrue interest
continuously, maximizing the value passed to your heirs.
{t("aboutBody1")}
</p>
<div
className="text-[18px] text-[#FCFFFF] animate-slide-up"
style={{ animationDelay: "0.3s" }}
>
Through integrated Stellar Anchors, your heirs receive payouts directly
in their local fiat bank accounts or mobile money wallets, bypassing any Web3 complexity.
{t("aboutBody2")}
</div>
</div>
{/* Decorative tree-like background glow */}
Expand Down
Loading
Loading