Add structured rejection reasons (checkable presets + free text)
The reject modal now offers 5 common rejection reasons as tickable options (no photo, incomplete info, looks fake/bot, inappropriate photos, contact info in profile), combined with an optional free-text note. The combined string is sent as the existing reason field — no backend change needed. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,7 @@ import {
|
||||
Heart,
|
||||
Sparkles,
|
||||
Search,
|
||||
Check,
|
||||
} from "lucide-react";
|
||||
import { Card } from "@/components/ui/Card";
|
||||
import { Avatar } from "@/components/ui/Avatar";
|
||||
@@ -260,6 +261,15 @@ export default function UserReviewPage() {
|
||||
);
|
||||
}
|
||||
|
||||
// دلایل رایج رد پروفایل — ادمین تیک میزنه، متن نهایی خودکار برای کاربر ساخته میشه
|
||||
const COMMON_REASONS = [
|
||||
"عکس پروفایل نداره یا واضح نیست",
|
||||
"اطلاعات پروفایل ناقصه",
|
||||
"پروفایل به نظر جعلی یا ربات میاد",
|
||||
"محتوای عکسها نامناسبه",
|
||||
"توی پروفایل شماره تماس یا لینک گذاشته",
|
||||
];
|
||||
|
||||
function RejectModal({
|
||||
open,
|
||||
onClose,
|
||||
@@ -271,14 +281,25 @@ function RejectModal({
|
||||
onConfirm: (reason: string) => void;
|
||||
loading: boolean;
|
||||
}) {
|
||||
const [reason, setReason] = useState("");
|
||||
const [selected, setSelected] = useState<string[]>([]);
|
||||
const [extra, setExtra] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
// eslint-disable-next-line react-hooks/set-state-in-effect
|
||||
if (open) setReason("");
|
||||
setSelected([]);
|
||||
setExtra("");
|
||||
}
|
||||
}, [open]);
|
||||
|
||||
const valid = reason.trim().length >= 3;
|
||||
function toggle(text: string) {
|
||||
setSelected((prev) =>
|
||||
prev.includes(text) ? prev.filter((t) => t !== text) : [...prev, text]
|
||||
);
|
||||
}
|
||||
|
||||
const finalReason = [...selected, extra.trim()].filter(Boolean).join("؛ ");
|
||||
const valid = finalReason.length >= 3;
|
||||
|
||||
return (
|
||||
<Modal open={open} onClose={onClose} title="رد کردن کاربر">
|
||||
@@ -287,15 +308,49 @@ function RejectModal({
|
||||
<label className="text-[13px] font-semibold text-(--color-content-secondary) px-1">
|
||||
دلیل رد (برای کاربر نمایش داده میشه)
|
||||
</label>
|
||||
<div className="flex flex-col gap-2">
|
||||
{COMMON_REASONS.map((text) => {
|
||||
const checked = selected.includes(text);
|
||||
return (
|
||||
<button
|
||||
key={text}
|
||||
type="button"
|
||||
onClick={() => toggle(text)}
|
||||
className={`flex items-center gap-2.5 rounded-(--radius-sm) border-2 px-3.5 py-2.5 text-right text-[13px] font-medium transition-colors ${
|
||||
checked
|
||||
? "border-(--color-brand-500) bg-(--color-surface-interactive) text-(--color-brand-700)"
|
||||
: "border-(--color-border-default) text-(--color-content-secondary)"
|
||||
}`}
|
||||
>
|
||||
<span
|
||||
className={`h-5 w-5 rounded-(--radius-xs) flex items-center justify-center shrink-0 border-2 ${
|
||||
checked
|
||||
? "bg-(--color-brand-500) border-(--color-brand-500)"
|
||||
: "border-(--color-border-default)"
|
||||
}`}
|
||||
>
|
||||
{checked && <Check size={13} className="text-white" strokeWidth={3} />}
|
||||
</span>
|
||||
{text}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-1.5">
|
||||
<label className="text-[13px] font-semibold text-(--color-content-secondary) px-1">
|
||||
توضیح تکمیلی (اختیاری)
|
||||
</label>
|
||||
<textarea
|
||||
value={reason}
|
||||
onChange={(e) => setReason(e.target.value)}
|
||||
rows={4}
|
||||
placeholder="مثلاً: عکس پروفایل نداره یا اطلاعات ناقصه"
|
||||
value={extra}
|
||||
onChange={(e) => setExtra(e.target.value)}
|
||||
rows={2}
|
||||
placeholder="اگه دلیل دیگهای هست بنویس..."
|
||||
className="rounded-(--radius-sm) border-2 border-(--color-border-default) bg-(--color-surface-default) px-4 py-3 text-[14px] focus:outline-none focus:border-(--color-border-interactive) focus:ring-4 focus:ring-(--color-brand-100) resize-none"
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end gap-2 pt-2">
|
||||
<Button variant="ghost" size="sm" onClick={onClose}>
|
||||
انصراف
|
||||
@@ -305,7 +360,7 @@ function RejectModal({
|
||||
isLoading={loading}
|
||||
disabled={!valid}
|
||||
className="!bg-(--color-status-error) !shadow-none hover:!bg-red-700"
|
||||
onClick={() => onConfirm(reason.trim())}
|
||||
onClick={() => onConfirm(finalReason)}
|
||||
>
|
||||
رد کردن کاربر
|
||||
</Button>
|
||||
|
||||
Reference in New Issue
Block a user