Browse Source
feat: implement marriage domain types, localization, and new pages for banned and accepted status management.
staging
feat: implement marriage domain types, localization, and new pages for banned and accepted status management.
staging
14 changed files with 300 additions and 34 deletions
-
1src/app/[lang]/banned/page.tsx
-
195src/app/banned/banned-client.tsx
-
5src/app/banned/page.tsx
-
8src/app/request-accepted/request-accepted-client.test.tsx
-
11src/app/request-accepted/request-accepted-client.tsx
-
2src/components/Componentes/navigation-button.tsx
-
5src/components/Componentes/subscription-required-sheet.tsx
-
5src/components/Componentes/support-sheet.tsx
-
9src/hooks/marriage/types.ts
-
4src/lib/get-submit-path.ts
-
9src/translations/locales/ar.json
-
33src/translations/locales/en.json
-
37src/translations/locales/fa.json
-
6src/translations/path_to_english.json
@ -0,0 +1 @@ |
|||
export { default } from "@/app/banned/page"; |
|||
@ -0,0 +1,195 @@ |
|||
"use client"; |
|||
|
|||
import React from "react"; |
|||
import { useRouter } from "next/navigation"; |
|||
import { useHardwareBackHandler } from "@/hooks/use-hardware-back-handler"; |
|||
import { useHabibWebReady } from "@/hooks/use-habib-web-ready"; |
|||
import { PageBackground } from "@/components/Componentes/page-background"; |
|||
import PageHeader from "@/components/Componentes/page-header"; |
|||
import { openDirectSupportContact } from "@/components/Componentes/support-access"; |
|||
import { useMarriageProfileQuery } from "@/hooks/marriage/use-profile-main"; |
|||
import { useI18n } from "@/translations/provider"; |
|||
|
|||
function ShieldAlertIcon(props: React.SVGProps<SVGSVGElement>) { |
|||
return ( |
|||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}> |
|||
<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z" /> |
|||
<line x1="12" y1="8" x2="12" y2="12" strokeWidth="2.4" /> |
|||
<circle cx="12" cy="16" r="1" fill="currentColor" /> |
|||
</svg> |
|||
); |
|||
} |
|||
|
|||
function LockIcon(props: React.SVGProps<SVGSVGElement>) { |
|||
return ( |
|||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2" strokeLinecap="round" strokeLinejoin="round" {...props}> |
|||
<rect x="3" y="11" width="18" height="11" rx="2" ry="2" /> |
|||
<path d="M7 11V7a5 5 0 0 1 10 0v4" /> |
|||
</svg> |
|||
); |
|||
} |
|||
|
|||
function InfoIcon(props: React.SVGProps<SVGSVGElement>) { |
|||
return ( |
|||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}> |
|||
<circle cx="12" cy="12" r="10" /> |
|||
<line x1="12" y1="16" x2="12" y2="12" strokeWidth="2.2" /> |
|||
<circle cx="12" cy="8" r="1" fill="currentColor" /> |
|||
</svg> |
|||
); |
|||
} |
|||
|
|||
function AlertTriangleIcon(props: React.SVGProps<SVGSVGElement>) { |
|||
return ( |
|||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}> |
|||
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3Z" /> |
|||
<line x1="12" y1="9" x2="12" y2="13" /> |
|||
<line x1="12" y1="17" x2="12.01" y2="17" /> |
|||
</svg> |
|||
); |
|||
} |
|||
|
|||
function HeadsetIcon(props: React.SVGProps<SVGSVGElement>) { |
|||
return ( |
|||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" {...props}> |
|||
<path d="M3 18v-6a9 9 0 0 1 18 0v6" /> |
|||
<path d="M21 19a2 2 0 0 1-2 2h-1a2 2 0 0 1-2-2v-3a2 2 0 0 1 2-2h3zM3 19a2 2 0 0 0 2 2h1a2 2 0 0 0 2-2v-3a2 2 0 0 0-2-2H3z" /> |
|||
</svg> |
|||
); |
|||
} |
|||
|
|||
function ArrowRightIcon(props: React.SVGProps<SVGSVGElement>) { |
|||
return ( |
|||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.4" strokeLinecap="round" strokeLinejoin="round" {...props}> |
|||
<line x1="5" y1="12" x2="19" y2="12" /> |
|||
<polyline points="12 5 19 12 12 19" /> |
|||
</svg> |
|||
); |
|||
} |
|||
|
|||
export default function BannedClient() { |
|||
const { dictionary: t } = useI18n(); |
|||
const router = useRouter(); |
|||
|
|||
const { data: profile } = useMarriageProfileQuery({ |
|||
refetchInterval: 5000, |
|||
}); |
|||
|
|||
useHardwareBackHandler(() => { |
|||
// Hardware back closes the service in Flutter
|
|||
return false; |
|||
}); |
|||
|
|||
useHabibWebReady(true); |
|||
|
|||
const banReasonKey = profile?.ban_reason || profile?.ban_info?.reason; |
|||
const dict = t as Record<string, string>; |
|||
const translatedBanReason = banReasonKey ? (dict[banReasonKey] || banReasonKey) : null; |
|||
|
|||
return ( |
|||
<> |
|||
<PageBackground /> |
|||
|
|||
<PageHeader |
|||
profile={profile} |
|||
sticky |
|||
leftButton={{ |
|||
icon: "back", |
|||
onClick: () => { |
|||
if (typeof window !== "undefined" && (window as any).HabibApp) { |
|||
(window as any).HabibApp.postMessage( |
|||
JSON.stringify({ action: "close_service" }), |
|||
); |
|||
} else { |
|||
router.back(); |
|||
} |
|||
}, |
|||
}} |
|||
rightButton={{ |
|||
icon: "support", |
|||
onClick: openDirectSupportContact, |
|||
}} |
|||
/> |
|||
|
|||
<main className="relative z-10 flex min-h-[calc(100dvh-56px-max(12px,calc(var(--safe-top)+4px)))] flex-col justify-between px-5 pb-6 pt-2 max-w-md mx-auto w-full"> |
|||
{/* Top/Center Content Section */} |
|||
<section className="flex flex-1 flex-col items-center pt-8 sm:pt-12 w-full"> |
|||
{/* Circular Glowing Orb Illustration (Properly Boxed & Scaled) */} |
|||
<div className="relative flex size-32 sm:size-36 items-center justify-center shrink-0"> |
|||
{/* Outer Orbit Lines */} |
|||
<div className="absolute inset-0 rounded-full border border-pink-300/40 pointer-events-none" /> |
|||
<div className="absolute inset-3 sm:inset-4 rounded-full border border-dashed border-pink-200/40 pointer-events-none" /> |
|||
|
|||
{/* Decorative Floating Dots */} |
|||
<div className="absolute top-2 left-5 size-2 rounded-full bg-rose-400/70" /> |
|||
<div className="absolute top-6 right-3 size-1.5 rounded-full bg-pink-300/80" /> |
|||
<div className="absolute bottom-4 left-6 size-1.5 rounded-full bg-rose-300/70" /> |
|||
<div className="absolute bottom-3 right-6 size-2 rounded-full bg-rose-400/70" /> |
|||
|
|||
{/* Diffuse Soft Pink Glow */} |
|||
<div className="absolute size-24 sm:size-28 rounded-full bg-[#E03950]/15 blur-xl pointer-events-none" /> |
|||
|
|||
{/* Main Central Orb */} |
|||
<div className="relative flex size-18 sm:size-20 items-center justify-center rounded-full bg-gradient-to-tr from-[#D91B42] via-[#F43F5E] to-[#FB7185] text-white shadow-[0_10px_24px_rgba(225,29,72,0.3)] ring-4 ring-rose-100/80"> |
|||
{/* Subtle top specular sheen */} |
|||
<div className="absolute inset-0.5 rounded-full bg-gradient-to-b from-white/30 to-transparent pointer-events-none" /> |
|||
<ShieldAlertIcon className="size-8 sm:size-9 stroke-[1.8] text-white drop-shadow-xs" /> |
|||
</div> |
|||
|
|||
{/* Overlapping Lock Badge */} |
|||
<div className="absolute -bottom-0.5 -right-0.5 flex size-6.5 sm:size-7 items-center justify-center rounded-full bg-gradient-to-tr from-[#9F1239] via-[#E11D48] to-[#F43F5E] text-white shadow-md ring-2.5 ring-white"> |
|||
<LockIcon className="size-3.5 sm:size-3.5 text-white" /> |
|||
</div> |
|||
</div> |
|||
|
|||
{/* Single Clear Heading (High Contrast, Standard Spacing) */} |
|||
<h1 className="mt-6 text-[18px] sm:text-[20px] font-black text-[#171717] tracking-normal leading-snug text-center"> |
|||
{t["Account Suspended"] || t["ACCOUNT SUSPENDED"] || "دسترسی حساب کاربری محدود شده است"} |
|||
</h1> |
|||
|
|||
{/* Standard Habib Warning/Alert Box Style */} |
|||
<aside className="mt-5 w-full rounded-[20px] border border-[#FDA4AF]/60 bg-[#FFF5F6] p-4 text-start shadow-[0_4px_16px_rgba(244,63,94,0.05)]"> |
|||
<div className="flex items-start gap-3 sm:gap-3.5"> |
|||
{/* Warning Icon Badge */} |
|||
<div className="flex size-10 shrink-0 items-center justify-center rounded-full bg-[#FFE4E8] text-[#E03950]"> |
|||
<InfoIcon className="size-5 stroke-[2.2]" /> |
|||
</div> |
|||
|
|||
{/* Text Content */} |
|||
<div className="space-y-2.5 flex-1 min-w-0 pt-0.5"> |
|||
<p className="text-[13px] text-[#4B5563] leading-[1.6] font-medium"> |
|||
{t["Account Suspended Notice"] || |
|||
"بر اساس قوانین و بررسیهای نظارتی سامانه، دسترسی حساب کاربری شما به بخش خدمات موقتاً مسدود گردیده است. برای کسب اطلاعات بیشتر، پیگیری و رفع ابهام، لطفاً با مشاوران در ارتباط باشید."} |
|||
</p> |
|||
|
|||
{/* Specific Ban Reason Badge */} |
|||
{translatedBanReason && ( |
|||
<div className="inline-flex items-center gap-1.5 px-3 py-1.5 rounded-xl bg-white/95 border border-[#FECDD3] text-[#BE123C] text-[11px] sm:text-xs font-bold shadow-3xs"> |
|||
<AlertTriangleIcon className="size-3.5 shrink-0 text-[#E03950]" /> |
|||
<span> |
|||
<strong className="font-extrabold">{t["Ban Reason"] || "دلیل محدودیت:"}</strong>{" "} |
|||
{translatedBanReason} |
|||
</span> |
|||
</div> |
|||
)} |
|||
</div> |
|||
</div> |
|||
</aside> |
|||
</section> |
|||
|
|||
{/* Footer Action Button (Matching Habib Frontend Primary Button Style) */} |
|||
<div className="mt-auto pt-8 pb-2 w-full"> |
|||
<button |
|||
type="button" |
|||
onClick={openDirectSupportContact} |
|||
className="w-full h-[52px] rounded-2xl bg-gradient-to-r from-[#FE6F82] via-[#F43F5E] to-[#E03950] text-white text-[15px] font-bold shadow-lg shadow-[#E03950]/25 hover:shadow-xl hover:shadow-[#E03950]/35 active:scale-[0.98] transition-all flex items-center justify-center gap-2.5 px-6 cursor-pointer" |
|||
> |
|||
<HeadsetIcon className="size-5 shrink-0" /> |
|||
<span>{t["Contact Advisors"] || t["Contact Support"] || "تماس با مشاوران"}</span> |
|||
<ArrowRightIcon className="size-4.5 shrink-0 rtl:rotate-180" /> |
|||
</button> |
|||
</div> |
|||
</main> |
|||
</> |
|||
); |
|||
} |
|||
@ -0,0 +1,5 @@ |
|||
import BannedClient from "./banned-client"; |
|||
|
|||
export default function BannedPage() { |
|||
return <BannedClient />; |
|||
} |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue