feat(settings): restructure settings into payment, shipping, and rich page builder v2 with SEO and icons
Some checks failed
Deploy Canina / deploy (push) Has been cancelled
Some checks failed
Deploy Canina / deploy (push) Has been cancelled
This commit is contained in:
parent
aa10ee735f
commit
a291fa0c4a
@ -25,6 +25,8 @@ import {
|
||||
Languages,
|
||||
UserCheck,
|
||||
DollarSign,
|
||||
CreditCard,
|
||||
Truck,
|
||||
Sliders,
|
||||
Globe,
|
||||
ChevronDown,
|
||||
@ -102,7 +104,9 @@ export default function Sidebar({ isOpen, setIsOpen }: SidebarProps) {
|
||||
badge: newOrdersCount > 0 ? newOrdersCount : undefined,
|
||||
},
|
||||
{ icon: Receipt, label: 'تراکنشها و لاگ پرداخت', path: '/transactions' },
|
||||
{ icon: DollarSign, label: 'تنظیمات مالی و ارسال', path: '/settings/financial' },
|
||||
{ icon: CreditCard, label: 'روشهای پرداخت و زیبال', path: '/settings/payment-methods' },
|
||||
{ icon: Truck, label: 'تنظیمات ارسال و کرایه', path: '/settings/shipping' },
|
||||
{ icon: DollarSign, label: 'تنظیمات مالی و مالیات', path: '/settings/financial' },
|
||||
],
|
||||
},
|
||||
{
|
||||
@ -151,7 +155,10 @@ export default function Sidebar({ isOpen, setIsOpen }: SidebarProps) {
|
||||
icon: Settings,
|
||||
items: [
|
||||
{ icon: Settings, label: 'تنظیمات اصلی فروشگاه', path: '/settings' },
|
||||
{ icon: Languages, label: 'متون رابط کاربری', path: '/ui-texts' },
|
||||
{ icon: Languages, label: 'ویرایشگر محتوای صفحات (Page Builder)', path: '/ui-texts' },
|
||||
{ icon: CreditCard, label: 'روشهای پرداخت و زیبال', path: '/settings/payment-methods' },
|
||||
{ icon: Truck, label: 'تنظیمات ارسال و کرایه', path: '/settings/shipping' },
|
||||
{ icon: DollarSign, label: 'تنظیمات مالی و مالیات', path: '/settings/financial' },
|
||||
{ icon: MessageSquare, label: 'درگاه پیامک (MeliPayamak)', path: '/settings/sms' },
|
||||
{ icon: ShieldCheck, label: 'گواهی SSL و امنیت', path: '/settings/ssl' },
|
||||
{ icon: Globe, label: 'تنظیمات سئو (SEO)', path: '/settings/seo' },
|
||||
|
||||
182
frontend/admin-panel/src/components/ui/IconPickerModal.tsx
Normal file
182
frontend/admin-panel/src/components/ui/IconPickerModal.tsx
Normal file
@ -0,0 +1,182 @@
|
||||
import React, { useState, useMemo } from 'react';
|
||||
import {
|
||||
X,
|
||||
Search,
|
||||
Check,
|
||||
Smile,
|
||||
Pill,
|
||||
ShieldCheck,
|
||||
HeartPulse,
|
||||
Sparkles,
|
||||
ShoppingBag,
|
||||
User,
|
||||
Building2,
|
||||
PhoneCall,
|
||||
Activity,
|
||||
Heart,
|
||||
Dog,
|
||||
BookOpen,
|
||||
FileText,
|
||||
Video,
|
||||
Award,
|
||||
Star,
|
||||
Truck,
|
||||
HelpCircle,
|
||||
MessageSquare,
|
||||
Globe,
|
||||
Settings,
|
||||
Flame,
|
||||
CheckCircle2,
|
||||
AlertCircle,
|
||||
ThumbsUp,
|
||||
Package,
|
||||
Layers,
|
||||
Compass,
|
||||
MapPin,
|
||||
Mail,
|
||||
Send,
|
||||
Zap,
|
||||
Tag,
|
||||
Gift,
|
||||
Clock,
|
||||
} from 'lucide-react';
|
||||
|
||||
interface IconPickerModalProps {
|
||||
isOpen: boolean;
|
||||
onClose: () => void;
|
||||
currentIcon?: string;
|
||||
onSelect: (iconName: string) => void;
|
||||
}
|
||||
|
||||
export const ICON_REGISTRY: Record<string, React.ComponentType<{ className?: string }>> = {
|
||||
Pill,
|
||||
ShieldCheck,
|
||||
HeartPulse,
|
||||
Sparkles,
|
||||
ShoppingBag,
|
||||
User,
|
||||
Building2,
|
||||
PhoneCall,
|
||||
Activity,
|
||||
Heart,
|
||||
Dog,
|
||||
BookOpen,
|
||||
FileText,
|
||||
Video,
|
||||
Award,
|
||||
Star,
|
||||
Truck,
|
||||
HelpCircle,
|
||||
MessageSquare,
|
||||
Globe,
|
||||
Settings,
|
||||
Flame,
|
||||
CheckCircle2,
|
||||
AlertCircle,
|
||||
ThumbsUp,
|
||||
Package,
|
||||
Layers,
|
||||
Compass,
|
||||
MapPin,
|
||||
Mail,
|
||||
Send,
|
||||
Zap,
|
||||
Tag,
|
||||
Gift,
|
||||
Clock,
|
||||
Smile,
|
||||
};
|
||||
|
||||
export default function IconPickerModal({
|
||||
isOpen,
|
||||
onClose,
|
||||
currentIcon,
|
||||
onSelect,
|
||||
}: IconPickerModalProps) {
|
||||
const [search, setSearch] = useState('');
|
||||
|
||||
const filteredIcons = useMemo(() => {
|
||||
const query = search.toLowerCase().trim();
|
||||
return Object.keys(ICON_REGISTRY).filter((name) =>
|
||||
name.toLowerCase().includes(query)
|
||||
);
|
||||
}, [search]);
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4 bg-gray-900/60 backdrop-blur-sm font-vazir" dir="rtl">
|
||||
<div className="bg-white rounded-3xl w-full max-w-lg shadow-2xl overflow-hidden border border-gray-100 animate-in zoom-in-95 duration-200">
|
||||
{/* Header */}
|
||||
<div className="p-6 border-b border-gray-100 flex items-center justify-between bg-gray-50/50">
|
||||
<div>
|
||||
<h3 className="text-base font-black text-gray-900">انتخاب آیکون (Lucide Icons)</h3>
|
||||
<p className="text-xs text-gray-500 font-medium mt-0.5">آیکون مورد نظر برای این بخش را انتخاب کنید</p>
|
||||
</div>
|
||||
<button
|
||||
onClick={onClose}
|
||||
className="p-2 text-gray-400 hover:text-gray-700 hover:bg-gray-100 rounded-xl transition-all cursor-pointer"
|
||||
>
|
||||
<X className="w-5 h-5" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Search */}
|
||||
<div className="p-4 border-b border-gray-100 bg-white">
|
||||
<div className="relative">
|
||||
<Search className="w-4 h-4 text-gray-400 absolute right-3.5 top-3" />
|
||||
<input
|
||||
type="text"
|
||||
placeholder="جستجوی نام آیکون (مانند Pill, Heart, Shield, Award)..."
|
||||
value={search}
|
||||
onChange={(e) => setSearch(e.target.value)}
|
||||
className="w-full pr-10 pl-4 py-2.5 bg-gray-50 border border-gray-200 rounded-xl text-xs font-bold focus:outline-none focus:ring-2 focus:ring-purple-500"
|
||||
dir="ltr"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Icon Grid */}
|
||||
<div className="p-6 max-h-[360px] overflow-y-auto grid grid-cols-4 sm:grid-cols-6 gap-3">
|
||||
{filteredIcons.map((name) => {
|
||||
const IconComp = ICON_REGISTRY[name];
|
||||
const isSelected = currentIcon === name;
|
||||
|
||||
return (
|
||||
<button
|
||||
key={name}
|
||||
type="button"
|
||||
onClick={() => {
|
||||
onSelect(name);
|
||||
onClose();
|
||||
}}
|
||||
className={`p-3 rounded-2xl flex flex-col items-center gap-1.5 transition-all border cursor-pointer group ${
|
||||
isSelected
|
||||
? 'bg-purple-600 text-white border-purple-600 shadow-md shadow-purple-200 scale-105'
|
||||
: 'bg-white hover:bg-purple-50 text-gray-700 border-gray-100 hover:border-purple-200 hover:text-purple-700'
|
||||
}`}
|
||||
>
|
||||
<IconComp className="w-6 h-6 transition-transform group-hover:scale-110" />
|
||||
<span className="text-[10px] font-mono font-bold truncate max-w-full" dir="ltr">
|
||||
{name}
|
||||
</span>
|
||||
{isSelected && <Check className="w-3 h-3 text-amber-300" />}
|
||||
</button>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
|
||||
{/* Footer */}
|
||||
<div className="p-4 border-t border-gray-100 flex justify-end bg-gray-50/50">
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClose}
|
||||
className="px-5 py-2 text-xs font-bold text-gray-600 hover:bg-gray-200 rounded-xl transition-all cursor-pointer"
|
||||
>
|
||||
بستن
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
239
frontend/admin-panel/src/components/ui/RichTextEditor.tsx
Normal file
239
frontend/admin-panel/src/components/ui/RichTextEditor.tsx
Normal file
@ -0,0 +1,239 @@
|
||||
import React, { useRef } from 'react';
|
||||
import {
|
||||
Bold,
|
||||
Italic,
|
||||
Underline,
|
||||
Heading1,
|
||||
Heading2,
|
||||
Heading3,
|
||||
List,
|
||||
ListOrdered,
|
||||
Link,
|
||||
AlignRight,
|
||||
AlignCenter,
|
||||
AlignLeft,
|
||||
Palette,
|
||||
Undo,
|
||||
Redo,
|
||||
} from 'lucide-react';
|
||||
|
||||
interface RichTextEditorProps {
|
||||
value: string;
|
||||
onChange: (html: string) => void;
|
||||
placeholder?: string;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const COLORS = [
|
||||
{ label: 'سیاه / پیشفرض', value: '#111827' },
|
||||
{ label: 'خاکستری', value: '#4b5563' },
|
||||
{ label: 'آبی کنینا', value: '#1d4ed8' },
|
||||
{ label: 'بنفش اختصاصی', value: '#7c3aed' },
|
||||
{ label: 'سبز درمانی', value: '#059669' },
|
||||
{ label: 'قرمز هشدار', value: '#dc2626' },
|
||||
{ label: 'کهربایی / زرد', value: '#d97706' },
|
||||
];
|
||||
|
||||
export default function RichTextEditor({
|
||||
value,
|
||||
onChange,
|
||||
placeholder,
|
||||
className = '',
|
||||
}: RichTextEditorProps) {
|
||||
const editorRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
const exec = (command: string, val: string | undefined = undefined) => {
|
||||
document.execCommand(command, false, val);
|
||||
if (editorRef.current) {
|
||||
onChange(editorRef.current.innerHTML);
|
||||
}
|
||||
};
|
||||
|
||||
const handleLink = () => {
|
||||
const url = prompt('آدرس لینک (URL) را وارد کنید:', 'https://');
|
||||
if (url) {
|
||||
exec('createLink', url);
|
||||
}
|
||||
};
|
||||
|
||||
const handleInput = () => {
|
||||
if (editorRef.current) {
|
||||
onChange(editorRef.current.innerHTML);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={`border border-gray-200 rounded-2xl bg-white overflow-hidden shadow-xs ${className}`}>
|
||||
{/* Toolbar */}
|
||||
<div className="bg-gray-50/80 border-b border-gray-100 p-2 flex flex-wrap items-center gap-1 text-gray-700">
|
||||
{/* Headings */}
|
||||
<div className="flex items-center gap-0.5 bg-white p-0.5 rounded-xl border border-gray-200">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => exec('formatBlock', '<h1>')}
|
||||
className="p-1.5 hover:bg-gray-100 rounded-lg text-xs font-bold transition-colors cursor-pointer"
|
||||
title="تگ تیتر H1 (برای سئو)"
|
||||
>
|
||||
<Heading1 className="w-4 h-4 text-purple-700" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => exec('formatBlock', '<h2>')}
|
||||
className="p-1.5 hover:bg-gray-100 rounded-lg text-xs font-bold transition-colors cursor-pointer"
|
||||
title="تگ تیتر H2"
|
||||
>
|
||||
<Heading2 className="w-4 h-4 text-purple-600" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => exec('formatBlock', '<h3>')}
|
||||
className="p-1.5 hover:bg-gray-100 rounded-lg text-xs font-bold transition-colors cursor-pointer"
|
||||
title="تگ تیتر H3"
|
||||
>
|
||||
<Heading3 className="w-4 h-4 text-purple-500" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => exec('formatBlock', '<p>')}
|
||||
className="p-1.5 hover:bg-gray-100 rounded-lg text-[11px] font-bold transition-colors cursor-pointer text-gray-600 px-2"
|
||||
title="پاراگراف عادی (P)"
|
||||
>
|
||||
P
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Basic Formats */}
|
||||
<div className="flex items-center gap-0.5 bg-white p-0.5 rounded-xl border border-gray-200">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => exec('bold')}
|
||||
className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer"
|
||||
title="Bold"
|
||||
>
|
||||
<Bold className="w-4 h-4" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => exec('italic')}
|
||||
className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer"
|
||||
title="Italic"
|
||||
>
|
||||
<Italic className="w-4 h-4" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => exec('underline')}
|
||||
className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer"
|
||||
title="Underline"
|
||||
>
|
||||
<Underline className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Alignment */}
|
||||
<div className="flex items-center gap-0.5 bg-white p-0.5 rounded-xl border border-gray-200">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => exec('justifyRight')}
|
||||
className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer"
|
||||
title="راستچین"
|
||||
>
|
||||
<AlignRight className="w-4 h-4" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => exec('justifyCenter')}
|
||||
className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer"
|
||||
title="وسطچین"
|
||||
>
|
||||
<AlignCenter className="w-4 h-4" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => exec('justifyLeft')}
|
||||
className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer"
|
||||
title="چپچین"
|
||||
>
|
||||
<AlignLeft className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Lists & Link */}
|
||||
<div className="flex items-center gap-0.5 bg-white p-0.5 rounded-xl border border-gray-200">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => exec('insertUnorderedList')}
|
||||
className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer"
|
||||
title="لیست بالتدار"
|
||||
>
|
||||
<List className="w-4 h-4" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => exec('insertOrderedList')}
|
||||
className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer"
|
||||
title="لیست شمارهدار"
|
||||
>
|
||||
<ListOrdered className="w-4 h-4" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleLink}
|
||||
className="p-1.5 hover:bg-gray-100 rounded-lg transition-colors cursor-pointer text-blue-600"
|
||||
title="درج لینک"
|
||||
>
|
||||
<Link className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
{/* Color Palette */}
|
||||
<div className="flex items-center gap-1 bg-white px-2 py-1 rounded-xl border border-gray-200">
|
||||
<Palette className="w-3.5 h-3.5 text-gray-400" />
|
||||
<div className="flex items-center gap-1">
|
||||
{COLORS.map((c) => (
|
||||
<button
|
||||
key={c.value}
|
||||
type="button"
|
||||
onClick={() => exec('foreColor', c.value)}
|
||||
className="w-3.5 h-3.5 rounded-full border border-black/10 cursor-pointer hover:scale-125 transition-transform"
|
||||
style={{ backgroundColor: c.value }}
|
||||
title={c.label}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Undo / Redo */}
|
||||
<div className="flex items-center gap-0.5 ms-auto">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => exec('undo')}
|
||||
className="p-1.5 hover:bg-gray-200 rounded-lg transition-colors cursor-pointer"
|
||||
title="Undo"
|
||||
>
|
||||
<Undo className="w-3.5 h-3.5 text-gray-500" />
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => exec('redo')}
|
||||
className="p-1.5 hover:bg-gray-200 rounded-lg transition-colors cursor-pointer"
|
||||
title="Redo"
|
||||
>
|
||||
<Redo className="w-3.5 h-3.5 text-gray-500" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Editable Area */}
|
||||
<div
|
||||
ref={editorRef}
|
||||
contentEditable
|
||||
onInput={handleInput}
|
||||
dangerouslySetInnerHTML={{ __html: value }}
|
||||
data-placeholder={placeholder}
|
||||
className="p-4 min-h-[140px] max-h-[350px] overflow-y-auto outline-none text-xs leading-relaxed text-gray-800 font-vazir empty:before:content-[attr(data-placeholder)] empty:before:text-gray-400"
|
||||
dir="rtl"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -1,5 +1,5 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { DollarSign, Save, Plus, X } from 'lucide-react';
|
||||
import { DollarSign, Save, Plus, X, Heart, Percent, Wallet } from 'lucide-react';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import api from '../services/api';
|
||||
import Spinner from '../components/ui/Spinner';
|
||||
@ -14,16 +14,20 @@ export default function FinancialSettingsPage() {
|
||||
charityDonationOptions: [10000, 20000, 50000],
|
||||
walletWithdrawalEnabled: false,
|
||||
});
|
||||
const [charityStep, setCharityStep] = useState('10000');
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
const [donationInput, setDonationInput] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
let isSubscribed = true;
|
||||
api.get('/settings/financial')
|
||||
.then(res => {
|
||||
Promise.all([
|
||||
api.get('/settings/financial'),
|
||||
api.get('/admin/settings'),
|
||||
])
|
||||
.then(([resFin, resAdmin]) => {
|
||||
if (!isSubscribed) return;
|
||||
const data = res.data?.data || res.data;
|
||||
const data = resFin.data?.data || resFin.data;
|
||||
if (data) {
|
||||
setFinancial({
|
||||
taxPercentage: Number(data.taxPercentage ?? 10),
|
||||
@ -35,8 +39,11 @@ export default function FinancialSettingsPage() {
|
||||
walletWithdrawalEnabled: Boolean(data.walletWithdrawalEnabled ?? false),
|
||||
});
|
||||
}
|
||||
if (resAdmin.data?.success) {
|
||||
setCharityStep(resAdmin.data.data.CHARITY_ROUND_STEP || '10000');
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
.catch((err) => {
|
||||
console.warn('Failed to fetch Financial settings', err);
|
||||
})
|
||||
.finally(() => {
|
||||
@ -51,8 +58,14 @@ export default function FinancialSettingsPage() {
|
||||
e.preventDefault();
|
||||
try {
|
||||
setIsSaving(true);
|
||||
await api.patch('/settings/financial', financial);
|
||||
toast.success('تنظیمات مالی و ارسال با موفقیت بروزرسانی شد');
|
||||
await Promise.all([
|
||||
api.patch('/settings/financial', financial),
|
||||
api.put('/admin/settings', {
|
||||
TAX_PERCENTAGE: String(financial.taxPercentage),
|
||||
CHARITY_ROUND_STEP: charityStep,
|
||||
}),
|
||||
]);
|
||||
toast.success('تنظیمات مالی با موفقیت بروزرسانی شد');
|
||||
} catch (err) {
|
||||
console.error('Failed to update financial settings:', err);
|
||||
toast.error('خطا در بروزرسانی تنظیمات مالی');
|
||||
@ -75,29 +88,37 @@ export default function FinancialSettingsPage() {
|
||||
const removeDonationOption = (amount: number) => {
|
||||
setFinancial({
|
||||
...financial,
|
||||
charityDonationOptions: financial.charityDonationOptions.filter(a => a !== amount),
|
||||
charityDonationOptions: financial.charityDonationOptions.filter((a) => a !== amount),
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-6 font-vazir" dir="rtl">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
|
||||
<div>
|
||||
<h2 className="text-2xl font-black text-gray-900 flex items-center gap-2">
|
||||
<DollarSign className="w-6 h-6 text-purple-600" />
|
||||
تنظیمات مالی و ارسال (Financial & Shipping Settings)
|
||||
<DollarSign className="w-6 h-6 text-emerald-600" />
|
||||
تنظیمات مالی، مالیات و خیریه (Financial Settings)
|
||||
</h2>
|
||||
<p className="text-gray-500 font-medium mt-1">تنظیم درصد مالیات، آستانه ارسال رایگان و گزینههای کمک به خیریه</p>
|
||||
<p className="text-gray-500 font-medium mt-1">
|
||||
تعیین درصد مالیات بر ارزش افزوده، کمکهای خیریه ردپای مهربانی و تسویهحساب کیف پول
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isLoading ? (
|
||||
<div className="flex justify-center p-12"><Spinner size="lg" className="text-purple-600" /></div>
|
||||
<div className="flex justify-center p-12">
|
||||
<Spinner size="lg" className="text-emerald-600" />
|
||||
</div>
|
||||
) : (
|
||||
<form onSubmit={handleSave} className="bg-white p-6 rounded-2xl shadow-sm border border-gray-200 space-y-6">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
{/* Tax Percentage */}
|
||||
<div>
|
||||
<label className="block text-sm font-bold text-gray-700 mb-1">درصد مالیات ارزش افزوده (taxPercentage) *</label>
|
||||
<label className="block text-sm font-bold text-gray-700 mb-1.5 flex items-center gap-1.5">
|
||||
<Percent className="w-4 h-4 text-emerald-600" />
|
||||
<span>درصد مالیات بر ارزش افزوده (VAT) *</span>
|
||||
</label>
|
||||
<div className="relative">
|
||||
<input
|
||||
required
|
||||
@ -106,36 +127,35 @@ export default function FinancialSettingsPage() {
|
||||
max="100"
|
||||
value={financial.taxPercentage}
|
||||
onChange={(e) => setFinancial({ ...financial, taxPercentage: Number(e.target.value) })}
|
||||
className="w-full px-4 py-3 rounded-xl border border-gray-200 focus:border-purple-500 outline-none font-bold text-sm"
|
||||
className="w-full px-4 py-3 rounded-xl border border-gray-200 focus:border-emerald-500 outline-none font-bold text-sm"
|
||||
dir="ltr"
|
||||
/>
|
||||
<span className="absolute left-4 top-1/2 -translate-y-1/2 text-gray-400 font-bold">%</span>
|
||||
</div>
|
||||
<p className="text-xs text-gray-500 mt-1">درصد قانونی محاسبه مالیات بر ارزش افزوده در فاکتور نهایی سفارشات.</p>
|
||||
</div>
|
||||
|
||||
{/* Charity Round Step */}
|
||||
<div>
|
||||
<label className="block text-sm font-bold text-gray-700 mb-1">هزینه ارسال استاندارد (standardShippingFee) *</label>
|
||||
<label className="block text-sm font-bold text-gray-700 mb-1.5 flex items-center gap-1.5">
|
||||
<Heart className="w-4 h-4 text-rose-500" />
|
||||
<span>پله رند کردن کمک به خیریه ردپای مهربانی (تومان)</span>
|
||||
</label>
|
||||
<PriceInput
|
||||
required
|
||||
value={financial.standardShippingFee}
|
||||
onChange={(val) => setFinancial({ ...financial, standardShippingFee: Number(val) })}
|
||||
className="px-4 py-3 rounded-xl border border-gray-200 focus:border-purple-500 text-sm"
|
||||
value={charityStep}
|
||||
onChange={(val) => setCharityStep(val)}
|
||||
placeholder="10000"
|
||||
className="px-4 py-3 rounded-xl border border-gray-200 focus:border-emerald-500 text-sm"
|
||||
/>
|
||||
<p className="text-xs text-gray-500 mt-1">مبلغ فاکتور به نزدیکترین ضریب این عدد (مثلاً ۱۰,۰۰۰ یا ۵۰,۰۰۰ تومان) رند میگردد.</p>
|
||||
</div>
|
||||
|
||||
<div className="md:col-span-2">
|
||||
<label className="block text-sm font-bold text-gray-700 mb-1">آستانه ارسال رایگان (freeShippingThreshold) *</label>
|
||||
<PriceInput
|
||||
required
|
||||
value={financial.freeShippingThreshold}
|
||||
onChange={(val) => setFinancial({ ...financial, freeShippingThreshold: Number(val) })}
|
||||
className="px-4 py-3 rounded-xl border border-gray-200 focus:border-purple-500 text-sm"
|
||||
/>
|
||||
<p className="text-xs text-gray-500 mt-1">سبدهای خرید با مبلغ بالاتر از این مقدار، ارسال رایگان خواهند داشت.</p>
|
||||
</div>
|
||||
|
||||
<div className="md:col-span-2 space-y-2">
|
||||
<label className="block text-sm font-bold text-gray-700 mb-1">گزینههای کمک به خیریه ردپای مهربانی (charityDonationOptions)</label>
|
||||
{/* Charity Donation Options */}
|
||||
<div className="md:col-span-2 space-y-2 pt-3 border-t border-gray-100">
|
||||
<label className="block text-sm font-bold text-gray-700 mb-1 flex items-center gap-1.5">
|
||||
<Heart className="w-4 h-4 text-rose-500" />
|
||||
<span>گزینههای دلخواه کمک مستقیم به خیریه (charityDonationOptions)</span>
|
||||
</label>
|
||||
<div className="flex gap-2 max-w-md">
|
||||
<PriceInput
|
||||
placeholder="مبلغ جدید (مثال: ۱۰۰,۰۰۰)"
|
||||
@ -146,17 +166,24 @@ export default function FinancialSettingsPage() {
|
||||
<button
|
||||
type="button"
|
||||
onClick={addDonationOption}
|
||||
className="px-4 py-2 bg-purple-600 hover:bg-purple-700 text-white rounded-xl text-xs font-bold flex items-center gap-1 shrink-0"
|
||||
className="px-4 py-2 bg-emerald-600 hover:bg-emerald-700 text-white rounded-xl text-xs font-bold flex items-center gap-1 shrink-0 cursor-pointer"
|
||||
>
|
||||
<Plus className="w-4 h-4" /> افزودن
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-wrap gap-2 pt-2">
|
||||
{financial.charityDonationOptions.map(amount => (
|
||||
<span key={amount} className="inline-flex items-center gap-1.5 px-3 py-1.5 bg-purple-50 text-purple-700 text-xs font-bold rounded-xl border border-purple-200">
|
||||
{financial.charityDonationOptions.map((amount) => (
|
||||
<span
|
||||
key={amount}
|
||||
className="inline-flex items-center gap-1.5 px-3 py-1.5 bg-rose-50 text-rose-700 text-xs font-bold rounded-xl border border-rose-200"
|
||||
>
|
||||
{amount.toLocaleString('fa-IR')} تومان
|
||||
<button type="button" onClick={() => removeDonationOption(amount)} className="hover:text-red-500">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => removeDonationOption(amount)}
|
||||
className="hover:text-red-500 cursor-pointer"
|
||||
>
|
||||
<X className="w-3.5 h-3.5" />
|
||||
</button>
|
||||
</span>
|
||||
@ -166,16 +193,21 @@ export default function FinancialSettingsPage() {
|
||||
|
||||
{/* Wallet Withdrawal Feature Toggle */}
|
||||
<div className="md:col-span-2 pt-4 border-t border-gray-100">
|
||||
<label className="flex items-center gap-3 cursor-pointer p-4 bg-purple-50/50 hover:bg-purple-50 rounded-2xl border border-purple-100 transition-colors">
|
||||
<label className="flex items-center gap-3 cursor-pointer p-4 bg-emerald-50/50 hover:bg-emerald-50 rounded-2xl border border-emerald-100 transition-colors">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={Boolean(financial.walletWithdrawalEnabled)}
|
||||
onChange={(e) => setFinancial({ ...financial, walletWithdrawalEnabled: e.target.checked })}
|
||||
className="w-5 h-5 rounded-lg text-purple-600 focus:ring-purple-500 border-gray-300 cursor-pointer"
|
||||
className="w-5 h-5 rounded-lg text-emerald-600 focus:ring-emerald-500 border-gray-300 cursor-pointer"
|
||||
/>
|
||||
<div>
|
||||
<span className="text-sm font-black text-gray-900 block">فعالسازی امکان ثبت درخواست برداشت و تسویهحساب کیف پول (wallet_withdrawal_enabled)</span>
|
||||
<span className="text-xs text-gray-500 font-medium block mt-0.5">در صورت فعال بودن، کاربران میتوانند از طریق داشبورد خود درخواست تسویه و واریز وجه به شماره شبا ثبت کنند.</span>
|
||||
<span className="text-sm font-black text-gray-900 block flex items-center gap-2">
|
||||
<Wallet className="w-4 h-4 text-emerald-600" />
|
||||
فعالسازی امکان ثبت درخواست برداشت و تسویهحساب کیف پول
|
||||
</span>
|
||||
<span className="text-xs text-gray-500 font-medium block mt-0.5">
|
||||
در صورت فعال بودن، کاربران میتوانند از طریق داشبورد خود درخواست تسویه و واریز وجه کیف پول به شماره شبا ثبت کنند.
|
||||
</span>
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
@ -185,7 +217,7 @@ export default function FinancialSettingsPage() {
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSaving}
|
||||
className="bg-purple-600 hover:bg-purple-700 text-white font-bold py-3 px-8 rounded-xl transition-colors flex items-center gap-2 shadow-md shadow-purple-200"
|
||||
className="bg-emerald-600 hover:bg-emerald-700 text-white font-bold py-3 px-8 rounded-xl transition-colors flex items-center gap-2 shadow-md shadow-emerald-200 cursor-pointer"
|
||||
>
|
||||
{isSaving ? <Spinner size="sm" /> : <Save className="w-5 h-5" />}
|
||||
ذخیره تنظیمات مالی
|
||||
|
||||
270
frontend/admin-panel/src/pages/PaymentGatewaysPage.tsx
Normal file
270
frontend/admin-panel/src/pages/PaymentGatewaysPage.tsx
Normal file
@ -0,0 +1,270 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { CreditCard, Save, ShieldCheck, Wallet, ArrowLeftRight, CheckCircle2 } from 'lucide-react';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import api from '../services/api';
|
||||
import Spinner from '../components/ui/Spinner';
|
||||
|
||||
export default function PaymentGatewaysPage() {
|
||||
const [settings, setSettings] = useState({
|
||||
PAY_GATEWAY_CARD_ENABLE: 'true',
|
||||
PAY_GATEWAY_WALLET_ENABLE: 'true',
|
||||
PAY_GATEWAY_ONLINE_ENABLE: 'true',
|
||||
PAY_GATEWAY_COD_ENABLE: 'false',
|
||||
ZIBAL_MERCHANT: 'zibal',
|
||||
ZIBAL_SANDBOX: 'true',
|
||||
FRONTEND_URL: 'https://canina.ir',
|
||||
});
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
let isSubscribed = true;
|
||||
api.get('/admin/settings')
|
||||
.then((res) => {
|
||||
if (!isSubscribed) return;
|
||||
if (res.data?.success) {
|
||||
const d = res.data.data;
|
||||
setSettings({
|
||||
PAY_GATEWAY_CARD_ENABLE: d.PAY_GATEWAY_CARD_ENABLE ?? 'true',
|
||||
PAY_GATEWAY_WALLET_ENABLE: d.PAY_GATEWAY_WALLET_ENABLE ?? 'true',
|
||||
PAY_GATEWAY_ONLINE_ENABLE: d.PAY_GATEWAY_ONLINE_ENABLE ?? 'true',
|
||||
PAY_GATEWAY_COD_ENABLE: d.PAY_GATEWAY_COD_ENABLE ?? 'false',
|
||||
ZIBAL_MERCHANT: d.ZIBAL_MERCHANT || 'zibal',
|
||||
ZIBAL_SANDBOX: d.ZIBAL_SANDBOX ?? 'true',
|
||||
FRONTEND_URL: d.FRONTEND_URL || 'https://canina.ir',
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Failed to fetch payment settings', err);
|
||||
})
|
||||
.finally(() => {
|
||||
if (isSubscribed) setIsLoading(false);
|
||||
});
|
||||
return () => {
|
||||
isSubscribed = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleSave = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
try {
|
||||
setIsSaving(true);
|
||||
await api.put('/admin/settings', settings);
|
||||
toast.success('تنظیمات روشهای پرداخت با موفقیت بروزرسانی شد.');
|
||||
} catch (err) {
|
||||
console.error('Failed to update payment settings', err);
|
||||
toast.error('خطا در ذخیره تنظیمات درگاه پرداخت');
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-6 font-vazir" dir="rtl">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
|
||||
<div>
|
||||
<h2 className="text-2xl font-black text-gray-900 flex items-center gap-2">
|
||||
<CreditCard className="w-6 h-6 text-indigo-600" />
|
||||
مدیریت روشهای پرداخت و درگاه بانکی
|
||||
</h2>
|
||||
<p className="text-gray-500 font-medium mt-1">
|
||||
پیکربندی پایانههای پرداخت اینترنتی زیبال، کیف پول داخلی، کارت به کارت و پرداخت در محل
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isLoading ? (
|
||||
<div className="flex justify-center p-12">
|
||||
<Spinner size="lg" className="text-indigo-600" />
|
||||
</div>
|
||||
) : (
|
||||
<form onSubmit={handleSave} className="space-y-6">
|
||||
{/* Methods Cards */}
|
||||
<div className="bg-white p-6 rounded-2xl shadow-sm border border-gray-200 space-y-6">
|
||||
<h3 className="text-base font-black text-gray-900 border-b border-gray-100 pb-3 flex items-center gap-2">
|
||||
<ShieldCheck className="w-5 h-5 text-indigo-600" />
|
||||
وضعیت فعال بودن روشهای پرداخت در تسویهحساب
|
||||
</h3>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
{/* Zibal IPG */}
|
||||
<div className="flex items-center justify-between p-4 bg-indigo-50/50 rounded-2xl border border-indigo-100">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-xl bg-indigo-600 text-white flex items-center justify-center font-black">
|
||||
Z
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-bold text-gray-900 text-sm">درگاه آنلاین شتاب (زیبال)</h4>
|
||||
<p className="text-xs text-gray-500 mt-0.5">پرداخت اینترنتی کلیه کارتهای عضو شتاب</p>
|
||||
</div>
|
||||
</div>
|
||||
<label className="relative inline-flex items-center cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="sr-only peer"
|
||||
checked={settings.PAY_GATEWAY_ONLINE_ENABLE === 'true'}
|
||||
onChange={(e) =>
|
||||
setSettings({
|
||||
...settings,
|
||||
PAY_GATEWAY_ONLINE_ENABLE: e.target.checked ? 'true' : 'false',
|
||||
})
|
||||
}
|
||||
/>
|
||||
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-indigo-600"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* Wallet Internal */}
|
||||
<div className="flex items-center justify-between p-4 bg-blue-50/50 rounded-2xl border border-blue-100">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-xl bg-blue-600 text-white flex items-center justify-center font-black">
|
||||
<Wallet className="w-5 h-5" />
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-bold text-gray-900 text-sm">اعتبار کیف پول کنینا</h4>
|
||||
<p className="text-xs text-gray-500 mt-0.5">پرداخت لحظهای از موجودی شارژشده کاربر</p>
|
||||
</div>
|
||||
</div>
|
||||
<label className="relative inline-flex items-center cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="sr-only peer"
|
||||
checked={settings.PAY_GATEWAY_WALLET_ENABLE === 'true'}
|
||||
onChange={(e) =>
|
||||
setSettings({
|
||||
...settings,
|
||||
PAY_GATEWAY_WALLET_ENABLE: e.target.checked ? 'true' : 'false',
|
||||
})
|
||||
}
|
||||
/>
|
||||
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-blue-600"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* Card to Card */}
|
||||
<div className="flex items-center justify-between p-4 bg-slate-50 rounded-2xl border border-gray-200">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-xl bg-slate-700 text-white flex items-center justify-center font-black">
|
||||
<ArrowLeftRight className="w-5 h-5" />
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-bold text-gray-900 text-sm">کارت به کارت (واریز مستقیم)</h4>
|
||||
<p className="text-xs text-gray-500 mt-0.5">واریز به شماره شبا / کارت رسمی و ثبت فیش</p>
|
||||
</div>
|
||||
</div>
|
||||
<label className="relative inline-flex items-center cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="sr-only peer"
|
||||
checked={settings.PAY_GATEWAY_CARD_ENABLE === 'true'}
|
||||
onChange={(e) =>
|
||||
setSettings({
|
||||
...settings,
|
||||
PAY_GATEWAY_CARD_ENABLE: e.target.checked ? 'true' : 'false',
|
||||
})
|
||||
}
|
||||
/>
|
||||
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-slate-700"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* Cash On Delivery */}
|
||||
<div className="flex items-center justify-between p-4 bg-amber-50/50 rounded-2xl border border-amber-100">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-xl bg-amber-600 text-white flex items-center justify-center font-black">
|
||||
<CreditCard className="w-5 h-5" />
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-bold text-gray-900 text-sm">پرداخت در محل (COD)</h4>
|
||||
<p className="text-xs text-gray-500 mt-0.5">پرداخت با پوز هنگام دریافت سفارش</p>
|
||||
</div>
|
||||
</div>
|
||||
<label className="relative inline-flex items-center cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="sr-only peer"
|
||||
checked={settings.PAY_GATEWAY_COD_ENABLE === 'true'}
|
||||
onChange={(e) =>
|
||||
setSettings({
|
||||
...settings,
|
||||
PAY_GATEWAY_COD_ENABLE: e.target.checked ? 'true' : 'false',
|
||||
})
|
||||
}
|
||||
/>
|
||||
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-amber-600"></div>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Zibal Configuration Card */}
|
||||
<div className="bg-white p-6 rounded-2xl shadow-sm border border-gray-200 space-y-5">
|
||||
<div className="flex items-center justify-between border-b border-gray-100 pb-3">
|
||||
<h3 className="text-base font-black text-gray-900 flex items-center gap-2">
|
||||
<ShieldCheck className="w-5 h-5 text-indigo-600" />
|
||||
پیکربندی پایانه پرداخت زیبال (Zibal IPG Config)
|
||||
</h3>
|
||||
{settings.ZIBAL_MERCHANT === 'zibal' && (
|
||||
<span className="bg-amber-100 text-amber-800 text-xs px-3 py-1 rounded-xl font-bold flex items-center gap-1">
|
||||
<CheckCircle2 className="w-3.5 h-3.5" />
|
||||
حالت آزمایشی (Sandbox)
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-5">
|
||||
<div>
|
||||
<label className="block text-xs font-bold text-gray-700 mb-1.5">
|
||||
کد مرچنت زیبال (Merchant ID) *
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
value={settings.ZIBAL_MERCHANT}
|
||||
onChange={(e) => setSettings({ ...settings, ZIBAL_MERCHANT: e.target.value })}
|
||||
placeholder="zibal یا کد مرچنت دریافتی"
|
||||
className="w-full border border-gray-200 rounded-xl p-3 outline-none focus:ring-2 focus:ring-indigo-500 text-xs font-mono font-bold"
|
||||
dir="ltr"
|
||||
/>
|
||||
<p className="text-[11px] text-gray-400 mt-1">
|
||||
جهت فعالسازی درگاه زنده، مرچنت آیدی رسمی زیبال را در این کادر قرار دهید.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-xs font-bold text-gray-700 mb-1.5">
|
||||
دامنه بازگشت پس از پرداخت (Frontend Return Domain) *
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
required
|
||||
value={settings.FRONTEND_URL}
|
||||
onChange={(e) => setSettings({ ...settings, FRONTEND_URL: e.target.value })}
|
||||
placeholder="https://canina.ir"
|
||||
className="w-full border border-gray-200 rounded-xl p-3 outline-none focus:ring-2 focus:ring-indigo-500 text-xs font-mono font-bold"
|
||||
dir="ltr"
|
||||
/>
|
||||
<p className="text-[11px] text-gray-400 mt-1">
|
||||
آدرس صفحهای که نتیجه تراکنش به آن ارجاع داده میشود.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSaving}
|
||||
className="bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-3 px-8 rounded-xl transition-colors flex items-center gap-2 shadow-md shadow-indigo-200 cursor-pointer"
|
||||
>
|
||||
{isSaving ? <Spinner size="sm" /> : <Save className="w-5 h-5" />}
|
||||
<span>ذخیره تغییرات روشهای پرداخت</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
164
frontend/admin-panel/src/pages/ShippingSettingsPage.tsx
Normal file
164
frontend/admin-panel/src/pages/ShippingSettingsPage.tsx
Normal file
@ -0,0 +1,164 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Truck, Save, Gift, ShieldAlert } from 'lucide-react';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import api from '../services/api';
|
||||
import Spinner from '../components/ui/Spinner';
|
||||
import PriceInput from '../components/ui/PriceInput';
|
||||
|
||||
export default function ShippingSettingsPage() {
|
||||
const [shipping, setShipping] = useState({
|
||||
SHIPPING_FEE: '85000',
|
||||
FREE_SHIPPING_THRESHOLD: '2000000',
|
||||
MIN_ORDER_AMOUNT: '0',
|
||||
shipping_notice:
|
||||
'ارسال رایگان برای سفارشهای بالای ۱۵۰ هزار تومان — گارانتی اصالت کنینا آلمان — مشاوره تخصصی مکملهای دارویی سگ و گربه با کادر دامپزشکان مجرب',
|
||||
});
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
let isSubscribed = true;
|
||||
api.get('/admin/settings')
|
||||
.then((res) => {
|
||||
if (!isSubscribed) return;
|
||||
if (res.data?.success) {
|
||||
const d = res.data.data;
|
||||
setShipping({
|
||||
SHIPPING_FEE: String(d.SHIPPING_FEE || d.shipping_fee || d.standardShippingFee || '85000'),
|
||||
FREE_SHIPPING_THRESHOLD: String(d.FREE_SHIPPING_THRESHOLD || d.free_shipping_threshold || d.freeShippingThreshold || '2000000'),
|
||||
MIN_ORDER_AMOUNT: String(d.MIN_ORDER_AMOUNT || d.min_order_amount || d.minOrderAmount || '0'),
|
||||
shipping_notice: d.shipping_notice || d.SHIPPING_NOTICE || 'ارسال رایگان برای سفارشهای بالای ۱۵۰ هزار تومان — گارانتی اصالت کنینا آلمان',
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('Failed to fetch shipping settings', err);
|
||||
})
|
||||
.finally(() => {
|
||||
if (isSubscribed) setIsLoading(false);
|
||||
});
|
||||
return () => {
|
||||
isSubscribed = false;
|
||||
};
|
||||
}, []);
|
||||
|
||||
const handleSave = async (e: React.FormEvent) => {
|
||||
e.preventDefault();
|
||||
try {
|
||||
setIsSaving(true);
|
||||
await api.put('/admin/settings', shipping);
|
||||
toast.success('تنظیمات ارسال و کرایه حمل با موفقیت بروزرسانی شد.');
|
||||
} catch (err) {
|
||||
console.error('Failed to update shipping settings:', err);
|
||||
toast.error('خطا در ذخیره تنظیمات ارسال');
|
||||
} finally {
|
||||
setIsSaving(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-6 font-vazir" dir="rtl">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
|
||||
<div>
|
||||
<h2 className="text-2xl font-black text-gray-900 flex items-center gap-2">
|
||||
<Truck className="w-6 h-6 text-blue-600" />
|
||||
تنظیمات ارسال و کرایه حمل (Shipping & Delivery)
|
||||
</h2>
|
||||
<p className="text-gray-500 font-medium mt-1">
|
||||
تعیین هزینه پایه پست، آستانه ارسال رایگان، حداقل مجاز مبلغ سفارش و نوار اعلان تحویل
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isLoading ? (
|
||||
<div className="flex justify-center p-12">
|
||||
<Spinner size="lg" className="text-blue-600" />
|
||||
</div>
|
||||
) : (
|
||||
<form onSubmit={handleSave} className="space-y-6">
|
||||
<div className="bg-white p-6 rounded-2xl shadow-sm border border-gray-200 space-y-6">
|
||||
<h3 className="text-base font-black text-gray-900 border-b border-gray-100 pb-3 flex items-center gap-2">
|
||||
<Truck className="w-5 h-5 text-blue-600" />
|
||||
قوانین هزینه و کرایه ارسال
|
||||
</h3>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-6">
|
||||
<div>
|
||||
<label className="block text-sm font-bold text-gray-700 mb-2">
|
||||
هزینه ثابت ارسال (تومان) *
|
||||
</label>
|
||||
<PriceInput
|
||||
value={shipping.SHIPPING_FEE}
|
||||
onChange={(val) => setShipping({ ...shipping, SHIPPING_FEE: val })}
|
||||
placeholder="مثال: ۸۵,۰۰۰"
|
||||
className="border border-gray-200 rounded-xl p-3 focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
<p className="text-xs text-gray-500 mt-1.5 font-medium">
|
||||
هزینه استاندارد پستی که برای سفارشهای عادی منظور میشود.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-bold text-gray-700 mb-2">
|
||||
آستانه ارسال رایگان (تومان) *
|
||||
</label>
|
||||
<PriceInput
|
||||
value={shipping.FREE_SHIPPING_THRESHOLD}
|
||||
onChange={(val) => setShipping({ ...shipping, FREE_SHIPPING_THRESHOLD: val })}
|
||||
placeholder="مثال: ۲,۰۰۰,۰۰۰"
|
||||
className="border border-gray-200 rounded-xl p-3 focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
<p className="text-xs text-gray-500 mt-1.5 font-medium">
|
||||
سفارشهای با جمع مبلغ بالاتر از این عدد، به طور خودکار رایگان ارسال میشوند.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-bold text-gray-700 mb-2">
|
||||
حداقل مبلغ سفارش مجاز (تومان)
|
||||
</label>
|
||||
<PriceInput
|
||||
value={shipping.MIN_ORDER_AMOUNT}
|
||||
onChange={(val) => setShipping({ ...shipping, MIN_ORDER_AMOUNT: val })}
|
||||
placeholder="۰ = بدون محدودیت"
|
||||
className="border border-gray-200 rounded-xl p-3 focus:ring-2 focus:ring-blue-500"
|
||||
/>
|
||||
<p className="text-xs text-gray-500 mt-1.5 font-medium">
|
||||
سفارشات کمتر از این عدد اجازه ورود به درگاه را نخواهند داشت (۰ برای لغو شرط).
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className="md:col-span-2">
|
||||
<label className="block text-sm font-bold text-gray-700 mb-2">
|
||||
متن نوار متحرک اعلان بالای سایت (Ticker Announcement)
|
||||
</label>
|
||||
<textarea
|
||||
rows={2}
|
||||
value={shipping.shipping_notice}
|
||||
onChange={(e) => setShipping({ ...shipping, shipping_notice: e.target.value })}
|
||||
placeholder="ارسال رایگان برای سفارشهای بالای ۱۵۰ هزار تومان — ..."
|
||||
className="w-full border border-gray-200 rounded-xl p-3 outline-none focus:ring-2 focus:ring-blue-500 text-xs font-bold bg-amber-50/40"
|
||||
/>
|
||||
<p className="text-xs text-gray-500 mt-1 font-medium">
|
||||
این متن در نوار زرد متحرک بالای تمام صفحات سایت نمایش داده میشود.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSaving}
|
||||
className="bg-blue-600 hover:bg-blue-700 text-white font-bold py-3 px-8 rounded-xl transition-colors flex items-center gap-2 shadow-md shadow-blue-200 cursor-pointer"
|
||||
>
|
||||
{isSaving ? <Spinner size="sm" /> : <Save className="w-5 h-5" />}
|
||||
<span>ذخیره تغییرات ارسال</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@ -1,5 +1,16 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { Sliders, Save, AlertTriangle } from 'lucide-react';
|
||||
import { Link } from 'react-router-dom';
|
||||
import {
|
||||
Sliders,
|
||||
Save,
|
||||
AlertTriangle,
|
||||
ShieldAlert,
|
||||
MessageSquare,
|
||||
BookOpen,
|
||||
ShoppingBag,
|
||||
Info,
|
||||
CheckCircle2,
|
||||
} from 'lucide-react';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import api from '../services/api';
|
||||
import Spinner from '../components/ui/Spinner';
|
||||
@ -12,26 +23,49 @@ export default function SystemSettingsPage() {
|
||||
b2bRegistrationOpen: true,
|
||||
supportPhone: '021-12345678',
|
||||
});
|
||||
|
||||
const [catalogSettings, setCatalogSettings] = useState({
|
||||
CATALOG_ONLY_MODE: 'false',
|
||||
CATALOG_SHOW_PRICES: 'true',
|
||||
CATALOG_ALLOW_CART: 'false',
|
||||
CATALOG_ALLOW_CHECKOUT: 'false',
|
||||
CATALOG_PREORDER_BTN: 'false',
|
||||
});
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
let isSubscribed = true;
|
||||
api.get('/settings/system')
|
||||
.then(res => {
|
||||
Promise.all([
|
||||
api.get('/settings/system'),
|
||||
api.get('/admin/settings'),
|
||||
])
|
||||
.then(([resSys, resAdmin]) => {
|
||||
if (!isSubscribed) return;
|
||||
const data = res.data?.data || res.data;
|
||||
const data = resSys.data?.data || resSys.data;
|
||||
if (data) {
|
||||
setSystem(prev => ({
|
||||
setSystem((prev) => ({
|
||||
maintenanceMode: Boolean(data.maintenanceMode),
|
||||
allowGuestCheckout: Boolean(data.allowGuestCheckout ?? true),
|
||||
b2bRegistrationOpen: Boolean(data.b2bRegistrationOpen ?? true),
|
||||
supportPhone: data.supportPhone || prev.supportPhone,
|
||||
}));
|
||||
}
|
||||
|
||||
if (resAdmin.data?.success) {
|
||||
const d = resAdmin.data.data;
|
||||
setCatalogSettings({
|
||||
CATALOG_ONLY_MODE: d.CATALOG_ONLY_MODE || 'false',
|
||||
CATALOG_SHOW_PRICES: d.CATALOG_SHOW_PRICES || 'true',
|
||||
CATALOG_ALLOW_CART: d.CATALOG_ALLOW_CART || 'false',
|
||||
CATALOG_ALLOW_CHECKOUT: d.CATALOG_ALLOW_CHECKOUT || 'false',
|
||||
CATALOG_PREORDER_BTN: d.CATALOG_PREORDER_BTN || 'false',
|
||||
});
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
console.warn('Failed to fetch System settings, using default state', err);
|
||||
.catch((err) => {
|
||||
console.warn('Failed to fetch system/catalog settings', err);
|
||||
})
|
||||
.finally(() => {
|
||||
if (isSubscribed) setIsLoading(false);
|
||||
@ -45,8 +79,14 @@ export default function SystemSettingsPage() {
|
||||
e.preventDefault();
|
||||
try {
|
||||
setIsSaving(true);
|
||||
await api.patch('/settings/system', system);
|
||||
toast.success('تنظیمات سیستمی با موفقیت بروزرسانی شد');
|
||||
await Promise.all([
|
||||
api.patch('/settings/system', system),
|
||||
api.put('/admin/settings', {
|
||||
MAINTENANCE_MODE: system.maintenanceMode ? 'true' : 'false',
|
||||
...catalogSettings,
|
||||
}),
|
||||
]);
|
||||
toast.success('تنظیمات سیستمی و حالتهای فروشگاه با موفقیت ذخیره شد.');
|
||||
} catch (err) {
|
||||
console.error('Failed to update system settings:', err);
|
||||
toast.error('خطا در بروزرسانی تنظیمات سیستمی');
|
||||
@ -56,29 +96,61 @@ export default function SystemSettingsPage() {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
<div className="space-y-6 font-vazir" dir="rtl">
|
||||
{/* Top Header with Quick Security and SMS links */}
|
||||
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
|
||||
<div>
|
||||
<h2 className="text-2xl font-black text-gray-900 flex items-center gap-2">
|
||||
<Sliders className="w-6 h-6 text-purple-600" />
|
||||
تنظیمات سیستمی و کنترل حالتها (System Settings)
|
||||
تنظیمات سیستمی پیشرفته و کنترل دسترسی
|
||||
</h2>
|
||||
<p className="text-gray-500 font-medium mt-1">مدیریت حالت تعمیرات، خرید مهمان و ثبتنام همکاران B2B</p>
|
||||
<p className="text-gray-500 font-medium mt-1">
|
||||
مدیریت وضعیت صیانت و تعمیرات، کنترل کاتالوگمود، خرید مهمان و ابزارهای امنیتی
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Action buttons for SSL and SMS as requested */}
|
||||
<div className="flex items-center gap-2.5 flex-wrap">
|
||||
<Link
|
||||
to="/settings/ssl"
|
||||
className="bg-emerald-50 text-emerald-700 hover:bg-emerald-100 border border-emerald-200 text-xs font-black px-4 py-2.5 rounded-xl transition-all flex items-center gap-2 shadow-xs"
|
||||
>
|
||||
<ShieldAlert className="w-4 h-4 text-emerald-600" />
|
||||
<span>مدیریت گواهی SSL و امنیت</span>
|
||||
</Link>
|
||||
<Link
|
||||
to="/settings/sms"
|
||||
className="bg-purple-50 text-purple-700 hover:bg-purple-100 border border-purple-200 text-xs font-black px-4 py-2.5 rounded-xl transition-all flex items-center gap-2 shadow-xs"
|
||||
>
|
||||
<MessageSquare className="w-4 h-4 text-purple-600" />
|
||||
<span>تنظیمات درگاه پیامک (MeliPayamak)</span>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isLoading ? (
|
||||
<div className="flex justify-center p-12"><Spinner size="lg" className="text-purple-600" /></div>
|
||||
<div className="flex justify-center p-12">
|
||||
<Spinner size="lg" className="text-purple-600" />
|
||||
</div>
|
||||
) : (
|
||||
<form onSubmit={handleSave} className="bg-white p-6 rounded-2xl shadow-sm border border-gray-200 space-y-6">
|
||||
<div className="space-y-4">
|
||||
{/* Maintenance Mode */}
|
||||
<div className="flex items-center justify-between p-4 bg-amber-50/60 rounded-xl border border-amber-200">
|
||||
<form onSubmit={handleSave} className="space-y-6">
|
||||
{/* Maintenance Mode Card */}
|
||||
<div className="bg-white p-6 rounded-2xl shadow-sm border border-gray-200 space-y-4">
|
||||
<h3 className="text-base font-black text-gray-900 border-b border-gray-100 pb-3 flex items-center gap-2">
|
||||
<AlertTriangle className="w-5 h-5 text-amber-500" />
|
||||
حالت تعمیرات و صیانت موقت سایت (Maintenance Mode)
|
||||
</h3>
|
||||
|
||||
<div className="flex items-center justify-between p-4 bg-amber-50/70 rounded-2xl border border-amber-200">
|
||||
<div className="flex items-center gap-3">
|
||||
<AlertTriangle className="w-6 h-6 text-amber-600" />
|
||||
<div className="w-10 h-10 rounded-xl bg-amber-500 text-white flex items-center justify-center font-black">
|
||||
<AlertTriangle className="w-5 h-5" />
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-bold text-gray-900 text-sm">حالت تعمیرات (maintenanceMode)</h4>
|
||||
<p className="text-xs text-gray-600 mt-0.5">غیرفعالسازی موقت فرانتاند جهت بروزرسانی دیتابیس یا سرور</p>
|
||||
<h4 className="font-bold text-gray-900 text-sm">فعالسازی حالت تعمیرات</h4>
|
||||
<p className="text-xs text-gray-600 mt-0.5">
|
||||
با فعال کردن این گزینه، فرانتاند سایت برای کاربران قفل شده و صفحه «در حال بروزرسانی» نمایش داده میشود.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<label className="relative inline-flex items-center cursor-pointer">
|
||||
@ -88,66 +160,177 @@ export default function SystemSettingsPage() {
|
||||
checked={system.maintenanceMode}
|
||||
onChange={(e) => setSystem({ ...system, maintenanceMode: e.target.checked })}
|
||||
/>
|
||||
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-amber-600"></div>
|
||||
<div className="w-12 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-amber-500"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* Guest Checkout */}
|
||||
<div className="flex items-center justify-between p-4 bg-gray-50 rounded-xl border border-gray-200">
|
||||
<div>
|
||||
<h4 className="font-bold text-gray-900 text-sm">اجازه خرید کاربر مهمان (allowGuestCheckout)</h4>
|
||||
<p className="text-xs text-gray-500 mt-0.5">امکان تسویهحساب سریع بدون نیاز به ایجاد حساب کاربری قبل از ثبت سفارش</p>
|
||||
</div>
|
||||
<label className="relative inline-flex items-center cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="sr-only peer"
|
||||
checked={system.allowGuestCheckout}
|
||||
onChange={(e) => setSystem({ ...system, allowGuestCheckout: e.target.checked })}
|
||||
/>
|
||||
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-purple-600"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* B2B Registration Open */}
|
||||
<div className="flex items-center justify-between p-4 bg-gray-50 rounded-xl border border-gray-200">
|
||||
<div>
|
||||
<h4 className="font-bold text-gray-900 text-sm">ثبتنام متقاضیان همکار باز است (b2bRegistrationOpen)</h4>
|
||||
<p className="text-xs text-gray-500 mt-0.5">فعال بودن فرم پذیرش درخواستهای جدید عمدهفروشی در سایت</p>
|
||||
</div>
|
||||
<label className="relative inline-flex items-center cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="sr-only peer"
|
||||
checked={system.b2bRegistrationOpen}
|
||||
onChange={(e) => setSystem({ ...system, b2bRegistrationOpen: e.target.checked })}
|
||||
/>
|
||||
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-purple-600"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{/* Support Phone */}
|
||||
<div>
|
||||
<label className="block text-sm font-bold text-gray-700 mb-1">شماره تلفن پشتیبانی اصلی (supportPhone) *</label>
|
||||
<input
|
||||
required
|
||||
type="text"
|
||||
value={system.supportPhone}
|
||||
onChange={(e) => setSystem({ ...system, supportPhone: e.target.value })}
|
||||
className="w-full px-4 py-3 rounded-xl border border-gray-200 focus:border-purple-500 outline-none text-sm font-bold"
|
||||
dir="ltr"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end pt-4 border-t border-gray-100">
|
||||
{/* Catalog Only Mode Card */}
|
||||
<div className="bg-white p-6 rounded-2xl shadow-sm border border-gray-200 space-y-4">
|
||||
<h3 className="text-base font-black text-gray-900 border-b border-gray-100 pb-3 flex items-center gap-2">
|
||||
<BookOpen className="w-5 h-5 text-purple-600" />
|
||||
حالت کاتالوگ آنلاین بدون فروش مستقیم (Catalog Only Mode)
|
||||
</h3>
|
||||
|
||||
<div className="p-4 bg-purple-50/60 rounded-2xl border border-purple-100 space-y-4">
|
||||
<div className="flex items-center justify-between">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-xl bg-purple-600 text-white flex items-center justify-center font-black">
|
||||
<BookOpen className="w-5 h-5" />
|
||||
</div>
|
||||
<div>
|
||||
<h4 className="font-bold text-gray-900 text-sm">فعالسازی حالت کاتالوگ</h4>
|
||||
<p className="text-xs text-gray-600 mt-0.5">
|
||||
مناسب برای زمانی که قصد دارید محصولات را صرفاً به عنوان دایرکتوری و مشخصات فنی معرفی کنید.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<label className="relative inline-flex items-center cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="sr-only peer"
|
||||
checked={catalogSettings.CATALOG_ONLY_MODE === 'true'}
|
||||
onChange={(e) =>
|
||||
setCatalogSettings({
|
||||
...catalogSettings,
|
||||
CATALOG_ONLY_MODE: e.target.checked ? 'true' : 'false',
|
||||
})
|
||||
}
|
||||
/>
|
||||
<div className="w-12 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-purple-600"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
{catalogSettings.CATALOG_ONLY_MODE === 'true' && (
|
||||
<div className="pt-4 border-t border-purple-200/60 grid grid-cols-1 md:grid-cols-2 gap-3 text-xs">
|
||||
<label className="flex items-center gap-2.5 font-bold text-gray-800 p-2.5 bg-white rounded-xl border border-purple-100 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={catalogSettings.CATALOG_SHOW_PRICES === 'true'}
|
||||
onChange={(e) =>
|
||||
setCatalogSettings({
|
||||
...catalogSettings,
|
||||
CATALOG_SHOW_PRICES: e.target.checked ? 'true' : 'false',
|
||||
})
|
||||
}
|
||||
className="w-4 h-4 rounded text-purple-600 focus:ring-purple-500"
|
||||
/>
|
||||
<span>نمایش قیمت محصولات در حالت کاتالوگ</span>
|
||||
</label>
|
||||
|
||||
<label className="flex items-center gap-2.5 font-bold text-gray-800 p-2.5 bg-white rounded-xl border border-purple-100 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={catalogSettings.CATALOG_ALLOW_CART === 'true'}
|
||||
onChange={(e) =>
|
||||
setCatalogSettings({
|
||||
...catalogSettings,
|
||||
CATALOG_ALLOW_CART: e.target.checked ? 'true' : 'false',
|
||||
})
|
||||
}
|
||||
className="w-4 h-4 rounded text-purple-600 focus:ring-purple-500"
|
||||
/>
|
||||
<span>امکان افزودن به سبد خرید</span>
|
||||
</label>
|
||||
|
||||
<label className="flex items-center gap-2.5 font-bold text-gray-800 p-2.5 bg-white rounded-xl border border-purple-100 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={catalogSettings.CATALOG_ALLOW_CHECKOUT === 'true'}
|
||||
onChange={(e) =>
|
||||
setCatalogSettings({
|
||||
...catalogSettings,
|
||||
CATALOG_ALLOW_CHECKOUT: e.target.checked ? 'true' : 'false',
|
||||
})
|
||||
}
|
||||
className="w-4 h-4 rounded text-purple-600 focus:ring-purple-500"
|
||||
/>
|
||||
<span>امکان ورود به صفحه تسویهحساب (ثبت فاکتور)</span>
|
||||
</label>
|
||||
|
||||
<label className="flex items-center gap-2.5 font-bold text-gray-800 p-2.5 bg-white rounded-xl border border-purple-100 cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={catalogSettings.CATALOG_PREORDER_BTN === 'true'}
|
||||
onChange={(e) =>
|
||||
setCatalogSettings({
|
||||
...catalogSettings,
|
||||
CATALOG_PREORDER_BTN: e.target.checked ? 'true' : 'false',
|
||||
})
|
||||
}
|
||||
className="w-4 h-4 rounded text-purple-600 focus:ring-purple-500"
|
||||
/>
|
||||
<span>نمایش دکمه «ثبت پیشخرید» به جای خرید مستقیم</span>
|
||||
</label>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* User & B2B System Rules */}
|
||||
<div className="bg-white p-6 rounded-2xl shadow-sm border border-gray-200 space-y-4">
|
||||
<h3 className="text-base font-black text-gray-900 border-b border-gray-100 pb-3 flex items-center gap-2">
|
||||
<ShoppingBag className="w-5 h-5 text-slate-700" />
|
||||
قوانین خرید مهمان و ثبتنام متقاضیان همکار
|
||||
</h3>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="flex items-center justify-between p-4 bg-gray-50 rounded-2xl border border-gray-200">
|
||||
<div>
|
||||
<h4 className="font-bold text-gray-900 text-sm">اجازه خرید کاربر مهمان</h4>
|
||||
<p className="text-xs text-gray-500 mt-0.5">تسویهحساب بدون نیاز به ساخت حساب کاربری قبلی</p>
|
||||
</div>
|
||||
<label className="relative inline-flex items-center cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="sr-only peer"
|
||||
checked={system.allowGuestCheckout}
|
||||
onChange={(e) => setSystem({ ...system, allowGuestCheckout: e.target.checked })}
|
||||
/>
|
||||
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-purple-600"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between p-4 bg-gray-50 rounded-2xl border border-gray-200">
|
||||
<div>
|
||||
<h4 className="font-bold text-gray-900 text-sm">فرم ثبتنام همکاران B2B باز است</h4>
|
||||
<p className="text-xs text-gray-500 mt-0.5">امکان ارسال درخواست نمایندگی جدید در سایت</p>
|
||||
</div>
|
||||
<label className="relative inline-flex items-center cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="sr-only peer"
|
||||
checked={system.b2bRegistrationOpen}
|
||||
onChange={(e) => setSystem({ ...system, b2bRegistrationOpen: e.target.checked })}
|
||||
/>
|
||||
<div className="w-11 h-6 bg-gray-200 peer-focus:outline-none rounded-full peer peer-checked:after:translate-x-full peer-checked:after:border-white after:content-[''] after:absolute after:top-[2px] after:left-[2px] after:bg-white after:border-gray-300 after:border after:rounded-full after:h-5 after:w-5 after:transition-all peer-checked:bg-purple-600"></div>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="md:col-span-2">
|
||||
<label className="block text-sm font-bold text-gray-700 mb-1">
|
||||
شماره تماس پشتیبانی اضطراری (در زمان تعمیرات)
|
||||
</label>
|
||||
<input
|
||||
required
|
||||
type="text"
|
||||
value={system.supportPhone}
|
||||
onChange={(e) => setSystem({ ...system, supportPhone: e.target.value })}
|
||||
className="w-full px-4 py-2.5 rounded-xl border border-gray-200 focus:border-purple-500 outline-none text-xs font-bold"
|
||||
dir="ltr"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-end">
|
||||
<button
|
||||
type="submit"
|
||||
disabled={isSaving}
|
||||
className="bg-purple-600 hover:bg-purple-700 text-white font-bold py-3 px-8 rounded-xl transition-colors flex items-center gap-2 shadow-md shadow-purple-200"
|
||||
className="bg-purple-600 hover:bg-purple-700 text-white font-bold py-3 px-8 rounded-xl transition-colors flex items-center gap-2 shadow-md shadow-purple-200 cursor-pointer"
|
||||
>
|
||||
{isSaving ? <Spinner size="sm" /> : <Save className="w-5 h-5" />}
|
||||
ذخیره تنظیمات سیستمی
|
||||
<span>ذخیره تنظیمات سیستمی</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -32,6 +32,8 @@ const PrescriptionsManager = lazyWithRetry(() => import('../pages/PrescriptionsM
|
||||
const B2BManager = lazyWithRetry(() => import('../pages/B2BManager'));
|
||||
const SeoSettingsPage = lazyWithRetry(() => import('../pages/SeoSettingsPage'));
|
||||
const FinancialSettingsPage = lazyWithRetry(() => import('../pages/FinancialSettingsPage'));
|
||||
const PaymentGatewaysPage = lazyWithRetry(() => import('../pages/PaymentGatewaysPage'));
|
||||
const ShippingSettingsPage = lazyWithRetry(() => import('../pages/ShippingSettingsPage'));
|
||||
const SystemSettingsPage = lazyWithRetry(() => import('../pages/SystemSettingsPage'));
|
||||
const SmsSettingsPage = lazyWithRetry(() => import('../pages/SmsSettingsPage'));
|
||||
const SslSettingsPage = lazyWithRetry(() => import('../pages/SslSettingsPage'));
|
||||
@ -68,6 +70,8 @@ export const router = createBrowserRouter([
|
||||
{ path: 'transactions/*', element: <Transactions /> },
|
||||
{ path: 'coupons/*', element: <Coupons /> },
|
||||
{ path: 'settings', element: <Settings /> },
|
||||
{ path: 'settings/payment-methods', element: <PaymentGatewaysPage /> },
|
||||
{ path: 'settings/shipping', element: <ShippingSettingsPage /> },
|
||||
{ path: 'settings/ssl', element: <SslSettingsPage /> },
|
||||
{ path: 'settings/sms', element: <SmsSettingsPage /> },
|
||||
{ path: 'settings/seo', element: <SeoSettingsPage /> },
|
||||
|
||||
@ -3,10 +3,10 @@
|
||||
"1": "productService.ts",
|
||||
"2": "CmsController",
|
||||
"3": "app.module.ts",
|
||||
"4": "reviews.controller.ts",
|
||||
"4": "CreateReviewDto",
|
||||
"5": "tickets.controller.ts",
|
||||
"6": "UserDashboard.tsx",
|
||||
"7": "Spinner.tsx",
|
||||
"7": "MediaSelector.tsx",
|
||||
"8": "admin.module.ts",
|
||||
"9": "PetProfile.tsx",
|
||||
"10": "DoctorsService",
|
||||
@ -28,7 +28,7 @@
|
||||
"26": "TEST-001",
|
||||
"27": "DEVOPS-001",
|
||||
"28": "DOC-001",
|
||||
"29": "WholesaleService",
|
||||
"29": "WholesaleApplyDto",
|
||||
"30": "main.ts",
|
||||
"31": "JwtAuthGuard",
|
||||
"32": "ZibalService",
|
||||
@ -42,9 +42,9 @@
|
||||
"40": "SslController",
|
||||
"41": "PodcastPlayerModal.tsx",
|
||||
"42": "IngredientsService",
|
||||
"43": "AuthService",
|
||||
"43": "RedisService",
|
||||
"44": "MediaController",
|
||||
"45": "Transactions.tsx",
|
||||
"45": "Pagination.tsx",
|
||||
"46": "SmsService",
|
||||
"47": "PetsService",
|
||||
"48": "PrescriptionsService",
|
||||
@ -69,8 +69,8 @@
|
||||
"67": "Operational Rules & Boundaries",
|
||||
"68": "Operational Rules & Boundaries",
|
||||
"69": "WikiController",
|
||||
"70": "ApiOperation",
|
||||
"71": "PetsController",
|
||||
"70": "AdminQueryDto",
|
||||
"71": ".update",
|
||||
"72": "seo.module.ts",
|
||||
"73": "admin.service.ts",
|
||||
"74": "🏢 AI Software Agency — Master Orchestration Protocol v3",
|
||||
@ -97,38 +97,38 @@
|
||||
"95": "Operational Rules & Boundaries",
|
||||
"96": "exclude",
|
||||
"97": "jest",
|
||||
"98": "AdminController",
|
||||
"98": "AdminService",
|
||||
"99": "Comprehensive Change Log",
|
||||
"100": "Operational Rules & Boundaries",
|
||||
"101": "Body",
|
||||
"101": "UITexts.tsx",
|
||||
"102": "eslint-plugin-prettier",
|
||||
"103": "ProductDto",
|
||||
"103": "SettingsController",
|
||||
"104": "AuthController",
|
||||
"105": "1. Summary of Integrity Repairs Performed",
|
||||
"106": "AdminService",
|
||||
"106": "orders.service.ts",
|
||||
"107": "Operational Rules & Boundaries",
|
||||
"108": "Operational Rules & Boundaries",
|
||||
"109": "Operational Rules & Boundaries",
|
||||
"110": "AppService",
|
||||
"111": "SmsLogQueryDto",
|
||||
"112": "BlogsService",
|
||||
"112": "PetsController",
|
||||
"113": "Vazirmatn Changelog",
|
||||
"114": "Vazirmatn Font فونت وزیرمتن",
|
||||
"115": "Operational Rules & Boundaries",
|
||||
"116": "compilerOptions",
|
||||
"117": "compilerOptions",
|
||||
"118": "backend/README.md",
|
||||
"119": "devDependencies",
|
||||
"119": "eslint",
|
||||
"120": "Repository Map",
|
||||
"121": "validate_integrity.js",
|
||||
"122": "admin-panel/package.json",
|
||||
"123": "Sahel-Font",
|
||||
"124": "Reports.tsx",
|
||||
"124": "Spinner.tsx",
|
||||
"125": "Sahel-Font",
|
||||
"126": "Role & Core Objective",
|
||||
"127": "orchestrate.py",
|
||||
"128": "backend/package.json",
|
||||
"129": "wholesale.controller.ts",
|
||||
"129": "WikiService",
|
||||
"130": "graphify reference: extra exports and benchmark",
|
||||
"131": "Phase 2 Final Quality Gate Summary Report",
|
||||
"132": "Task Modifications Log",
|
||||
@ -141,7 +141,7 @@
|
||||
"139": "System Discovery",
|
||||
"140": "Product Requirement Document (PRD)",
|
||||
"141": "WikiController",
|
||||
"142": "globals",
|
||||
"142": "devDependencies",
|
||||
"143": "@nestjs/cli",
|
||||
"144": "Baseline Command Plan & Reconciled Command History",
|
||||
"145": "SmsSettingsPage.tsx",
|
||||
@ -213,8 +213,8 @@
|
||||
"211": "@types/multer",
|
||||
"212": "CreateHealthLogDto",
|
||||
"213": "@testing-library/jest-dom",
|
||||
"214": "LoginDto",
|
||||
"215": ".addPattern",
|
||||
"214": "MetricsController",
|
||||
"215": "CreateReminderDto",
|
||||
"216": "FormField.tsx",
|
||||
"217": "Input.tsx",
|
||||
"218": "Textarea.tsx",
|
||||
@ -237,12 +237,12 @@
|
||||
"235": "typescript",
|
||||
"236": "vitest",
|
||||
"237": "axios",
|
||||
"238": "@types/passport-jwt",
|
||||
"239": "@types/supertest",
|
||||
"238": "bcryptjs",
|
||||
"239": "helmet",
|
||||
"240": "ts-loader",
|
||||
"241": "typescript",
|
||||
"241": "js-yaml",
|
||||
"242": "@types/bcrypt",
|
||||
"243": "RedisService",
|
||||
"243": "@nestjs/jwt",
|
||||
"244": "blog.entity.ts",
|
||||
"245": "home.entity.ts",
|
||||
"246": "wiki.entity.ts",
|
||||
@ -289,10 +289,25 @@
|
||||
"287": "Production Docker Compose",
|
||||
"288": "Staging Docker Compose",
|
||||
"289": "tailwindcss",
|
||||
"290": "@nestjs/swagger",
|
||||
"291": "NetworkBanner.tsx",
|
||||
"292": "@nestjs/throttler",
|
||||
"293": "passport-jwt",
|
||||
"294": "@prisma/client",
|
||||
"295": "reflect-metadata",
|
||||
"296": "swagger-ui-express",
|
||||
"297": "@eslint/eslintrc",
|
||||
"298": "@types/react-dom",
|
||||
"298": "eslint-config-prettier",
|
||||
"299": "@eslint/js",
|
||||
"300": "jest",
|
||||
"301": "@nestjs/schematics",
|
||||
"302": "@nestjs/testing",
|
||||
"303": "source-map-support",
|
||||
"304": "ts-jest",
|
||||
"305": "RouteErrorBoundary",
|
||||
"307": "AdminLoginDto",
|
||||
"306": "tsconfig-paths",
|
||||
"307": "@types/bcryptjs",
|
||||
"308": "typescript-eslint",
|
||||
"309": "eslint-config-next",
|
||||
"312": "tailwindcss"
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -1,5 +1,5 @@
|
||||
{
|
||||
"0": ".retryPayment",
|
||||
"0": "OrdersService",
|
||||
"1": "productService.ts",
|
||||
"2": "CmsController",
|
||||
"3": "app.module.ts",
|
||||
@ -28,28 +28,28 @@
|
||||
"26": "TEST-001",
|
||||
"27": "DEVOPS-001",
|
||||
"28": "DOC-001",
|
||||
"29": "WholesaleApplyDto",
|
||||
"29": "WholesaleService",
|
||||
"30": "main.ts",
|
||||
"31": "JwtAuthGuard",
|
||||
"32": "ZibalService",
|
||||
"33": "راهنمای تست سیستم (Software Testing)",
|
||||
"34": "CategoriesController",
|
||||
"35": "B2BController",
|
||||
"35": "B2BService",
|
||||
"36": "What You Must Do When Invoked",
|
||||
"37": "userStore.ts",
|
||||
"38": "UsersService",
|
||||
"39": "What You Must Do When Invoked",
|
||||
"40": "SslController",
|
||||
"41": "PodcastPlayerModal.tsx",
|
||||
"42": "IngredientsController",
|
||||
"42": "IngredientsService",
|
||||
"43": "AuthService",
|
||||
"44": "MediaController",
|
||||
"45": "Transactions.tsx",
|
||||
"46": "SmsService",
|
||||
"47": "PetsService",
|
||||
"48": "PrescriptionsController",
|
||||
"48": "PrescriptionsService",
|
||||
"49": "SmartAdvisorService",
|
||||
"50": "TestimonialsController",
|
||||
"50": "TestimonialsService",
|
||||
"51": "Role & Core Objective",
|
||||
"52": "ContactService",
|
||||
"53": "PaymentController",
|
||||
@ -57,13 +57,13 @@
|
||||
"55": "Media.tsx",
|
||||
"56": "compilerOptions",
|
||||
"57": "PetsController",
|
||||
"58": "BlogsController",
|
||||
"58": "PaginationDto",
|
||||
"59": "dependencies",
|
||||
"60": "compilerOptions",
|
||||
"61": "HomeClient.tsx",
|
||||
"62": "BlogsController",
|
||||
"63": "SettingsService",
|
||||
"64": "BannersController",
|
||||
"64": "BannersService",
|
||||
"65": "Required Review Group Closures",
|
||||
"66": "Coupons.tsx",
|
||||
"67": "Operational Rules & Boundaries",
|
||||
@ -111,7 +111,7 @@
|
||||
"109": "Operational Rules & Boundaries",
|
||||
"110": "AppService",
|
||||
"111": "SmsLogQueryDto",
|
||||
"112": "SettingsController",
|
||||
"112": "BlogsService",
|
||||
"113": "Vazirmatn Changelog",
|
||||
"114": "Vazirmatn Font فونت وزیرمتن",
|
||||
"115": "Operational Rules & Boundaries",
|
||||
@ -128,7 +128,7 @@
|
||||
"126": "Role & Core Objective",
|
||||
"127": "orchestrate.py",
|
||||
"128": "backend/package.json",
|
||||
"129": "OrdersController",
|
||||
"129": "wholesale.controller.ts",
|
||||
"130": "graphify reference: extra exports and benchmark",
|
||||
"131": "Phase 2 Final Quality Gate Summary Report",
|
||||
"132": "Task Modifications Log",
|
||||
@ -140,7 +140,7 @@
|
||||
"138": "InitiatePaymentDto",
|
||||
"139": "System Discovery",
|
||||
"140": "Product Requirement Document (PRD)",
|
||||
"141": "PaginationDto",
|
||||
"141": "WikiController",
|
||||
"142": "globals",
|
||||
"143": "@nestjs/cli",
|
||||
"144": "Baseline Command Plan & Reconciled Command History",
|
||||
@ -214,7 +214,7 @@
|
||||
"212": "CreateHealthLogDto",
|
||||
"213": "@testing-library/jest-dom",
|
||||
"214": "LoginDto",
|
||||
"215": "CreateOrderDto",
|
||||
"215": ".addPattern",
|
||||
"216": "FormField.tsx",
|
||||
"217": "Input.tsx",
|
||||
"218": "Textarea.tsx",
|
||||
@ -233,10 +233,10 @@
|
||||
"231": "typescript",
|
||||
"232": "RegisterDto",
|
||||
"233": "@testing-library/react",
|
||||
"234": "OrdersService",
|
||||
"234": "@types/react",
|
||||
"235": "typescript",
|
||||
"236": "vitest",
|
||||
"237": "WikiService",
|
||||
"237": "axios",
|
||||
"238": "@types/passport-jwt",
|
||||
"239": "@types/supertest",
|
||||
"240": "ts-loader",
|
||||
@ -288,14 +288,8 @@
|
||||
"286": "Shabnam Font Sample",
|
||||
"287": "Production Docker Compose",
|
||||
"288": "Staging Docker Compose",
|
||||
"289": "eslint-config-next",
|
||||
"290": "MetricsController",
|
||||
"289": "tailwindcss",
|
||||
"291": "NetworkBanner.tsx",
|
||||
"292": ".findAll",
|
||||
"293": "CreateReminderDto",
|
||||
"294": "TestimonialsService",
|
||||
"295": "prescriptions.controller.ts",
|
||||
"296": "ValidateCouponDto",
|
||||
"297": "@eslint/eslintrc",
|
||||
"298": "@types/react-dom",
|
||||
"305": "RouteErrorBoundary",
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
# Graph Report - canina (2026-08-18)
|
||||
|
||||
## Corpus Check
|
||||
- 513 files · ~735,602 words
|
||||
- 513 files · ~735,601 words
|
||||
- Verdict: corpus is large enough that graph structure adds value.
|
||||
|
||||
## Summary
|
||||
- 3648 nodes · 6193 edges · 302 communities (200 shown, 102 thin omitted)
|
||||
- 3650 nodes · 6193 edges · 296 communities (194 shown, 102 thin omitted)
|
||||
- Extraction: 96% EXTRACTED · 4% INFERRED · 0% AMBIGUOUS · INFERRED: 230 edges (avg confidence: 0.79)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
- Run `graphify update .` after code changes (no API cost).
|
||||
|
||||
## Community Hubs (Navigation)
|
||||
- .retryPayment
|
||||
- OrdersService
|
||||
- productService.ts
|
||||
- CmsController
|
||||
- app.module.ts
|
||||
@ -44,28 +44,28 @@
|
||||
- TEST-001
|
||||
- DEVOPS-001
|
||||
- DOC-001
|
||||
- WholesaleApplyDto
|
||||
- WholesaleService
|
||||
- main.ts
|
||||
- JwtAuthGuard
|
||||
- ZibalService
|
||||
- راهنمای تست سیستم (Software Testing)
|
||||
- CategoriesController
|
||||
- B2BController
|
||||
- B2BService
|
||||
- What You Must Do When Invoked
|
||||
- userStore.ts
|
||||
- UsersService
|
||||
- What You Must Do When Invoked
|
||||
- SslController
|
||||
- PodcastPlayerModal.tsx
|
||||
- IngredientsController
|
||||
- IngredientsService
|
||||
- AuthService
|
||||
- MediaController
|
||||
- Transactions.tsx
|
||||
- SmsService
|
||||
- PetsService
|
||||
- PrescriptionsController
|
||||
- PrescriptionsService
|
||||
- SmartAdvisorService
|
||||
- TestimonialsController
|
||||
- TestimonialsService
|
||||
- Role & Core Objective
|
||||
- ContactService
|
||||
- PaymentController
|
||||
@ -73,13 +73,13 @@
|
||||
- Media.tsx
|
||||
- compilerOptions
|
||||
- PetsController
|
||||
- BlogsController
|
||||
- PaginationDto
|
||||
- dependencies
|
||||
- compilerOptions
|
||||
- HomeClient.tsx
|
||||
- BlogsController
|
||||
- SettingsService
|
||||
- BannersController
|
||||
- BannersService
|
||||
- Required Review Group Closures
|
||||
- Coupons.tsx
|
||||
- Operational Rules & Boundaries
|
||||
@ -127,7 +127,7 @@
|
||||
- Operational Rules & Boundaries
|
||||
- AppService
|
||||
- SmsLogQueryDto
|
||||
- SettingsController
|
||||
- BlogsService
|
||||
- Vazirmatn Changelog
|
||||
- Vazirmatn Font فونت وزیرمتن
|
||||
- Operational Rules & Boundaries
|
||||
@ -144,7 +144,7 @@
|
||||
- Role & Core Objective
|
||||
- orchestrate.py
|
||||
- backend/package.json
|
||||
- OrdersController
|
||||
- wholesale.controller.ts
|
||||
- graphify reference: extra exports and benchmark
|
||||
- Phase 2 Final Quality Gate Summary Report
|
||||
- Task Modifications Log
|
||||
@ -156,7 +156,7 @@
|
||||
- InitiatePaymentDto
|
||||
- System Discovery
|
||||
- Product Requirement Document (PRD)
|
||||
- PaginationDto
|
||||
- WikiController
|
||||
- globals
|
||||
- @nestjs/cli
|
||||
- Baseline Command Plan & Reconciled Command History
|
||||
@ -230,7 +230,7 @@
|
||||
- CreateHealthLogDto
|
||||
- @testing-library/jest-dom
|
||||
- LoginDto
|
||||
- CreateOrderDto
|
||||
- .addPattern
|
||||
- FormField.tsx
|
||||
- Input.tsx
|
||||
- Textarea.tsx
|
||||
@ -249,10 +249,9 @@
|
||||
- typescript
|
||||
- RegisterDto
|
||||
- @testing-library/react
|
||||
- OrdersService
|
||||
- @types/react
|
||||
- typescript
|
||||
- vitest
|
||||
- WikiService
|
||||
- @types/passport-jwt
|
||||
- @types/supertest
|
||||
- ts-loader
|
||||
@ -291,14 +290,7 @@
|
||||
- Shabnam Font Sample
|
||||
- Production Docker Compose
|
||||
- Staging Docker Compose
|
||||
- eslint-config-next
|
||||
- MetricsController
|
||||
- NetworkBanner.tsx
|
||||
- .findAll
|
||||
- CreateReminderDto
|
||||
- TestimonialsService
|
||||
- prescriptions.controller.ts
|
||||
- ValidateCouponDto
|
||||
- @eslint/eslintrc
|
||||
- @types/react-dom
|
||||
- RouteErrorBoundary
|
||||
@ -320,14 +312,14 @@
|
||||
## Surprising Connections (you probably didn't know these)
|
||||
- `User Profile Photo` --conceptually_related_to--> `User Roles and Capabilities` [INFERRED]
|
||||
backend/uploads/1781288429353-508765350.jpg → docs/02-user-guide.md
|
||||
- `OrdersController` --references--> `ApiResponse` [EXTRACTED]
|
||||
backend/src/orders/orders.controller.ts → frontend/admin-panel/src/types/admin.ts
|
||||
- `AuthController` --references--> `ApiResponse` [EXTRACTED]
|
||||
backend/src/auth/auth.controller.ts → frontend/admin-panel/src/types/admin.ts
|
||||
- `WikiController` --references--> `ApiResponse` [EXTRACTED]
|
||||
backend/src/wiki/wiki.controller.ts → frontend/admin-panel/src/types/admin.ts
|
||||
- `ProductsController` --references--> `ApiResponse` [EXTRACTED]
|
||||
backend/src/products/products.controller.ts → frontend/admin-panel/src/types/admin.ts
|
||||
- `BlogsController` --references--> `ApiResponse` [EXTRACTED]
|
||||
backend/src/blogs/blogs.controller.ts → frontend/admin-panel/src/types/admin.ts
|
||||
- `HomeController` --references--> `ApiResponse` [EXTRACTED]
|
||||
backend/src/home/home.controller.ts → frontend/admin-panel/src/types/admin.ts
|
||||
- `OrdersController` --references--> `ApiResponse` [EXTRACTED]
|
||||
backend/src/orders/orders.controller.ts → frontend/admin-panel/src/types/admin.ts
|
||||
|
||||
## Import Cycles
|
||||
- 3-file cycle: `frontend/application/lib/services/api.ts -> frontend/application/lib/store/userStore.ts -> frontend/application/lib/services/authService.ts -> frontend/application/lib/services/api.ts`
|
||||
@ -338,11 +330,11 @@
|
||||
- **Rastikerdar Font Ecosystem** — frontend_application_public_fonts_shabnam_font_v5_0_1_readme, frontend_application_public_fonts_vazirmatn_v33_003_readme, vazir_font [EXTRACTED 0.95]
|
||||
- **Canina Deployment Stack** — scripts_compose_prod, scripts_compose_stage [EXTRACTED 1.00]
|
||||
|
||||
## Communities (302 total, 102 thin omitted)
|
||||
## Communities (296 total, 102 thin omitted)
|
||||
|
||||
### Community 0 - ".retryPayment"
|
||||
Cohesion: 0.19
|
||||
Nodes (11): ApiBadRequestResponse, ApiCreatedResponse, ApiNotFoundResponse, ApiOkResponse, ApiOperation, Body, Get, Param (+3 more)
|
||||
### Community 0 - "OrdersService"
|
||||
Cohesion: 0.06
|
||||
Nodes (35): CreateOrderDto, OrderItemDto, ApiProperty, ApiPropertyOptional, IsArray, IsNotEmpty, IsNumber, IsOptional (+27 more)
|
||||
|
||||
### Community 1 - "productService.ts"
|
||||
Cohesion: 0.06
|
||||
@ -354,7 +346,7 @@ Nodes (24): CmsController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controlle
|
||||
|
||||
### Community 3 - "app.module.ts"
|
||||
Cohesion: 0.08
|
||||
Nodes (29): B2BModule, Module, BannersModule, Module, CmsModule, Module, SmsModule, Global (+21 more)
|
||||
Nodes (30): B2BModule, Module, BannersModule, Module, CmsModule, Module, SmsModule, Global (+22 more)
|
||||
|
||||
### Community 4 - "reviews.controller.ts"
|
||||
Cohesion: 0.07
|
||||
@ -374,7 +366,7 @@ Nodes (21): ConfirmModal(), ConfirmModalProps, getFileType(), Media, MediaSelect
|
||||
|
||||
### Community 8 - "admin.module.ts"
|
||||
Cohesion: 0.06
|
||||
Nodes (21): AdminModule, Module, BlogQuery, BlogsService, Injectable, PetQuery, PetsService, Injectable (+13 more)
|
||||
Nodes (21): AdminModule, Module, PetQuery, PetsService, Injectable, ReportsController, ApiBearerAuth, ApiOperation (+13 more)
|
||||
|
||||
### Community 9 - "PetProfile.tsx"
|
||||
Cohesion: 0.14
|
||||
@ -394,14 +386,14 @@ Nodes (29): App(), HeroBanner, VetTestimonial, ContactInfoItem, ContactSubmissio
|
||||
|
||||
### Community 13 - "PrismaService"
|
||||
Cohesion: 0.07
|
||||
Nodes (20): CategoryQuery, B2BService, B2BWholesaleOrderItem, Injectable, BannersService, Injectable, MeliPayamakPattern, MeliPayamakResponse (+12 more)
|
||||
Nodes (19): ApiExcludeController, CategoryQuery, MetricsController, Controller, Get, Res, MeliPayamakPattern, MeliPayamakResponse (+11 more)
|
||||
|
||||
### Community 14 - "pets/pets.controller.ts"
|
||||
Cohesion: 0.16
|
||||
Nodes (13): CreatePetDto, ApiProperty, ApiPropertyOptional, IsArray, IsNotEmpty, IsNumber, IsOptional, IsString (+5 more)
|
||||
Cohesion: 0.11
|
||||
Nodes (19): CreatePetDto, ApiProperty, ApiPropertyOptional, IsArray, IsNotEmpty, IsNumber, IsOptional, IsString (+11 more)
|
||||
|
||||
### Community 15 - "ProductsService"
|
||||
Cohesion: 0.10
|
||||
Cohesion: 0.09
|
||||
Nodes (19): GetProductsDto, ApiPropertyOptional, IsEnum, IsOptional, IsString, ProductsController, ApiOperation, ApiTags (+11 more)
|
||||
|
||||
### Community 16 - "lib/services/api.ts"
|
||||
@ -425,8 +417,8 @@ Cohesion: 0.06
|
||||
Nodes (32): Acceptance Criteria, Affected Application, Affected Files, Alternative Direction, BE-001, Category, Completion Statement, Confidence (+24 more)
|
||||
|
||||
### Community 21 - "Roles"
|
||||
Cohesion: 0.29
|
||||
Nodes (9): Roles(), ApiBearerAuth, Body, Delete, Param, Patch, Post, Put (+1 more)
|
||||
Cohesion: 0.20
|
||||
Nodes (15): Roles(), SettingsController, ApiBearerAuth, ApiOkResponse, ApiOperation, ApiTags, Body, Controller (+7 more)
|
||||
|
||||
### Community 22 - "FE-001"
|
||||
Cohesion: 0.06
|
||||
@ -456,17 +448,17 @@ Nodes (31): Acceptance Criteria, Affected Application, Affected Files, Alternati
|
||||
Cohesion: 0.06
|
||||
Nodes (31): Acceptance Criteria, Affected Application, Affected Files, Alternative Direction, Category, Completion Statement, Confidence, Dependencies (+23 more)
|
||||
|
||||
### Community 29 - "WholesaleApplyDto"
|
||||
Cohesion: 0.10
|
||||
Nodes (20): ApiProperty, ApiPropertyOptional, IsNotEmpty, IsOptional, IsString, WholesaleApplyDto, ApiBearerAuth, ApiOperation (+12 more)
|
||||
### Community 29 - "WholesaleService"
|
||||
Cohesion: 0.14
|
||||
Nodes (14): ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Get, Param, Post (+6 more)
|
||||
|
||||
### Community 30 - "main.ts"
|
||||
Cohesion: 0.11
|
||||
Nodes (11): AppModule, Module, CustomHttpExceptionFilter, Catch, PrismaExceptionFilter, Catch, DecimalInterceptor, Injectable (+3 more)
|
||||
|
||||
### Community 31 - "JwtAuthGuard"
|
||||
Cohesion: 0.17
|
||||
Nodes (7): JwtAuthGuard, Injectable, ROLES_KEY, SortOrder, RequestWithUser, RolesGuard, Injectable
|
||||
Cohesion: 0.15
|
||||
Nodes (9): JwtAuthGuard, Injectable, B2BWholesaleOrderItem, ROLES_KEY, SortOrder, RequestWithUser, RolesGuard, Injectable (+1 more)
|
||||
|
||||
### Community 32 - "ZibalService"
|
||||
Cohesion: 0.15
|
||||
@ -480,9 +472,9 @@ Nodes (25): اجرای بکاند, اجرای فرانتاند, اجرای
|
||||
Cohesion: 0.10
|
||||
Nodes (16): CategoriesController, ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Body, Controller, Delete (+8 more)
|
||||
|
||||
### Community 35 - "B2BController"
|
||||
### Community 35 - "B2BService"
|
||||
Cohesion: 0.14
|
||||
Nodes (12): B2BController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Get, Param (+4 more)
|
||||
Nodes (14): B2BController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Get, Param (+6 more)
|
||||
|
||||
### Community 36 - "What You Must Do When Invoked"
|
||||
Cohesion: 0.07
|
||||
@ -508,9 +500,9 @@ Nodes (14): SslController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controlle
|
||||
Cohesion: 0.40
|
||||
Nodes (3): PLAYBACK_RATES, PodcastPlayerModal(), PodcastPlayerModalProps
|
||||
|
||||
### Community 42 - "IngredientsController"
|
||||
### Community 42 - "IngredientsService"
|
||||
Cohesion: 0.13
|
||||
Nodes (12): IngredientsController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+4 more)
|
||||
Nodes (14): IngredientsController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+6 more)
|
||||
|
||||
### Community 43 - "AuthService"
|
||||
Cohesion: 0.22
|
||||
@ -524,17 +516,17 @@ Nodes (16): MediaController, ApiBearerAuth, ApiOperation, ApiTags, Body, Control
|
||||
Cohesion: 0.33
|
||||
Nodes (4): GatewayHealth, Stats, Transaction, Transactions
|
||||
|
||||
### Community 48 - "PrescriptionsController"
|
||||
Cohesion: 0.15
|
||||
Nodes (12): PrescriptionsController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Get, Param (+4 more)
|
||||
### Community 48 - "PrescriptionsService"
|
||||
Cohesion: 0.14
|
||||
Nodes (14): PrescriptionsController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Get, Param (+6 more)
|
||||
|
||||
### Community 49 - "SmartAdvisorService"
|
||||
Cohesion: 0.13
|
||||
Nodes (14): SmartAdvisorController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+6 more)
|
||||
|
||||
### Community 50 - "TestimonialsController"
|
||||
Cohesion: 0.14
|
||||
Nodes (12): TestimonialsController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+4 more)
|
||||
### Community 50 - "TestimonialsService"
|
||||
Cohesion: 0.13
|
||||
Nodes (14): TestimonialsController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+6 more)
|
||||
|
||||
### Community 51 - "Role & Core Objective"
|
||||
Cohesion: 0.09
|
||||
@ -564,9 +556,9 @@ Nodes (23): compilerOptions, allowImportingTsExtensions, erasableSyntaxOnly, jsx
|
||||
Cohesion: 0.15
|
||||
Nodes (11): PetsController, ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Controller, Delete, Get (+3 more)
|
||||
|
||||
### Community 58 - "BlogsController"
|
||||
Cohesion: 0.13
|
||||
Nodes (13): BlogsController, ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiTags, Controller, Get, Param (+5 more)
|
||||
### Community 58 - "PaginationDto"
|
||||
Cohesion: 0.09
|
||||
Nodes (21): BlogsController, ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiTags, Controller, Get, Param (+13 more)
|
||||
|
||||
### Community 59 - "dependencies"
|
||||
Cohesion: 0.05
|
||||
@ -585,12 +577,12 @@ Cohesion: 0.13
|
||||
Nodes (15): BlogsController, ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Body, Controller, Delete (+7 more)
|
||||
|
||||
### Community 63 - "SettingsService"
|
||||
Cohesion: 0.10
|
||||
Cohesion: 0.12
|
||||
Nodes (3): SmsLogQuery, SettingsService, Injectable
|
||||
|
||||
### Community 64 - "BannersController"
|
||||
### Community 64 - "BannersService"
|
||||
Cohesion: 0.13
|
||||
Nodes (13): BannersController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+5 more)
|
||||
Nodes (15): BannersController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+7 more)
|
||||
|
||||
### Community 65 - "Required Review Group Closures"
|
||||
Cohesion: 0.10
|
||||
@ -658,7 +650,7 @@ Nodes (9): GatewayHealthResult, IPaymentGateway, PaymentInquiryResult, PaymentRe
|
||||
|
||||
### Community 81 - "devDependencies"
|
||||
Cohesion: 0.13
|
||||
Nodes (15): devDependencies, eslint, jsdom, tailwindcss, @tailwindcss/postcss, @types/node, @types/react, @vitejs/plugin-react (+7 more)
|
||||
Nodes (15): eslint-config-next, devDependencies, eslint, eslint-config-next, jsdom, tailwindcss, @tailwindcss/postcss, @types/node (+7 more)
|
||||
|
||||
### Community 82 - "api"
|
||||
Cohesion: 0.15
|
||||
@ -702,7 +694,7 @@ Nodes (32): compilerOptions, allowJs, esModuleInterop, incremental, isolatedModu
|
||||
|
||||
### Community 92 - "scripts"
|
||||
Cohesion: 0.14
|
||||
Nodes (14): scripts, build, docs:generate, format, lint, start, start:debug, start:dev (+6 more)
|
||||
Nodes (14): scripts, build, docs:generate, lint, prestart:dev, start, start:debug, start:dev (+6 more)
|
||||
|
||||
### Community 93 - "Deep Audit Summary Report"
|
||||
Cohesion: 0.14
|
||||
@ -768,9 +760,9 @@ Nodes (5): AppController, Controller, Get, AppService, Injectable
|
||||
Cohesion: 0.25
|
||||
Nodes (7): SmsLogQueryDto, ApiPropertyOptional, IsIn, IsNumber, IsOptional, IsString, Type
|
||||
|
||||
### Community 112 - "SettingsController"
|
||||
Cohesion: 0.24
|
||||
Nodes (7): SettingsController, ApiOkResponse, ApiOperation, ApiTags, Controller, Get, Query
|
||||
### Community 112 - "BlogsService"
|
||||
Cohesion: 0.22
|
||||
Nodes (3): BlogQuery, BlogsService, Injectable
|
||||
|
||||
### Community 113 - "Vazirmatn Changelog"
|
||||
Cohesion: 0.18
|
||||
@ -836,9 +828,9 @@ Nodes (8): cmd_next_task(), cmd_progress(), cmd_reset(), cmd_status(), cmd_unblo
|
||||
Cohesion: 0.22
|
||||
Nodes (8): author, description, license, name, prisma, seed, private, version
|
||||
|
||||
### Community 129 - "OrdersController"
|
||||
Cohesion: 0.22
|
||||
Nodes (7): OrdersController, ApiBearerAuth, ApiTags, Controller, UseGuards, OrdersModule, Module
|
||||
### Community 129 - "wholesale.controller.ts"
|
||||
Cohesion: 0.31
|
||||
Nodes (6): ApiProperty, ApiPropertyOptional, IsNotEmpty, IsOptional, IsString, WholesaleApplyDto
|
||||
|
||||
### Community 130 - "graphify reference: extra exports and benchmark"
|
||||
Cohesion: 0.22
|
||||
@ -884,9 +876,9 @@ Nodes (7): Active Core Applications, Current Architecture, Evidence-Based Status
|
||||
Cohesion: 0.29
|
||||
Nodes (6): 1. Executive Vision, 2. Target Audience, 3. Functional Requirements, 4. Non-Functional Requirements (Performance, Security), 5. Epic / Feature Breakdown, Product Requirement Document (PRD)
|
||||
|
||||
### Community 141 - "PaginationDto"
|
||||
Cohesion: 0.11
|
||||
Nodes (15): PaginationDto, ApiPropertyOptional, IsEnum, IsInt, IsOptional, IsString, Min, Type (+7 more)
|
||||
### Community 141 - "WikiController"
|
||||
Cohesion: 0.13
|
||||
Nodes (13): ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiTags, Controller, Get, Param, Query (+5 more)
|
||||
|
||||
### Community 144 - "Baseline Command Plan & Reconciled Command History"
|
||||
Cohesion: 0.29
|
||||
@ -1040,10 +1032,6 @@ Nodes (6): CreateHealthLogDto, ApiProperty, ApiPropertyOptional, IsNotEmpty, IsO
|
||||
Cohesion: 0.33
|
||||
Nodes (5): LoginDto, ApiProperty, IsNotEmpty, IsString, MinLength
|
||||
|
||||
### Community 215 - "CreateOrderDto"
|
||||
Cohesion: 0.22
|
||||
Nodes (11): CreateOrderDto, OrderItemDto, ApiProperty, ApiPropertyOptional, IsArray, IsNotEmpty, IsNumber, IsOptional (+3 more)
|
||||
|
||||
### Community 223 - "Shabnam Font README"
|
||||
Cohesion: 0.67
|
||||
Nodes (3): Shabnam Font README, Shabnam Font Sample, Vazir Font
|
||||
@ -1052,34 +1040,6 @@ Nodes (3): Shabnam Font README, Shabnam Font Sample, Vazir Font
|
||||
Cohesion: 0.22
|
||||
Nodes (8): RegisterDto, ApiProperty, ApiPropertyOptional, IsEmail, IsNotEmpty, IsOptional, IsString, MinLength
|
||||
|
||||
### Community 237 - "WikiService"
|
||||
Cohesion: 0.22
|
||||
Nodes (3): Injectable, WikiQuery, WikiService
|
||||
|
||||
### Community 290 - "MetricsController"
|
||||
Cohesion: 0.25
|
||||
Nodes (5): ApiExcludeController, MetricsController, Controller, Get, Res
|
||||
|
||||
### Community 292 - ".findAll"
|
||||
Cohesion: 0.32
|
||||
Nodes (6): ApiNotFoundResponse, ApiOkResponse, ApiOperation, Get, Param, Query
|
||||
|
||||
### Community 293 - "CreateReminderDto"
|
||||
Cohesion: 0.29
|
||||
Nodes (6): CreateReminderDto, ApiProperty, ApiPropertyOptional, IsNotEmpty, IsOptional, IsString
|
||||
|
||||
### Community 294 - "TestimonialsService"
|
||||
Cohesion: 0.33
|
||||
Nodes (4): TestimonialsModule, Module, TestimonialsService, Injectable
|
||||
|
||||
### Community 295 - "prescriptions.controller.ts"
|
||||
Cohesion: 0.53
|
||||
Nodes (3): UserReqPayload, PrescriptionsService, Injectable
|
||||
|
||||
### Community 296 - "ValidateCouponDto"
|
||||
Cohesion: 0.50
|
||||
Nodes (4): IsNotEmpty, IsNumber, IsString, ValidateCouponDto
|
||||
|
||||
### Community 305 - "RouteErrorBoundary"
|
||||
Cohesion: 0.22
|
||||
Nodes (3): Props, RouteErrorBoundary, State
|
||||
@ -1089,24 +1049,24 @@ Cohesion: 0.29
|
||||
Nodes (6): AdminLoginDto, ApiProperty, IsEmail, IsNotEmpty, IsString, MinLength
|
||||
|
||||
## Knowledge Gaps
|
||||
- **1242 isolated node(s):** `BlogPost`, `SmartAdvisorProps`, `DosageResult`, `FAQ`, `Specialist` (+1237 more)
|
||||
- **1242 isolated node(s):** `$schema`, `collection`, `sourceRoot`, `deleteOutDir`, `name` (+1237 more)
|
||||
These have ≤1 connection - possible missing edges or undocumented components.
|
||||
- **102 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
||||
|
||||
## Suggested Questions
|
||||
_Questions this graph is uniquely positioned to answer:_
|
||||
|
||||
- **Why does `ApiResponse` connect `src/services/api.ts` to `OrdersController`, `UsersService`, `PetsController`, `AuthController`, `PaginationDto`, `HomeController`, `ProductsService`, `BlogsController`?**
|
||||
_High betweenness centrality (0.060) - this node is a cross-community bridge._
|
||||
- **Why does `Roles()` connect `Roles` to `BannersController`, `CmsController`, `B2BController`, `reviews.controller.ts`, `tickets.controller.ts`, `prescriptions.controller.ts`, `SslController`, `IngredientsController`, `ProductsService`, `PrescriptionsController`, `SettingsController`, `SmartAdvisorService`, `TestimonialsController`, `ContactService`, `PaymentController`, `WholesaleApplyDto`, `JwtAuthGuard`?**
|
||||
_High betweenness centrality (0.045) - this node is a cross-community bridge._
|
||||
- **Why does `JwtAuthGuard` connect `JwtAuthGuard` to `OrdersController`, `app.module.ts`, `reviews.controller.ts`, `tickets.controller.ts`, `UsersService`, `prescriptions.controller.ts`, `admin.module.ts`, `admin.service.ts`, `MediaController`, `pets/pets.controller.ts`, `ProductsService`, `CreateVideoDto`, `auth.service.ts`?**
|
||||
_High betweenness centrality (0.026) - this node is a cross-community bridge._
|
||||
- **What connects `BlogPost`, `SmartAdvisorProps`, `DosageResult` to the rest of the system?**
|
||||
- **Why does `Roles()` connect `Roles` to `BannersService`, `wholesale.controller.ts`, `CmsController`, `B2BService`, `reviews.controller.ts`, `tickets.controller.ts`, `SslController`, `IngredientsService`, `ProductsService`, `PrescriptionsService`, `SmartAdvisorService`, `TestimonialsService`, `ContactService`, `PaymentController`, `.addPattern`, `WholesaleService`, `JwtAuthGuard`?**
|
||||
_High betweenness centrality (0.051) - this node is a cross-community bridge._
|
||||
- **Why does `ApiResponse` connect `src/services/api.ts` to `OrdersService`, `UsersService`, `PetsController`, `AuthController`, `WikiController`, `HomeController`, `ProductsService`, `PaginationDto`?**
|
||||
_High betweenness centrality (0.040) - this node is a cross-community bridge._
|
||||
- **Why does `JwtAuthGuard` connect `JwtAuthGuard` to `OrdersService`, `wholesale.controller.ts`, `CmsController`, `reviews.controller.ts`, `tickets.controller.ts`, `UsersService`, `admin.module.ts`, `admin.service.ts`, `MediaController`, `PrismaService`, `pets/pets.controller.ts`, `ProductsService`, `CreateVideoDto`, `auth.service.ts`?**
|
||||
_High betweenness centrality (0.024) - this node is a cross-community bridge._
|
||||
- **What connects `$schema`, `collection`, `sourceRoot` to the rest of the system?**
|
||||
_1242 weakly-connected nodes found - possible documentation gaps or missing edges._
|
||||
- **Should `OrdersService` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.06168831168831169 - nodes in this community are weakly interconnected._
|
||||
- **Should `productService.ts` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.05888376856118792 - nodes in this community are weakly interconnected._
|
||||
- **Should `CmsController` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.08823529411764706 - nodes in this community are weakly interconnected._
|
||||
- **Should `app.module.ts` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.08350951374207188 - nodes in this community are weakly interconnected._
|
||||
_Cohesion score 0.0899854862119013 - nodes in this community are weakly interconnected._
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,16 +1,16 @@
|
||||
# Graph Report - canina (2026-08-18)
|
||||
|
||||
## Corpus Check
|
||||
- 513 files · ~735,601 words
|
||||
- 517 files · ~740,145 words
|
||||
- Verdict: corpus is large enough that graph structure adds value.
|
||||
|
||||
## Summary
|
||||
- 3650 nodes · 6193 edges · 296 communities (194 shown, 102 thin omitted)
|
||||
- 3669 nodes · 6227 edges · 311 communities (195 shown, 116 thin omitted)
|
||||
- Extraction: 96% EXTRACTED · 4% INFERRED · 0% AMBIGUOUS · INFERRED: 230 edges (avg confidence: 0.79)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Graph Freshness
|
||||
- Built from commit: `2ee85848`
|
||||
- Built from commit: `aa10ee73`
|
||||
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
|
||||
- Run `graphify update .` after code changes (no API cost).
|
||||
|
||||
@ -19,10 +19,10 @@
|
||||
- productService.ts
|
||||
- CmsController
|
||||
- app.module.ts
|
||||
- reviews.controller.ts
|
||||
- CreateReviewDto
|
||||
- tickets.controller.ts
|
||||
- UserDashboard.tsx
|
||||
- Spinner.tsx
|
||||
- MediaSelector.tsx
|
||||
- admin.module.ts
|
||||
- PetProfile.tsx
|
||||
- DoctorsService
|
||||
@ -44,7 +44,7 @@
|
||||
- TEST-001
|
||||
- DEVOPS-001
|
||||
- DOC-001
|
||||
- WholesaleService
|
||||
- WholesaleApplyDto
|
||||
- main.ts
|
||||
- JwtAuthGuard
|
||||
- ZibalService
|
||||
@ -58,9 +58,9 @@
|
||||
- SslController
|
||||
- PodcastPlayerModal.tsx
|
||||
- IngredientsService
|
||||
- AuthService
|
||||
- RedisService
|
||||
- MediaController
|
||||
- Transactions.tsx
|
||||
- Pagination.tsx
|
||||
- SmsService
|
||||
- PetsService
|
||||
- PrescriptionsService
|
||||
@ -85,8 +85,8 @@
|
||||
- Operational Rules & Boundaries
|
||||
- Operational Rules & Boundaries
|
||||
- WikiController
|
||||
- ApiOperation
|
||||
- PetsController
|
||||
- AdminQueryDto
|
||||
- .update
|
||||
- seo.module.ts
|
||||
- admin.service.ts
|
||||
- 🏢 AI Software Agency — Master Orchestration Protocol v3
|
||||
@ -113,38 +113,38 @@
|
||||
- Operational Rules & Boundaries
|
||||
- exclude
|
||||
- jest
|
||||
- AdminController
|
||||
- AdminService
|
||||
- Comprehensive Change Log
|
||||
- Operational Rules & Boundaries
|
||||
- Body
|
||||
- UITexts.tsx
|
||||
- eslint-plugin-prettier
|
||||
- ProductDto
|
||||
- SettingsController
|
||||
- AuthController
|
||||
- 1. Summary of Integrity Repairs Performed
|
||||
- AdminService
|
||||
- orders.service.ts
|
||||
- Operational Rules & Boundaries
|
||||
- Operational Rules & Boundaries
|
||||
- Operational Rules & Boundaries
|
||||
- AppService
|
||||
- SmsLogQueryDto
|
||||
- BlogsService
|
||||
- PetsController
|
||||
- Vazirmatn Changelog
|
||||
- Vazirmatn Font فونت وزیرمتن
|
||||
- Operational Rules & Boundaries
|
||||
- compilerOptions
|
||||
- compilerOptions
|
||||
- backend/README.md
|
||||
- devDependencies
|
||||
- eslint
|
||||
- Repository Map
|
||||
- validate_integrity.js
|
||||
- admin-panel/package.json
|
||||
- Sahel-Font
|
||||
- Reports.tsx
|
||||
- Spinner.tsx
|
||||
- Sahel-Font
|
||||
- Role & Core Objective
|
||||
- orchestrate.py
|
||||
- backend/package.json
|
||||
- wholesale.controller.ts
|
||||
- WikiService
|
||||
- graphify reference: extra exports and benchmark
|
||||
- Phase 2 Final Quality Gate Summary Report
|
||||
- Task Modifications Log
|
||||
@ -157,7 +157,7 @@
|
||||
- System Discovery
|
||||
- Product Requirement Document (PRD)
|
||||
- WikiController
|
||||
- globals
|
||||
- devDependencies
|
||||
- @nestjs/cli
|
||||
- Baseline Command Plan & Reconciled Command History
|
||||
- SmsSettingsPage.tsx
|
||||
@ -229,8 +229,8 @@
|
||||
- @types/multer
|
||||
- CreateHealthLogDto
|
||||
- @testing-library/jest-dom
|
||||
- LoginDto
|
||||
- .addPattern
|
||||
- MetricsController
|
||||
- CreateReminderDto
|
||||
- FormField.tsx
|
||||
- Input.tsx
|
||||
- Textarea.tsx
|
||||
@ -252,12 +252,12 @@
|
||||
- @types/react
|
||||
- typescript
|
||||
- vitest
|
||||
- @types/passport-jwt
|
||||
- @types/supertest
|
||||
- bcryptjs
|
||||
- helmet
|
||||
- ts-loader
|
||||
- typescript
|
||||
- js-yaml
|
||||
- @types/bcrypt
|
||||
- RedisService
|
||||
- @nestjs/jwt
|
||||
- blog.entity.ts
|
||||
- home.entity.ts
|
||||
- wiki.entity.ts
|
||||
@ -290,11 +290,26 @@
|
||||
- Shabnam Font Sample
|
||||
- Production Docker Compose
|
||||
- Staging Docker Compose
|
||||
- @nestjs/swagger
|
||||
- NetworkBanner.tsx
|
||||
- @nestjs/throttler
|
||||
- passport-jwt
|
||||
- @prisma/client
|
||||
- reflect-metadata
|
||||
- swagger-ui-express
|
||||
- @eslint/eslintrc
|
||||
- @types/react-dom
|
||||
- eslint-config-prettier
|
||||
- @eslint/js
|
||||
- jest
|
||||
- @nestjs/schematics
|
||||
- @nestjs/testing
|
||||
- source-map-support
|
||||
- ts-jest
|
||||
- RouteErrorBoundary
|
||||
- AdminLoginDto
|
||||
- tsconfig-paths
|
||||
- @types/bcryptjs
|
||||
- typescript-eslint
|
||||
- eslint-config-next
|
||||
- tailwindcss
|
||||
|
||||
## God Nodes (most connected - your core abstractions)
|
||||
@ -302,8 +317,8 @@
|
||||
2. `Roles()` - 75 edges
|
||||
3. `useSettingsStore` - 47 edges
|
||||
4. `SmsService` - 42 edges
|
||||
5. `PaginationDto` - 39 edges
|
||||
6. `api` - 38 edges
|
||||
5. `api` - 40 edges
|
||||
6. `PaginationDto` - 39 edges
|
||||
7. `AdminService` - 34 edges
|
||||
8. `AdminController` - 33 edges
|
||||
9. `JwtAuthGuard` - 32 edges
|
||||
@ -330,11 +345,11 @@
|
||||
- **Rastikerdar Font Ecosystem** — frontend_application_public_fonts_shabnam_font_v5_0_1_readme, frontend_application_public_fonts_vazirmatn_v33_003_readme, vazir_font [EXTRACTED 0.95]
|
||||
- **Canina Deployment Stack** — scripts_compose_prod, scripts_compose_stage [EXTRACTED 1.00]
|
||||
|
||||
## Communities (296 total, 102 thin omitted)
|
||||
## Communities (311 total, 116 thin omitted)
|
||||
|
||||
### Community 0 - "OrdersService"
|
||||
Cohesion: 0.06
|
||||
Nodes (35): CreateOrderDto, OrderItemDto, ApiProperty, ApiPropertyOptional, IsArray, IsNotEmpty, IsNumber, IsOptional (+27 more)
|
||||
Cohesion: 0.07
|
||||
Nodes (29): CreateOrderDto, OrderItemDto, ApiProperty, ApiPropertyOptional, IsArray, IsNotEmpty, IsNumber, IsOptional (+21 more)
|
||||
|
||||
### Community 1 - "productService.ts"
|
||||
Cohesion: 0.06
|
||||
@ -345,28 +360,28 @@ Cohesion: 0.09
|
||||
Nodes (24): CmsController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+16 more)
|
||||
|
||||
### Community 3 - "app.module.ts"
|
||||
Cohesion: 0.08
|
||||
Nodes (30): B2BModule, Module, BannersModule, Module, CmsModule, Module, SmsModule, Global (+22 more)
|
||||
|
||||
### Community 4 - "reviews.controller.ts"
|
||||
Cohesion: 0.07
|
||||
Nodes (31): CreateReviewDto, ApiProperty, IsInt, IsNotEmpty, IsOptional, IsString, Min, ApiProperty (+23 more)
|
||||
Nodes (36): B2BModule, Module, BannersModule, Module, CmsModule, Module, SmsModule, Global (+28 more)
|
||||
|
||||
### Community 4 - "CreateReviewDto"
|
||||
Cohesion: 0.07
|
||||
Nodes (29): CreateReviewDto, ApiProperty, IsInt, IsNotEmpty, IsOptional, IsString, Min, ApiProperty (+21 more)
|
||||
|
||||
### Community 5 - "tickets.controller.ts"
|
||||
Cohesion: 0.09
|
||||
Nodes (31): AdminUpdateTicketDto, CreateTicketDto, ReplyTicketDto, ApiProperty, ApiPropertyOptional, IsNotEmpty, IsOptional, IsString (+23 more)
|
||||
Nodes (29): AdminUpdateTicketDto, CreateTicketDto, ReplyTicketDto, ApiProperty, ApiPropertyOptional, IsNotEmpty, IsOptional, IsString (+21 more)
|
||||
|
||||
### Community 6 - "UserDashboard.tsx"
|
||||
Cohesion: 0.09
|
||||
Nodes (28): VerifyContent(), AddressModal(), AddressModalProps, BackButton(), BackButtonProps, DeleteConfirmModal(), DeleteConfirmModalProps, HeaderButton() (+20 more)
|
||||
|
||||
### Community 7 - "Spinner.tsx"
|
||||
Cohesion: 0.11
|
||||
Nodes (21): ConfirmModal(), ConfirmModalProps, getFileType(), Media, MediaSelector(), MediaSelectorProps, Pagination(), PaginationProps (+13 more)
|
||||
### Community 7 - "MediaSelector.tsx"
|
||||
Cohesion: 0.07
|
||||
Nodes (27): ConfirmModal(), ConfirmModalProps, getFileType(), Media, MediaSelector(), MediaSelectorProps, BlogPost, Category (+19 more)
|
||||
|
||||
### Community 8 - "admin.module.ts"
|
||||
Cohesion: 0.06
|
||||
Nodes (21): AdminModule, Module, PetQuery, PetsService, Injectable, ReportsController, ApiBearerAuth, ApiOperation (+13 more)
|
||||
Cohesion: 0.07
|
||||
Nodes (20): AdminModule, Module, BlogQuery, BlogsService, Injectable, MediaService, Injectable, ReportsController (+12 more)
|
||||
|
||||
### Community 9 - "PetProfile.tsx"
|
||||
Cohesion: 0.14
|
||||
@ -381,16 +396,16 @@ Cohesion: 0.14
|
||||
Nodes (14): metadata, BrandLogo(), BrandLogoProps, EnamadBadge(), Footer(), Hero(), StatCounter(), MaintenancePage() (+6 more)
|
||||
|
||||
### Community 12 - "adminRoutes.tsx"
|
||||
Cohesion: 0.05
|
||||
Nodes (29): App(), HeroBanner, VetTestimonial, ContactInfoItem, ContactSubmission, CategoryDist, DashboardData, SslStatus (+21 more)
|
||||
Cohesion: 0.09
|
||||
Nodes (16): App(), HeroBanner, VetTestimonial, ContactInfoItem, ContactSubmission, CategoryDist, DashboardData, Ticket (+8 more)
|
||||
|
||||
### Community 13 - "PrismaService"
|
||||
Cohesion: 0.07
|
||||
Nodes (19): ApiExcludeController, CategoryQuery, MetricsController, Controller, Get, Res, MeliPayamakPattern, MeliPayamakResponse (+11 more)
|
||||
Cohesion: 0.08
|
||||
Nodes (15): B2BWholesaleOrderItem, MeliPayamakPattern, MeliPayamakResponse, SendPatternSmsOptions, SmsConfig, SmsLogQuery, CreateContactSubmissionDto, UpdateContactInfoItemDto (+7 more)
|
||||
|
||||
### Community 14 - "pets/pets.controller.ts"
|
||||
Cohesion: 0.11
|
||||
Nodes (19): CreatePetDto, ApiProperty, ApiPropertyOptional, IsArray, IsNotEmpty, IsNumber, IsOptional, IsString (+11 more)
|
||||
Cohesion: 0.16
|
||||
Nodes (13): CreatePetDto, ApiProperty, ApiPropertyOptional, IsArray, IsNotEmpty, IsNumber, IsOptional, IsString (+5 more)
|
||||
|
||||
### Community 15 - "ProductsService"
|
||||
Cohesion: 0.09
|
||||
@ -401,24 +416,24 @@ Cohesion: 0.06
|
||||
Nodes (18): metadata, ContactFormClient(), ContactInfoItem, Testimonial, TestimonialsSection(), api, ApiErrorPayload, BASE_DOMAIN (+10 more)
|
||||
|
||||
### Community 17 - "CreateVideoDto"
|
||||
Cohesion: 0.07
|
||||
Nodes (32): CreateVideoDto, ApiProperty, ApiPropertyOptional, IsBoolean, IsNotEmpty, IsOptional, IsString, UpdateVideoDto (+24 more)
|
||||
Cohesion: 0.09
|
||||
Nodes (24): CreateVideoDto, ApiProperty, ApiPropertyOptional, IsBoolean, IsNotEmpty, IsOptional, IsString, UpdateVideoDto (+16 more)
|
||||
|
||||
### Community 18 - "src/services/api.ts"
|
||||
Cohesion: 0.09
|
||||
Nodes (25): ProtectedRoute(), Login(), B2BManager, SeoSettingsPage, SmartAdvisorManager, SystemSettingsPage, ApiErrorPayload, failedQueue (+17 more)
|
||||
Cohesion: 0.10
|
||||
Nodes (23): ProtectedRoute(), SEARCHABLE_PAGES, Topbar(), TopbarProps, Login(), B2BManager, SmartAdvisorManager, SystemSettingsPage (+15 more)
|
||||
|
||||
### Community 19 - "auth.service.ts"
|
||||
Cohesion: 0.15
|
||||
Nodes (14): AdminLoginInput, LoginInput, RegisterInput, SendOtpDto, ApiProperty, IsNotEmpty, IsString, Matches (+6 more)
|
||||
Cohesion: 0.08
|
||||
Nodes (25): AdminLoginInput, LoginInput, RegisterInput, AdminLoginDto, ApiProperty, IsEmail, IsNotEmpty, IsString (+17 more)
|
||||
|
||||
### Community 20 - "BE-001"
|
||||
Cohesion: 0.06
|
||||
Nodes (32): Acceptance Criteria, Affected Application, Affected Files, Alternative Direction, BE-001, Category, Completion Statement, Confidence (+24 more)
|
||||
|
||||
### Community 21 - "Roles"
|
||||
Cohesion: 0.20
|
||||
Nodes (15): Roles(), SettingsController, ApiBearerAuth, ApiOkResponse, ApiOperation, ApiTags, Body, Controller (+7 more)
|
||||
Cohesion: 0.25
|
||||
Nodes (10): Roles(), ApiBearerAuth, ApiOperation, Body, Delete, Param, Patch, Post (+2 more)
|
||||
|
||||
### Community 22 - "FE-001"
|
||||
Cohesion: 0.06
|
||||
@ -448,20 +463,20 @@ Nodes (31): Acceptance Criteria, Affected Application, Affected Files, Alternati
|
||||
Cohesion: 0.06
|
||||
Nodes (31): Acceptance Criteria, Affected Application, Affected Files, Alternative Direction, Category, Completion Statement, Confidence, Dependencies (+23 more)
|
||||
|
||||
### Community 29 - "WholesaleService"
|
||||
Cohesion: 0.14
|
||||
Nodes (14): ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Get, Param, Post (+6 more)
|
||||
### Community 29 - "WholesaleApplyDto"
|
||||
Cohesion: 0.10
|
||||
Nodes (20): ApiProperty, ApiPropertyOptional, IsNotEmpty, IsOptional, IsString, WholesaleApplyDto, ApiBearerAuth, ApiOperation (+12 more)
|
||||
|
||||
### Community 30 - "main.ts"
|
||||
Cohesion: 0.11
|
||||
Nodes (11): AppModule, Module, CustomHttpExceptionFilter, Catch, PrismaExceptionFilter, Catch, DecimalInterceptor, Injectable (+3 more)
|
||||
|
||||
### Community 31 - "JwtAuthGuard"
|
||||
Cohesion: 0.15
|
||||
Nodes (9): JwtAuthGuard, Injectable, B2BWholesaleOrderItem, ROLES_KEY, SortOrder, RequestWithUser, RolesGuard, Injectable (+1 more)
|
||||
Cohesion: 0.18
|
||||
Nodes (7): JwtAuthGuard, Injectable, ROLES_KEY, RequestWithUser, RolesGuard, Injectable, UserReqPayload
|
||||
|
||||
### Community 32 - "ZibalService"
|
||||
Cohesion: 0.15
|
||||
Cohesion: 0.14
|
||||
Nodes (4): PaymentService, Injectable, Injectable, ZibalService
|
||||
|
||||
### Community 33 - "راهنمای تست سیستم (Software Testing)"
|
||||
@ -469,8 +484,8 @@ Cohesion: 0.07
|
||||
Nodes (25): اجرای بکاند, اجرای فرانتاند, اجرای پروژه در سرور با PM2, برای راهاندازی بکاند:, برای راهاندازی فرانتاند Next.js:, بیلد کردن پروژه (Building), ذخیره پروسهها تا پس از ریاستارت سرور قطع نشوند:, راهاندازی و انتشار سیستم (Setup & Deployment) (+17 more)
|
||||
|
||||
### Community 34 - "CategoriesController"
|
||||
Cohesion: 0.10
|
||||
Nodes (16): CategoriesController, ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Body, Controller, Delete (+8 more)
|
||||
Cohesion: 0.09
|
||||
Nodes (17): CategoriesController, ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Body, Controller, Delete (+9 more)
|
||||
|
||||
### Community 35 - "B2BService"
|
||||
Cohesion: 0.14
|
||||
@ -485,8 +500,8 @@ Cohesion: 0.09
|
||||
Nodes (32): ClientLayout(), ArchiveProductCard(), AuthModal(), AuthModalProps, extractOtpFromText(), B2BPortal(), CartDrawer(), CheckoutPage() (+24 more)
|
||||
|
||||
### Community 38 - "UsersService"
|
||||
Cohesion: 0.05
|
||||
Nodes (42): DEFAULT_JWT_REFRESH_SECRET, DEFAULT_JWT_SECRET, getJwtSecret(), AuthModule, Module, JwtPayload, JwtStrategy, Injectable (+34 more)
|
||||
Cohesion: 0.06
|
||||
Nodes (41): DEFAULT_JWT_REFRESH_SECRET, DEFAULT_JWT_SECRET, getJwtSecret(), AuthModule, Module, JwtPayload, JwtStrategy, Injectable (+33 more)
|
||||
|
||||
### Community 39 - "What You Must Do When Invoked"
|
||||
Cohesion: 0.07
|
||||
@ -504,17 +519,17 @@ Nodes (3): PLAYBACK_RATES, PodcastPlayerModal(), PodcastPlayerModalProps
|
||||
Cohesion: 0.13
|
||||
Nodes (14): IngredientsController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+6 more)
|
||||
|
||||
### Community 43 - "AuthService"
|
||||
Cohesion: 0.22
|
||||
Nodes (3): AuthService, Injectable, normalizeMobile()
|
||||
### Community 43 - "RedisService"
|
||||
Cohesion: 0.09
|
||||
Nodes (6): AuthService, Injectable, normalizeMobile(), RedisService, Injectable, UserAddressInput
|
||||
|
||||
### Community 44 - "MediaController"
|
||||
Cohesion: 0.11
|
||||
Nodes (16): MediaController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+8 more)
|
||||
Nodes (14): MediaController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+6 more)
|
||||
|
||||
### Community 45 - "Transactions.tsx"
|
||||
Cohesion: 0.33
|
||||
Nodes (4): GatewayHealth, Stats, Transaction, Transactions
|
||||
### Community 45 - "Pagination.tsx"
|
||||
Cohesion: 0.13
|
||||
Nodes (11): Pagination(), PaginationProps, Pet, GatewayHealth, Stats, Transaction, ProductItem, WikiTerm (+3 more)
|
||||
|
||||
### Community 48 - "PrescriptionsService"
|
||||
Cohesion: 0.14
|
||||
@ -545,24 +560,24 @@ Cohesion: 0.06
|
||||
Nodes (31): compilerOptions, allowSyntheticDefaultImports, baseUrl, declaration, emitDecoratorMetadata, esModuleInterop, experimentalDecorators, forceConsistentCasingInFileNames (+23 more)
|
||||
|
||||
### Community 55 - "Media.tsx"
|
||||
Cohesion: 0.09
|
||||
Nodes (20): Badge(), BadgeProps, BadgeVariant, variantStyles, ImagePreviewModal(), ImagePreviewModalProps, ToggleSwitch(), ToggleSwitchProps (+12 more)
|
||||
Cohesion: 0.14
|
||||
Nodes (13): Badge(), BadgeProps, BadgeVariant, variantStyles, ImagePreviewModal(), ImagePreviewModalProps, getFileType(), Media (+5 more)
|
||||
|
||||
### Community 56 - "compilerOptions"
|
||||
Cohesion: 0.08
|
||||
Nodes (23): compilerOptions, allowImportingTsExtensions, erasableSyntaxOnly, jsx, lib, module, moduleDetection, moduleResolution (+15 more)
|
||||
|
||||
### Community 57 - "PetsController"
|
||||
Cohesion: 0.15
|
||||
Nodes (11): PetsController, ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Controller, Delete, Get (+3 more)
|
||||
Cohesion: 0.10
|
||||
Nodes (14): PetsController, ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Controller, Delete, Get (+6 more)
|
||||
|
||||
### Community 58 - "PaginationDto"
|
||||
Cohesion: 0.09
|
||||
Nodes (21): BlogsController, ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiTags, Controller, Get, Param (+13 more)
|
||||
Cohesion: 0.06
|
||||
Nodes (31): BlogsController, ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiTags, Controller, Get, Param (+23 more)
|
||||
|
||||
### Community 59 - "dependencies"
|
||||
Cohesion: 0.05
|
||||
Nodes (41): dependencies, bcrypt, bcryptjs, class-transformer, class-validator, helmet, ioredis, js-yaml (+33 more)
|
||||
Cohesion: 0.10
|
||||
Nodes (21): dependencies, bcrypt, class-transformer, class-validator, ioredis, @nestjs/common, @nestjs/core, @nestjs/passport (+13 more)
|
||||
|
||||
### Community 60 - "compilerOptions"
|
||||
Cohesion: 0.10
|
||||
@ -576,10 +591,6 @@ Nodes (20): HomeClient(), HomeClientProps, getHomeData(), Home(), metadata, meta
|
||||
Cohesion: 0.13
|
||||
Nodes (15): BlogsController, ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Body, Controller, Delete (+7 more)
|
||||
|
||||
### Community 63 - "SettingsService"
|
||||
Cohesion: 0.12
|
||||
Nodes (3): SmsLogQuery, SettingsService, Injectable
|
||||
|
||||
### Community 64 - "BannersService"
|
||||
Cohesion: 0.13
|
||||
Nodes (15): BannersController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+7 more)
|
||||
@ -604,21 +615,21 @@ Nodes (18): 1. Framework-Aware Analysis, 2. DOM & Semantic Structure Analysis, 3
|
||||
Cohesion: 0.13
|
||||
Nodes (14): ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Body, Controller, Delete, Get (+6 more)
|
||||
|
||||
### Community 70 - "ApiOperation"
|
||||
Cohesion: 0.14
|
||||
Nodes (8): ApiOperation, ApiQuery, Get, Query, AdminQueryDto, ApiPropertyOptional, IsOptional, IsString
|
||||
### Community 70 - "AdminQueryDto"
|
||||
Cohesion: 0.20
|
||||
Nodes (7): ApiQuery, Get, Query, AdminQueryDto, ApiPropertyOptional, IsOptional, IsString
|
||||
|
||||
### Community 71 - "PetsController"
|
||||
Cohesion: 0.14
|
||||
Nodes (20): PetsController, ApiBadRequestResponse, ApiBearerAuth, ApiCreatedResponse, ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiTags (+12 more)
|
||||
### Community 71 - ".update"
|
||||
Cohesion: 0.24
|
||||
Nodes (11): ApiNotFoundResponse, ApiOkResponse, ApiOperation, Body, Delete, Get, Param, Patch (+3 more)
|
||||
|
||||
### Community 72 - "seo.module.ts"
|
||||
Cohesion: 0.16
|
||||
Nodes (10): SeoController, ApiOperation, ApiTags, Controller, Get, Param, SeoModule, Module (+2 more)
|
||||
|
||||
### Community 73 - "admin.service.ts"
|
||||
Cohesion: 0.18
|
||||
Nodes (13): CouponInput, CouponTargetInput, PaginationQuery, CreateUserDto, ApiProperty, ApiPropertyOptional, IsEmail, IsNotEmpty (+5 more)
|
||||
Cohesion: 0.13
|
||||
Nodes (21): CouponInput, CouponTargetInput, PaginationQuery, ProductDto, ApiPropertyOptional, IsArray, IsBoolean, IsNumber (+13 more)
|
||||
|
||||
### Community 74 - "🏢 AI Software Agency — Master Orchestration Protocol v3"
|
||||
Cohesion: 0.11
|
||||
@ -650,11 +661,11 @@ Nodes (9): GatewayHealthResult, IPaymentGateway, PaymentInquiryResult, PaymentRe
|
||||
|
||||
### Community 81 - "devDependencies"
|
||||
Cohesion: 0.13
|
||||
Nodes (15): eslint-config-next, devDependencies, eslint, eslint-config-next, jsdom, tailwindcss, @tailwindcss/postcss, @types/node (+7 more)
|
||||
Nodes (15): devDependencies, eslint, jsdom, tailwindcss, @tailwindcss/postcss, @types/node, @types/react-dom, @vitejs/plugin-react (+7 more)
|
||||
|
||||
### Community 82 - "api"
|
||||
Cohesion: 0.15
|
||||
Nodes (13): Layout(), MenuGroup, Sidebar(), SidebarProps, SubMenuItem, SEARCHABLE_PAGES, Topbar(), TopbarProps (+5 more)
|
||||
Cohesion: 0.29
|
||||
Nodes (6): Layout(), MenuGroup, Sidebar(), SidebarProps, SubMenuItem, api
|
||||
|
||||
### Community 83 - "Orders.tsx"
|
||||
Cohesion: 0.14
|
||||
@ -716,9 +727,9 @@ Nodes (8): exclude, extends, dist, node_modules, prisma, **/*spec.ts, test, ./ts
|
||||
Cohesion: 0.15
|
||||
Nodes (13): jest, collectCoverageFrom, coverageDirectory, moduleFileExtensions, rootDir, testEnvironment, testRegex, transform (+5 more)
|
||||
|
||||
### Community 98 - "AdminController"
|
||||
Cohesion: 0.12
|
||||
Nodes (8): AdminController, ApiBearerAuth, ApiTags, Controller, Delete, Param, Put, UseGuards
|
||||
### Community 98 - "AdminService"
|
||||
Cohesion: 0.09
|
||||
Nodes (13): AdminController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Param (+5 more)
|
||||
|
||||
### Community 99 - "Comprehensive Change Log"
|
||||
Cohesion: 0.15
|
||||
@ -728,9 +739,13 @@ Nodes (12): 10. `TASK-VERIFY-001`, 1. `TASK-SEC-001`, 2. `TASK-SEC-002`, 3. `TAS
|
||||
Cohesion: 0.17
|
||||
Nodes (11): 1. Detect Test Runner from Tech Stack, 2. Execution Output Capture (Mandatory), 3. Acceptance Criteria Verification, 4. Failure Routing Protocol, 5. Success Routing Protocol, 6. Forbidden Actions, Expected JSON Output Schema, Operational Rules & Boundaries (+3 more)
|
||||
|
||||
### Community 103 - "ProductDto"
|
||||
Cohesion: 0.22
|
||||
Nodes (7): ProductDto, ApiPropertyOptional, IsArray, IsBoolean, IsNumber, IsOptional, IsString
|
||||
### Community 101 - "UITexts.tsx"
|
||||
Cohesion: 0.10
|
||||
Nodes (18): ICON_REGISTRY, IconPickerModal(), IconPickerModalProps, COLORS, RichTextEditor(), RichTextEditorProps, ToggleSwitch(), ToggleSwitchProps (+10 more)
|
||||
|
||||
### Community 103 - "SettingsController"
|
||||
Cohesion: 0.21
|
||||
Nodes (6): SettingsController, ApiOkResponse, ApiTags, Controller, Get, Query
|
||||
|
||||
### Community 104 - "AuthController"
|
||||
Cohesion: 0.27
|
||||
@ -740,6 +755,10 @@ Nodes (12): AuthController, ApiBadRequestResponse, ApiBearerAuth, ApiOkResponse,
|
||||
Cohesion: 0.17
|
||||
Nodes (11): 1.1 Authoritative Source File Inventory Rebuilt, 1.2 Raw Finding Dispositions Reconciled, 1.3 Finding Identifier Normalization, 1.4 Rejected Finding Cleanup, 1. Summary of Integrity Repairs Performed, 2. Final Verified Finding Metrics, 3. Reference and Compiler Integrity Results, 4. Quality Gate Conclusion (+3 more)
|
||||
|
||||
### Community 106 - "orders.service.ts"
|
||||
Cohesion: 0.24
|
||||
Nodes (6): IsNotEmpty, IsNumber, IsString, ValidateCouponDto, OrdersModule, Module
|
||||
|
||||
### Community 107 - "Operational Rules & Boundaries"
|
||||
Cohesion: 0.18
|
||||
Nodes (10): 1. Detect Tech Stack First (Universal), 2. Explicit Scoring Methodology (Universal), 3. Code Coverage Ratio Rule, 4. Deep Directory Scanning, 5. Forbidden Actions, Expected JSON Output Schema, Operational Rules & Boundaries, Required Output Artifacts (What files to write/update) (+2 more)
|
||||
@ -760,9 +779,9 @@ Nodes (5): AppController, Controller, Get, AppService, Injectable
|
||||
Cohesion: 0.25
|
||||
Nodes (7): SmsLogQueryDto, ApiPropertyOptional, IsIn, IsNumber, IsOptional, IsString, Type
|
||||
|
||||
### Community 112 - "BlogsService"
|
||||
Cohesion: 0.22
|
||||
Nodes (3): BlogQuery, BlogsService, Injectable
|
||||
### Community 112 - "PetsController"
|
||||
Cohesion: 0.18
|
||||
Nodes (9): PetsController, ApiBadRequestResponse, ApiBearerAuth, ApiCreatedResponse, ApiTags, Controller, UploadedFile, UseGuards (+1 more)
|
||||
|
||||
### Community 113 - "Vazirmatn Changelog"
|
||||
Cohesion: 0.18
|
||||
@ -788,10 +807,6 @@ Nodes (9): compilerOptions, esModuleInterop, module, moduleResolution, skipLibCh
|
||||
Cohesion: 0.20
|
||||
Nodes (9): Compile and run the project, Deployment, Description, License, Project setup, Resources, Run tests, Stay in touch (+1 more)
|
||||
|
||||
### Community 119 - "devDependencies"
|
||||
Cohesion: 0.09
|
||||
Nodes (23): devDependencies, eslint, eslint-config-prettier, @eslint/js, jest, @nestjs/schematics, @nestjs/testing, source-map-support (+15 more)
|
||||
|
||||
### Community 120 - "Repository Map"
|
||||
Cohesion: 0.20
|
||||
Nodes (9): 1. Active Customer Storefront: React 19 + Vite Application, 2. Active Backend Service: NestJS Application, 3. Excluded Placeholder / Non-Auditable Directories, Active Applications & Non-Auditable Scopes, Documentation Governance, Important Configuration & Infrastructure Files, Mandatory Global Audit Exclusions, Repository Map (+1 more)
|
||||
@ -808,9 +823,9 @@ Nodes (9): name, private, scripts, build, dev, lint, preview, type (+1 more)
|
||||
Cohesion: 0.20
|
||||
Nodes (9): Arch Linux, Contributors, Install, Known problems for variable version, License, Sahel-Font, To Do (variable), طریقه استفاده از نسخه متغیر variable (+1 more)
|
||||
|
||||
### Community 124 - "Reports.tsx"
|
||||
Cohesion: 0.20
|
||||
Nodes (7): BestSellerItem, CategoryDistItem, COLORS, CustomTooltipProps, ReportData, TopCouponItem, Reports
|
||||
### Community 124 - "Spinner.tsx"
|
||||
Cohesion: 0.08
|
||||
Nodes (18): Spinner(), BestSellerItem, CategoryDistItem, COLORS, CustomTooltipProps, ReportData, TopCouponItem, ProductReview (+10 more)
|
||||
|
||||
### Community 125 - "Sahel-Font"
|
||||
Cohesion: 0.20
|
||||
@ -828,9 +843,9 @@ Nodes (8): cmd_next_task(), cmd_progress(), cmd_reset(), cmd_status(), cmd_unblo
|
||||
Cohesion: 0.22
|
||||
Nodes (8): author, description, license, name, prisma, seed, private, version
|
||||
|
||||
### Community 129 - "wholesale.controller.ts"
|
||||
Cohesion: 0.31
|
||||
Nodes (6): ApiProperty, ApiPropertyOptional, IsNotEmpty, IsOptional, IsString, WholesaleApplyDto
|
||||
### Community 129 - "WikiService"
|
||||
Cohesion: 0.22
|
||||
Nodes (3): Injectable, WikiQuery, WikiService
|
||||
|
||||
### Community 130 - "graphify reference: extra exports and benchmark"
|
||||
Cohesion: 0.22
|
||||
@ -877,8 +892,12 @@ Cohesion: 0.29
|
||||
Nodes (6): 1. Executive Vision, 2. Target Audience, 3. Functional Requirements, 4. Non-Functional Requirements (Performance, Security), 5. Epic / Feature Breakdown, Product Requirement Document (PRD)
|
||||
|
||||
### Community 141 - "WikiController"
|
||||
Cohesion: 0.13
|
||||
Nodes (13): ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiTags, Controller, Get, Param, Query (+5 more)
|
||||
Cohesion: 0.21
|
||||
Nodes (9): ApiNotFoundResponse, ApiOkResponse, ApiOperation, ApiTags, Controller, Get, Param, Query (+1 more)
|
||||
|
||||
### Community 142 - "devDependencies"
|
||||
Cohesion: 0.22
|
||||
Nodes (9): devDependencies, globals, @types/passport-jwt, @types/supertest, typescript, globals, typescript, @types/passport-jwt (+1 more)
|
||||
|
||||
### Community 144 - "Baseline Command Plan & Reconciled Command History"
|
||||
Cohesion: 0.29
|
||||
@ -1028,9 +1047,13 @@ Nodes (3): ADR-AUTH-001: Admin Panel Authentication Architecture & Token Managem
|
||||
Cohesion: 0.29
|
||||
Nodes (6): CreateHealthLogDto, ApiProperty, ApiPropertyOptional, IsNotEmpty, IsOptional, IsString
|
||||
|
||||
### Community 214 - "LoginDto"
|
||||
Cohesion: 0.33
|
||||
Nodes (5): LoginDto, ApiProperty, IsNotEmpty, IsString, MinLength
|
||||
### Community 214 - "MetricsController"
|
||||
Cohesion: 0.29
|
||||
Nodes (5): ApiExcludeController, MetricsController, Controller, Get, Res
|
||||
|
||||
### Community 215 - "CreateReminderDto"
|
||||
Cohesion: 0.29
|
||||
Nodes (6): CreateReminderDto, ApiProperty, ApiPropertyOptional, IsNotEmpty, IsOptional, IsString
|
||||
|
||||
### Community 223 - "Shabnam Font README"
|
||||
Cohesion: 0.67
|
||||
@ -1044,28 +1067,24 @@ Nodes (8): RegisterDto, ApiProperty, ApiPropertyOptional, IsEmail, IsNotEmpty, I
|
||||
Cohesion: 0.22
|
||||
Nodes (3): Props, RouteErrorBoundary, State
|
||||
|
||||
### Community 307 - "AdminLoginDto"
|
||||
Cohesion: 0.29
|
||||
Nodes (6): AdminLoginDto, ApiProperty, IsEmail, IsNotEmpty, IsString, MinLength
|
||||
|
||||
## Knowledge Gaps
|
||||
- **1242 isolated node(s):** `$schema`, `collection`, `sourceRoot`, `deleteOutDir`, `name` (+1237 more)
|
||||
- **1250 isolated node(s):** `$schema`, `collection`, `sourceRoot`, `deleteOutDir`, `name` (+1245 more)
|
||||
These have ≤1 connection - possible missing edges or undocumented components.
|
||||
- **102 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
||||
- **116 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
||||
|
||||
## Suggested Questions
|
||||
_Questions this graph is uniquely positioned to answer:_
|
||||
|
||||
- **Why does `Roles()` connect `Roles` to `BannersService`, `wholesale.controller.ts`, `CmsController`, `B2BService`, `reviews.controller.ts`, `tickets.controller.ts`, `SslController`, `IngredientsService`, `ProductsService`, `PrescriptionsService`, `SmartAdvisorService`, `TestimonialsService`, `ContactService`, `PaymentController`, `.addPattern`, `WholesaleService`, `JwtAuthGuard`?**
|
||||
- **Why does `Roles()` connect `Roles` to `BannersService`, `CmsController`, `B2BService`, `CreateReviewDto`, `tickets.controller.ts`, `SettingsController`, `SslController`, `IngredientsService`, `ProductsService`, `PrescriptionsService`, `SmartAdvisorService`, `TestimonialsService`, `ContactService`, `PaymentController`, `WholesaleApplyDto`, `JwtAuthGuard`?**
|
||||
_High betweenness centrality (0.051) - this node is a cross-community bridge._
|
||||
- **Why does `ApiResponse` connect `src/services/api.ts` to `OrdersService`, `UsersService`, `PetsController`, `AuthController`, `WikiController`, `HomeController`, `ProductsService`, `PaginationDto`?**
|
||||
_High betweenness centrality (0.040) - this node is a cross-community bridge._
|
||||
- **Why does `JwtAuthGuard` connect `JwtAuthGuard` to `OrdersService`, `wholesale.controller.ts`, `CmsController`, `reviews.controller.ts`, `tickets.controller.ts`, `UsersService`, `admin.module.ts`, `admin.service.ts`, `MediaController`, `PrismaService`, `pets/pets.controller.ts`, `ProductsService`, `CreateVideoDto`, `auth.service.ts`?**
|
||||
- **Why does `ApiResponse` connect `src/services/api.ts` to `OrdersService`, `UsersService`, `AuthController`, `WikiController`, `HomeController`, `PetsController`, `ProductsService`, `PaginationDto`?**
|
||||
_High betweenness centrality (0.042) - this node is a cross-community bridge._
|
||||
- **Why does `JwtAuthGuard` connect `JwtAuthGuard` to `WikiService`, `CategoriesController`, `CmsController`, `tickets.controller.ts`, `UsersService`, `admin.module.ts`, `admin.service.ts`, `orders.service.ts`, `PrismaService`, `pets/pets.controller.ts`, `auth.service.ts`, `PetsController`, `PaginationDto`?**
|
||||
_High betweenness centrality (0.024) - this node is a cross-community bridge._
|
||||
- **What connects `$schema`, `collection`, `sourceRoot` to the rest of the system?**
|
||||
_1242 weakly-connected nodes found - possible documentation gaps or missing edges._
|
||||
_1250 weakly-connected nodes found - possible documentation gaps or missing edges._
|
||||
- **Should `OrdersService` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.06168831168831169 - nodes in this community are weakly interconnected._
|
||||
_Cohesion score 0.07171717171717172 - nodes in this community are weakly interconnected._
|
||||
- **Should `productService.ts` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.05888376856118792 - nodes in this community are weakly interconnected._
|
||||
- **Should `CmsController` be split into smaller, more focused modules?**
|
||||
|
||||
1
graphify-out/cache/last_query_stamp
vendored
Normal file
1
graphify-out/cache/last_query_stamp
vendored
Normal file
@ -0,0 +1 @@
|
||||
1787069487.057531
|
||||
2
graphify-out/cache/stat-index.json
vendored
2
graphify-out/cache/stat-index.json
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user