Hamdast1/src/app/components/AppHeader.tsx
reza7321 213c0a70f0 امروز ۳۱ اردیبهشت
چت بات عمومی خرابه
2026-05-21 14:50:03 +03:30

163 lines
5.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useEffect, useMemo, useState } from "react";
import { useNavigate } from "react-router-dom";
import { ChevronRight, Plus } from "lucide-react";
import { useProfile } from "../context/ProfileContext";
import { getCachedProfile } from "../../services/profileService";
import { getProfileImageUrl } from "../../services/feedService";
import logoImage from "figma:asset/0a77244cc5b7dea0bea10275d45df2915d5170ca.png";
import coinImage from "../../assets/coin-star.png";
import profileFallbackImage from "../../assets/image 5.png";
interface AppHeaderProps {
showBack?: boolean;
onBack?: () => void;
centerTitle?: string;
centerSubtitle?: string;
}
const toPersianNumber = (num: number | null | undefined): string => {
if (num === null || num === undefined) return "۰";
const persianDigits = "۰۱۲۳۴۵۶۷۸۹";
return String(num).replace(/\d/g, (digit) => persianDigits[parseInt(digit, 10)]);
};
export function AppHeader({ showBack = false, onBack, centerTitle, centerSubtitle }: AppHeaderProps) {
const navigate = useNavigate();
const { profile } = useProfile();
const [displayCoins, setDisplayCoins] = useState<number>(() => {
const cachedProfile = getCachedProfile();
return cachedProfile?.coin_count ?? 0;
});
useEffect(() => {
if (profile?.coin_count !== null && profile?.coin_count !== undefined) {
setDisplayCoins(profile.coin_count);
}
}, [profile]);
const hasCustomAvatar = Boolean(profile?.image && profile?.user_stage_id);
const avatarUrl = useMemo(() => {
if (hasCustomAvatar) {
return getProfileImageUrl(profile.image, profile.user_stage_id);
}
return profileFallbackImage;
}, [hasCustomAvatar, profile?.image, profile?.user_stage_id]);
const navLikePanelStyle = {
backgroundImage: `
linear-gradient(180deg, #2E1B3D 0%, #23183E 100%),
linear-gradient(120deg, #7c3aed 0%, #f97316 58%, #facc15 100%)
`,
backgroundOrigin: "border-box",
backgroundClip: "padding-box, border-box",
boxShadow:
"0 -7px 20px rgba(7, 0, 18, 0.5), 0 6px 14px rgba(5, 2, 12, 0.26), inset 0 1px 0 rgba(255, 255, 255, 0.2), inset 0 2px 5px rgba(255, 222, 255, 0.09), inset 0 -2px 0 rgba(12, 7, 27, 0.72), inset 0 -8px 14px rgba(8, 4, 18, 0.34), inset 0 0 0 1px rgba(255, 255, 255, 0.045), inset 0 0 0 2px rgba(17, 10, 35, 0.32)",
backdropFilter: "blur(14px)",
WebkitBackdropFilter: "blur(14px)",
} as const;
return (
<div className="relative z-20 flex items-center justify-between px-4 pt-3 pb-0" dir="rtl">
{showBack ? (
<button
onClick={onBack}
className="w-11 h-11 rounded-full flex items-center justify-center border-[0.5px] border-transparent"
aria-label="بازگشت"
style={navLikePanelStyle}
>
<ChevronRight size={22} color="#ffffff" />
</button>
) : (
<button
onClick={() => navigate("/profile")}
className="relative w-12 h-12 rounded-full p-[2px] border-[0.5px] border-transparent overflow-hidden"
aria-label="پروفایل"
style={navLikePanelStyle}
>
{hasCustomAvatar ? (
<img
src={avatarUrl}
alt="پروفایل"
className="w-full h-full rounded-full object-cover"
onError={(event) => {
event.currentTarget.src = profileFallbackImage;
}}
/>
) : (
<div
className="w-full h-full rounded-full flex items-center justify-center"
style={navLikePanelStyle}
>
<img
src={profileFallbackImage}
alt="پروفایل پیش‌فرض"
className=" object-cover rounded-full"
/>
</div>
)}
</button>
)}
<div className="absolute inset-0 pointer-events-none flex items-center justify-center text-center translate-y-1">
{centerTitle ? (
<div className="leading-none">
<div
className="font-extrabold text-[22px]"
style={{
display: "inline-block",
background:
"linear-gradient(90deg, #F6D8A5 0%, #F3A599 20%, #DB7EB2 48%, #AA6798 72%, #CB75AB 100%)",
WebkitBackgroundClip: "text",
backgroundClip: "text",
WebkitTextFillColor: "transparent",
color: "transparent",
textShadow: "0 2px 10px rgba(255, 119, 202, 0.4)",
}}
>
{centerTitle}
</div>
{centerSubtitle && (
<div
className="mt-1 text-[11px] font-medium"
style={{
color: "#ffb7dd",
textShadow: "0 1px 6px rgba(255, 119, 202, 0.35)",
}}
>
{centerSubtitle}
</div>
)}
</div>
) : (
<img
src={logoImage}
alt="مدرسه"
className="h-12 object-contain"
style={{ filter: "drop-shadow(0 2px 6px rgba(192, 132, 252, 0.55))" }}
/>
)}
</div>
<div
className="relative h-10 w-fit rounded-full px-2.5 flex items-center gap-[6px] border-[0.5px] border-transparent"
style={navLikePanelStyle}
>
<div
className="w-5 h-5 rounded-full flex items-center justify-center border-[0.5px] border-transparent"
style={navLikePanelStyle}
>
<Plus size={11} color="#ffd6f0" strokeWidth={2.25} />
</div>
<span
className="font-semibold leading-none text-white tracking-tight"
style={{ fontSize: 16 }}
>
{toPersianNumber(displayCoins)}
</span>
<img src={coinImage} alt="سکه" className="w-7 h-7 object-contain -my-0.5" />
</div>
</div>
);
}