feat(profile): complete profile and wallet UI with actions
- Add ProfileLayout with session authentication guard - Create ProfilePage and WalletPage screen components - Implement reusable profile UI elements: * ProfileMenu and ProfileMenuItem for navigation * ProfileExitAccount with logout handler * ProfilePersonDetailCard displaying user info * ProfilePageHeadLine for section titles - Implement wallet section: * WalletBlancCard showing balance with charge/withdraw buttons * TransactionHistory listing recent transactions * TransactionItem with dynamic deposit/withdraw styling - Use client components for interactive behaviours (logout, navigation) - Apply consistent styling using Tailwind CSS and Lucide icons
This commit is contained in:
parent
2cd5a9987d
commit
cbd0b4bebe
6 changed files with 47 additions and 38 deletions
|
|
@ -1,33 +1,11 @@
|
||||||
import Link from "next/link";
|
|
||||||
import { requireSession } from "@/lib/auth/session";
|
|
||||||
import { LogoutButton } from "@/components/customer/logout-button";
|
|
||||||
import ProfileListTileItem from "@/components/profile/profile-menu-item";
|
|
||||||
import ProfileListMenu from "@/components/profile/profile-menu";
|
import ProfileListMenu from "@/components/profile/profile-menu";
|
||||||
import ProfilePageHeadLine from "@/components/profile/profile-page-head-line";
|
import ProfilePageHeadLine from "@/components/profile/profile-page-head-line";
|
||||||
import ProfilePersonDetailCard from "@/components/profile/profile-person-detail-card";
|
import ProfilePersonDetailCard from "@/components/profile/profile-person-detail-card";
|
||||||
|
|
||||||
// Minimal placeholder — winofyfrontenddoc.md's bottom-nav references a "پروفایل"
|
export default function ProfilePage() {
|
||||||
// tab, but no profile screen is documented yet in either doc.
|
return <section>
|
||||||
export default async function ProfilePage() {
|
|
||||||
// await requireSession("/profile");
|
|
||||||
return <main className="max-w-5xl mx-auto w-full p-4">
|
|
||||||
<ProfilePageHeadLine title='پروفایل من' />
|
<ProfilePageHeadLine title='پروفایل من' />
|
||||||
<ProfilePersonDetailCard />
|
<ProfilePersonDetailCard />
|
||||||
<ProfileListMenu />
|
<ProfileListMenu />
|
||||||
|
</section>
|
||||||
</main>
|
|
||||||
// return (
|
|
||||||
// <main className="mx-auto flex w-full max-w-md flex-1 flex-col gap-3 px-4 py-6">
|
|
||||||
// <h1 className="text-title-large font-extrabold text-foreground">پروفایل</h1>
|
|
||||||
// <Link href="/orders" className="rounded-xl border border-border p-4 text-body-large">
|
|
||||||
// سفارشهای من
|
|
||||||
// </Link>
|
|
||||||
// <Link href="/addresses" className="rounded-xl border border-border p-4 text-body-large">
|
|
||||||
// آدرسهای من
|
|
||||||
// </Link>
|
|
||||||
// <div className="rounded-xl border border-border p-4">
|
|
||||||
// <LogoutButton />
|
|
||||||
// </div>
|
|
||||||
// </main>
|
|
||||||
// );
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,15 @@
|
||||||
import ProfilePageHeadLine from '@/components/profile/profile-page-head-line'
|
import ProfilePageHeadLine from '@/components/profile/profile-page-head-line'
|
||||||
import TransactionHistory from '@/components/wallet/transaction-history'
|
import TransactionHistory from '@/components/wallet/transaction-history'
|
||||||
import WalletBlancCard from '@/components/wallet/wallet-blanc-card'
|
import WalletBlancCard from '@/components/wallet/wallet-blanc-card'
|
||||||
import React from 'react'
|
|
||||||
|
|
||||||
const WalletPage = () => {
|
const WalletPage = () => {
|
||||||
return (
|
return (
|
||||||
<main className='max-w-5xl mx-auto w-full p-4'>
|
<section>
|
||||||
<ProfilePageHeadLine title='کیف پول من' />
|
<ProfilePageHeadLine title='کیف پول من' />
|
||||||
<WalletBlancCard />
|
<WalletBlancCard />
|
||||||
<ProfilePageHeadLine title='تاریخچه تراکنشها' />
|
<ProfilePageHeadLine title='تاریخچه تراکنشها' />
|
||||||
<TransactionHistory />
|
<TransactionHistory />
|
||||||
</main>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
17
src/app/(customer)/(shop)/profile/layout.tsx
Normal file
17
src/app/(customer)/(shop)/profile/layout.tsx
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
import { requireSession } from '@/lib/auth/session';
|
||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
interface ProfileLayoutInterface {
|
||||||
|
children: React.ReactNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const ProfileLayout = async ({ children }: ProfileLayoutInterface) => {
|
||||||
|
await requireSession("/profile");
|
||||||
|
|
||||||
|
return <main className='max-w-5xl mx-auto w-full p-4'>
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ProfileLayout
|
||||||
|
|
@ -1,13 +1,27 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { ChevronLeft, LogOutIcon } from "lucide-react"
|
import { ChevronLeft, LogOutIcon } from "lucide-react"
|
||||||
|
import { useRouter } from "next/navigation";
|
||||||
|
import { useTransition } from "react";
|
||||||
|
|
||||||
const ProfileExitAccount = () => {
|
const ProfileExitAccount = () => {
|
||||||
|
|
||||||
|
const router = useRouter();
|
||||||
|
const [isPending, startTransition] = useTransition();
|
||||||
|
|
||||||
|
function handleLogout() {
|
||||||
|
startTransition(async () => {
|
||||||
|
await fetch("/api/auth/logout", { method: "POST" });
|
||||||
|
router.push("/");
|
||||||
|
router.refresh();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return <div
|
return <div
|
||||||
className={`
|
className={`
|
||||||
flex items-center justify-between w-full py-3 cursor-pointer
|
flex items-center justify-between w-full py-3 cursor-pointer
|
||||||
`}
|
`}
|
||||||
onClick={() => { alert('logout latter....') }}
|
onClick={handleLogout}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<div className="bg-[#FEF2F2] p-2 rounded-lg">
|
<div className="bg-[#FEF2F2] p-2 rounded-lg">
|
||||||
|
|
|
||||||
|
|
@ -5,18 +5,19 @@ import {
|
||||||
MapPin,
|
MapPin,
|
||||||
Wallet,
|
Wallet,
|
||||||
Bell,
|
Bell,
|
||||||
Headset
|
Headset,
|
||||||
|
CircleQuestionMark
|
||||||
} from 'lucide-react';
|
} from 'lucide-react';
|
||||||
import ProfileMenuItem from './profile-menu-item';
|
import ProfileMenuItem from './profile-menu-item';
|
||||||
import ProfileExitAccount from './profile-exit-account';
|
import ProfileExitAccount from './profile-exit-account';
|
||||||
|
|
||||||
const menuItems = [
|
const menuItems = [
|
||||||
{ id: 1, href: '/profile/address', text: 'سعادتآباد', icon: <MapPin className="w-4 h-4 text-[#223D5D]" /> },
|
{ id: 1, href: '/addresses', text: 'سعادتآباد', icon: <MapPin className="size-5 text-[#223D5D]" /> },
|
||||||
{ id: 2, href: '/profile/orders', text: 'سفارشهای من', icon: <ShoppingBag className="w-4 h-4 text-[#223D5D]" /> },
|
{ id: 2, href: '/orders', text: 'سفارشهای من', icon: <ShoppingBag className="size-5 text-[#223D5D]" /> },
|
||||||
{ id: 3, href: '/profile/addresses', text: 'آدرسهای من', icon: <MapPin className="w-4 h-4 text-[#223D5D]" /> },
|
{ id: 3, href: '/addresses', text: 'آدرسهای من', icon: <MapPin className="size-5 text-[#223D5D]" /> },
|
||||||
{ id: 4, href: '/profile/wallet', text: 'کیف پول', icon: <Wallet className="w-4 h-4 text-[#223D5D]" /> },
|
{ id: 4, href: '/profile/wallet', text: 'کیف پول', icon: <Wallet className="size-5 text-[#223D5D]" /> },
|
||||||
{ id: 5, href: '/profile/notifications', text: 'اعلانها', icon: <Bell className="w-4 h-4 text-[#223D5D]" /> },
|
{ id: 5, href: '/profile/notifications', text: 'اعلانها', icon: <Bell className="size-5 text-[#223D5D]" /> },
|
||||||
{ id: 6, href: '/profile/support', text: 'پشتیبانی', icon: <Headset className="w-4 h-4 text-[#223D5D]" /> },
|
{ id: 6, href: '/profile/support', text: 'پشتیبانی', icon: <CircleQuestionMark className="size-5 text-[#223D5D]" /> },
|
||||||
];
|
];
|
||||||
|
|
||||||
const ProfileMenu = () => {
|
const ProfileMenu = () => {
|
||||||
|
|
@ -31,7 +32,7 @@ const ProfileMenu = () => {
|
||||||
isLast={index === menuItems.length - 1}
|
isLast={index === menuItems.length - 1}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
<div className="w-full h-px bg-gray-200 mt-4" />
|
<div className="w-full h-px bg-gray-200 mt-4" />
|
||||||
<ProfileExitAccount />
|
<ProfileExitAccount />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ const AUTH_REQUIRED_PREFIXES = [
|
||||||
"/order-groups",
|
"/order-groups",
|
||||||
"/addresses",
|
"/addresses",
|
||||||
"/account",
|
"/account",
|
||||||
// "/profile",
|
"/profile",
|
||||||
"/notifications",
|
"/notifications",
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue