Their three commits (730d0bd,5a9b543,387edfb) reached production by push and auto-deployed.387edfbexpects a users.username column that the live database does not have, so POST /api/v1/auth/login was returning HTTP 500. Their schema changes never applied either (projects still has only id, name, description, start_date, pm_user_id, created_at), so nothing depends on the reverted code. This commit sets the tree back to exactlya02b3ea— verified with git diff against it — while keeping history linear: the work itself is preserved on 'pm' at387edfb.
69 lines
2.8 KiB
TypeScript
69 lines
2.8 KiB
TypeScript
import type { ReactNode } from "react";
|
|
import { useLocation, useNavigate } from "react-router-dom";
|
|
import { ChevronRight, ClipboardList } from "lucide-react";
|
|
import { cn } from "../../lib/utils";
|
|
|
|
interface HeaderProps {
|
|
title: string;
|
|
sub?: string;
|
|
backTo?: string; // مسیر بازگشتِ جایگزین (وقتی سابقهای در برنامه نیست)
|
|
backLabel?: string;
|
|
actions?: ReactNode; // دکمههای سمت چپ
|
|
brand?: boolean; // نمایش آیکون دفتر کنار عنوان
|
|
icon?: ReactNode; // آیکون سفارشی جعبهی کنار منو (پیشفرض: ClipboardList)
|
|
menu?: ReactNode; // منوی همبرگری بالای راست (ناوبری بین پنلها)
|
|
}
|
|
|
|
// نوار بالای هر صفحه: منو (همبرگری) + جعبهی آیکون + عنوان + اکشنها
|
|
export function Header({ title, sub, backTo, backLabel = "بازگشت", actions, brand, icon, menu }: HeaderProps) {
|
|
const navigate = useNavigate();
|
|
const location = useLocation();
|
|
|
|
// اگر کاربر از داخل برنامه به این صفحه آمده، یک قدم برمیگردیم؛
|
|
// اگر مستقیم باز شده (بدون سابقهی داخلی)، به backTo میرویم.
|
|
const goBack = () => {
|
|
if (location.key !== "default") navigate(-1);
|
|
else if (backTo) navigate(backTo);
|
|
};
|
|
|
|
return (
|
|
<header className="flex flex-wrap items-center gap-3 border-b border-line bg-panel px-5 py-2.5 max-md:sticky max-md:top-0 max-md:z-40">
|
|
{menu && <div className="flex shrink-0 items-center">{menu}</div>}
|
|
{(icon || brand) && (
|
|
<span className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-accent-bg text-accent">
|
|
{icon || <ClipboardList className="h-4.5 w-4.5" strokeWidth={2} />}
|
|
</span>
|
|
)}
|
|
{backTo && (
|
|
<button
|
|
type="button"
|
|
onClick={goBack}
|
|
className="hidden md:inline-flex cursor-pointer items-center gap-0.5 rounded-md px-2 py-1 text-[13px] text-muted transition-colors hover:bg-slate-bg hover:text-ink"
|
|
>
|
|
<ChevronRight className="h-4 w-4" />
|
|
{backLabel}
|
|
</button>
|
|
)}
|
|
<div className="flex min-w-0 items-center gap-2.5">
|
|
<div className="min-w-0">
|
|
<h1 className="text-[17px] font-extrabold leading-6">{title}</h1>
|
|
{sub && <div className="text-[11px] text-muted">{sub}</div>}
|
|
</div>
|
|
</div>
|
|
<div className="ms-auto flex flex-wrap items-center gap-2">{actions}</div>
|
|
</header>
|
|
);
|
|
}
|
|
|
|
// بدنهی صفحه با عرض محدود و چینش مرکزی
|
|
export function PageLayout({
|
|
children,
|
|
className,
|
|
}: {
|
|
children: ReactNode;
|
|
className?: string;
|
|
}) {
|
|
return (
|
|
<div className={cn("mx-auto w-full max-w-[1200px] px-4 py-4 max-md:pb-24", className)}>{children}</div>
|
|
);
|
|
} |