feat: complete product management with dynamic FAQs, PAO, storage conditions, safety guidelines and key highlights
This commit is contained in:
parent
ddd0dcbab6
commit
101611d8a7
@ -442,6 +442,20 @@ export class AdminService {
|
||||
const marginWholesale =
|
||||
data.marginWholesalePercent ?? data.wholesaleMarginPercent;
|
||||
|
||||
const dosageConfigData: Record<string, any> = {
|
||||
...(data.dosageConfig || {}),
|
||||
...(data.feedingAdvice !== undefined ? { feedingAdvice: data.feedingAdvice } : {}),
|
||||
...(data.showFaqs !== undefined ? { showFaqs: data.showFaqs } : {}),
|
||||
...(data.faqs !== undefined ? { faqs: data.faqs } : {}),
|
||||
...(data.paoMonths !== undefined ? { paoMonths: data.paoMonths } : {}),
|
||||
...(data.storageInfo !== undefined ? { storageInfo: data.storageInfo } : {}),
|
||||
...(data.precautions !== undefined ? { precautions: data.precautions } : {}),
|
||||
...(data.lifeStage !== undefined ? { lifeStage: data.lifeStage } : {}),
|
||||
...(data.keyHighlights !== undefined ? { keyHighlights: data.keyHighlights } : {}),
|
||||
...(data.isPreorder !== undefined ? { isPreorder: data.isPreorder } : {}),
|
||||
...(data.preorderDeposit !== undefined ? { preorderDeposit: data.preorderDeposit } : {}),
|
||||
};
|
||||
|
||||
const product = await this.prisma.product.create({
|
||||
data: {
|
||||
artNo: data.artNo || `ART-${Date.now()}`,
|
||||
@ -474,6 +488,7 @@ export class AdminService {
|
||||
unit: data.unit || 'عدد',
|
||||
packageSize: data.packageSize || 100,
|
||||
dosageLogic: data.dosageLogic || '',
|
||||
dosageConfig: Object.keys(dosageConfigData).length > 0 ? dosageConfigData : undefined,
|
||||
suitableFor: data.suitableFor || 'سگ',
|
||||
imageUrl: data.imageUrl || '',
|
||||
images: Array.isArray(data.images)
|
||||
@ -535,6 +550,22 @@ export class AdminService {
|
||||
const marginWholesale =
|
||||
data.marginWholesalePercent ?? data.wholesaleMarginPercent;
|
||||
|
||||
const existingDosageConfig = (existing.dosageConfig as Record<string, any>) || {};
|
||||
const updatedDosageConfig: Record<string, any> = {
|
||||
...existingDosageConfig,
|
||||
...(data.dosageConfig || {}),
|
||||
...(data.feedingAdvice !== undefined ? { feedingAdvice: data.feedingAdvice } : {}),
|
||||
...(data.showFaqs !== undefined ? { showFaqs: data.showFaqs } : {}),
|
||||
...(data.faqs !== undefined ? { faqs: data.faqs } : {}),
|
||||
...(data.paoMonths !== undefined ? { paoMonths: data.paoMonths } : {}),
|
||||
...(data.storageInfo !== undefined ? { storageInfo: data.storageInfo } : {}),
|
||||
...(data.precautions !== undefined ? { precautions: data.precautions } : {}),
|
||||
...(data.lifeStage !== undefined ? { lifeStage: data.lifeStage } : {}),
|
||||
...(data.keyHighlights !== undefined ? { keyHighlights: data.keyHighlights } : {}),
|
||||
...(data.isPreorder !== undefined ? { isPreorder: data.isPreorder } : {}),
|
||||
...(data.preorderDeposit !== undefined ? { preorderDeposit: data.preorderDeposit } : {}),
|
||||
};
|
||||
|
||||
const product = await this.prisma.product.update({
|
||||
where: { id },
|
||||
data: {
|
||||
@ -568,6 +599,7 @@ export class AdminService {
|
||||
unit: data.unit,
|
||||
packageSize: data.packageSize,
|
||||
dosageLogic: data.dosageLogic,
|
||||
dosageConfig: updatedDosageConfig,
|
||||
suitableFor: data.suitableFor,
|
||||
imageUrl: data.imageUrl,
|
||||
images: Array.isArray(data.images)
|
||||
|
||||
@ -264,4 +264,47 @@ export class ProductDto {
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
preorderDeposit?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'دستور مصرف و توصیه بالینی' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
feedingAdvice?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'نمایش بخش سوالات متداول' })
|
||||
@IsOptional()
|
||||
@IsBoolean()
|
||||
showFaqs?: boolean;
|
||||
|
||||
@ApiPropertyOptional({ description: 'پرسش و پاسخهای متداول محصول' })
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
faqs?: Array<{ question: string; answer: string }>;
|
||||
|
||||
@ApiPropertyOptional({ description: 'مدت زمان ماندگاری پس از باز شدن (PAO)' })
|
||||
@IsOptional()
|
||||
paoMonths?: number | string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'شرایط نگهداری استاندارد' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
storageInfo?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'تداخلات و توصیههای احتیاطی' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
precautions?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'رده سنی و شرایط مصرف' })
|
||||
@IsOptional()
|
||||
@IsString()
|
||||
lifeStage?: string;
|
||||
|
||||
@ApiPropertyOptional({ description: 'نکات کلیدی بالای صفحه (Bullet Points)' })
|
||||
@IsOptional()
|
||||
@IsArray()
|
||||
keyHighlights?: string[];
|
||||
|
||||
@ApiPropertyOptional({ description: 'پیکربندی جامع دوز و دادههای تکمیلی' })
|
||||
@IsOptional()
|
||||
dosageConfig?: Record<string, any>;
|
||||
}
|
||||
|
||||
@ -106,6 +106,15 @@ export interface Product {
|
||||
isPreorder?: boolean;
|
||||
preorderDeposit?: string | number;
|
||||
totalSold?: number;
|
||||
feedingAdvice?: string;
|
||||
showFaqs?: boolean;
|
||||
faqs?: Array<{ question: string; answer: string }>;
|
||||
paoMonths?: number | string;
|
||||
storageInfo?: string;
|
||||
precautions?: string;
|
||||
lifeStage?: string;
|
||||
keyHighlights?: string[];
|
||||
dosageConfig?: Record<string, any>;
|
||||
}
|
||||
|
||||
export default function Products() {
|
||||
@ -259,6 +268,14 @@ export default function Products() {
|
||||
pdfTitle: '',
|
||||
pdfDescription: '',
|
||||
pdfCover: '',
|
||||
feedingAdvice: '',
|
||||
showFaqs: true,
|
||||
faqs: [] as Array<{ question: string; answer: string }>,
|
||||
paoMonths: '12' as number | string,
|
||||
storageInfo: '',
|
||||
precautions: '',
|
||||
lifeStage: 'مناسب تمام سنین و دوران بارداری و شیردهی',
|
||||
keyHighlights: ['', '', '', ''] as string[],
|
||||
symptoms: [] as string[],
|
||||
isPreorder: false,
|
||||
preorderDeposit: '' as number | string,
|
||||
@ -392,6 +409,16 @@ export default function Products() {
|
||||
wMargin = Math.round(((Number(wPrice) - Number(bPrice)) / Number(bPrice)) * 100);
|
||||
}
|
||||
|
||||
const dosageConfig = (product.dosageConfig as Record<string, any>) || {};
|
||||
const initialFaqs = dosageConfig.faqs || product.faqs || [];
|
||||
const initialHighlights = dosageConfig.keyHighlights || product.keyHighlights || ['', '', '', ''];
|
||||
const paddedHighlights = [
|
||||
initialHighlights[0] || '',
|
||||
initialHighlights[1] || '',
|
||||
initialHighlights[2] || '',
|
||||
initialHighlights[3] || '',
|
||||
];
|
||||
|
||||
setFormData({
|
||||
artNo: product.artNo || '',
|
||||
nameFa: product.nameFa || '',
|
||||
@ -409,6 +436,14 @@ export default function Products() {
|
||||
unit: product.unit || '',
|
||||
packageSize: product.packageSize !== undefined && product.packageSize !== null ? Number(product.packageSize) : '',
|
||||
dosageLogic: product.dosageLogic || '',
|
||||
feedingAdvice: dosageConfig.feedingAdvice || product.feedingAdvice || product.dosageLogic || '',
|
||||
showFaqs: dosageConfig.showFaqs !== undefined ? Boolean(dosageConfig.showFaqs) : (product.showFaqs !== undefined ? Boolean(product.showFaqs) : true),
|
||||
faqs: Array.isArray(initialFaqs) ? initialFaqs : [],
|
||||
paoMonths: dosageConfig.paoMonths !== undefined ? dosageConfig.paoMonths : (product.paoMonths !== undefined ? product.paoMonths : '12'),
|
||||
storageInfo: dosageConfig.storageInfo || product.storageInfo || '',
|
||||
precautions: dosageConfig.precautions || product.precautions || '',
|
||||
lifeStage: dosageConfig.lifeStage || product.lifeStage || 'مناسب تمام سنین و دوران بارداری و شیردهی',
|
||||
keyHighlights: paddedHighlights,
|
||||
suitableFor: product.suitableFor || 'سگ و گربه',
|
||||
imageUrl: product.imageUrl || '',
|
||||
slug: product.slug || '',
|
||||
@ -450,7 +485,21 @@ export default function Products() {
|
||||
wholesaleMarginPercent: pricingSettings.defaultWholesaleMarginPercent,
|
||||
roundingStep: '',
|
||||
roundingMode: '',
|
||||
priceDisplay: '', unit: '', packageSize: '', dosageLogic: '', suitableFor: 'سگ و گربه',
|
||||
priceDisplay: '', unit: '', packageSize: '', dosageLogic: '',
|
||||
feedingAdvice: '',
|
||||
showFaqs: true,
|
||||
faqs: [],
|
||||
paoMonths: '12',
|
||||
storageInfo: 'در جای خشک، خنک (دمای زیر ۲۵ درجه سانتیگراد) و دور از تابش مستقیم نور خورشید نگهداری شود.',
|
||||
precautions: 'دور از دسترس کودکان نگهداری شود. در صورت مصرف همزمان با سایر پمادها یا اسپریهای درمانی، حداقل ۲۰ دقیقه فاصله زمانی رعایت شود.',
|
||||
lifeStage: 'مناسب تمام سنین و دوران بارداری و شیردهی',
|
||||
keyHighlights: [
|
||||
'۱۰۰٪ فرمولاسیون طبیعی و بدون نگهدارنده مضر',
|
||||
'ایمن و بدون سمیت در صورت لیسیدن محدود',
|
||||
'گرید دارویی و استاندارد صنعتی آلمان (GMP)',
|
||||
'مناسب تمام سنین و دوران بارداری و شیردهی'
|
||||
],
|
||||
suitableFor: 'سگ و گربه',
|
||||
imageUrl: '', metaTitle: '', metaDescription: '', keywords: '', canonicalUrl: '', slug: '',
|
||||
stockStatus: 'IN_STOCK', noIndex: false, noFollow: false, ogImage: '', featuredImageAlt: '',
|
||||
images: [],
|
||||
@ -699,7 +748,14 @@ export default function Products() {
|
||||
noIndex: Boolean(formData.noIndex),
|
||||
noFollow: Boolean(formData.noFollow),
|
||||
ogImage: (formData.ogImage || '').trim() || undefined,
|
||||
featuredImageAlt: (formData.featuredImageAlt || '').trim() || undefined,
|
||||
feedingAdvice: (formData.feedingAdvice || '').trim() || undefined,
|
||||
showFaqs: Boolean(formData.showFaqs),
|
||||
faqs: formData.faqs || [],
|
||||
paoMonths: formData.paoMonths !== '' ? formData.paoMonths : undefined,
|
||||
storageInfo: (formData.storageInfo || '').trim() || undefined,
|
||||
precautions: (formData.precautions || '').trim() || undefined,
|
||||
lifeStage: (formData.lifeStage || '').trim() || undefined,
|
||||
keyHighlights: formData.keyHighlights ? formData.keyHighlights.filter(h => h && h.trim().length > 0) : [],
|
||||
slug: derivedSlug,
|
||||
symptoms: formData.symptoms || [],
|
||||
isPreorder: Boolean(formData.isPreorder),
|
||||
@ -1120,6 +1176,8 @@ export default function Products() {
|
||||
<div className="flex border-b border-gray-100 px-5 sm:px-6 pt-2 gap-3 sm:gap-4 overflow-x-auto shrink-0 bg-gray-50/50">
|
||||
{[
|
||||
{ id: 'general', label: 'اطلاعات پایه' },
|
||||
{ id: 'technical', label: 'مشخصات علمی و نگهداری' },
|
||||
{ id: 'faq', label: 'پرسشهای متداول (FAQ)' },
|
||||
{ id: 'pricing', label: 'موجودی و قیمت' },
|
||||
{ id: 'seo', label: 'سئو (SEO)' },
|
||||
{ id: 'media', label: 'رسانه' }
|
||||
@ -1253,15 +1311,21 @@ export default function Products() {
|
||||
</div>
|
||||
<div className="space-y-2 md:col-span-2">
|
||||
<label className="text-sm font-bold text-gray-700 flex items-center gap-1.5">
|
||||
<span>منطق دوز مصرفی (Dosage Logic)</span>
|
||||
<span>دستور مصرف بالینی و راهنمای دوز (Feeding Advice)</span>
|
||||
<div className="group relative inline-block">
|
||||
<HelpCircle className="w-3.5 h-3.5 text-gray-400 hover:text-purple-600 cursor-help" />
|
||||
<div className="absolute bottom-full right-1/2 translate-x-1/2 mb-2 hidden group-hover:block w-52 p-2.5 bg-gray-900 text-white text-[10px] rounded-lg shadow-xl text-center z-30 font-vazir leading-relaxed">
|
||||
فرمول نحوه مصرف روزانه کالا بر اساس وزن پت (مثال: ۲ میلیلیتر به ازای هر ۵ کیلوگرم وزن).
|
||||
<div className="absolute bottom-full right-1/2 translate-x-1/2 mb-2 hidden group-hover:block w-64 p-2.5 bg-gray-900 text-white text-[10px] rounded-lg shadow-xl text-center z-30 font-vazir leading-relaxed">
|
||||
راهنمای دقیق مصرف برای خریدار در صفحه محصول (مثال: روزانه ۱ قرص به ازای ۱۰ کیلوگرم وزن همراه با غذا).
|
||||
</div>
|
||||
</div>
|
||||
</label>
|
||||
<textarea rows={2} value={formData.dosageLogic} onChange={(e) => setFormData({ ...formData, dosageLogic: e.target.value })} className="w-full px-4 py-3 rounded-xl border border-gray-200 focus:border-purple-500 outline-none"></textarea>
|
||||
<textarea
|
||||
rows={2}
|
||||
value={formData.feedingAdvice}
|
||||
onChange={(e) => setFormData({ ...formData, feedingAdvice: e.target.value })}
|
||||
placeholder="مثال: روزانه ۱ قرص به ازای هر ۱۰ کیلوگرم وزن بدن، ترجیحاً همراه با غذای اصلی مصرف شود."
|
||||
className="w-full px-4 py-3 rounded-xl border border-gray-200 focus:border-purple-500 outline-none font-vazir text-sm"
|
||||
/>
|
||||
</div>
|
||||
<div className="space-y-2 md:col-span-2">
|
||||
<label className="text-sm font-bold text-gray-700 flex items-center gap-1.5">
|
||||
@ -1350,32 +1414,329 @@ export default function Products() {
|
||||
<p className="text-[11px] text-gray-400 font-medium">از منوی پیشنهادی انتخاب کنید یا علامت جدید بنویسید و کلید Enter را بزنید.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Dosage Calculator Field in General Tab */}
|
||||
<div className="space-y-2 pt-2 border-t border-gray-100">
|
||||
<label className="text-sm font-bold text-gray-700 flex items-center justify-between">
|
||||
<span className="flex items-center gap-1.5">
|
||||
<span>دستور مصرف بالینی و راهنمای دوز مصرفی</span>
|
||||
<div className="group relative inline-block">
|
||||
<HelpCircle className="w-3.5 h-3.5 text-gray-400 hover:text-purple-600 cursor-help" />
|
||||
<div className="absolute bottom-full right-1/2 translate-x-1/2 mb-2 hidden group-hover:block w-64 p-2.5 bg-gray-900 text-white text-[10px] rounded-lg shadow-xl text-center z-30 font-vazir leading-relaxed">
|
||||
دستور مصرف روان و فارسی کالا (مانند: روزانه ۱ قرص به ازای هر ۱۰ کیلوگرم وزن بدن). این متن در کاتالوگ آنلاین و صفحه مشخصات کالا به صورت برجسته نمایش داده میشود.
|
||||
{/* Technical & Storage Tab */}
|
||||
<div className={activeTab === 'technical' ? 'block space-y-5' : 'hidden'}>
|
||||
{/* PAO & Storage Card */}
|
||||
<div className="bg-white p-5 rounded-2xl border border-gray-200 shadow-sm space-y-4">
|
||||
<h4 className="text-sm font-black text-gray-800 flex items-center gap-2 border-b pb-2">
|
||||
<Thermometer className="w-4 h-4 text-purple-600" />
|
||||
<span>ماندگاری پس از باز شدن (PAO) و شرایط نگهداری</span>
|
||||
</h4>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-bold text-gray-700 flex items-center justify-between">
|
||||
<span>مدت زمان مجاز مصرف پس از باز شدن (PAO)</span>
|
||||
<span className="text-[10px] text-purple-600 font-bold">نماد استاندارد دارویی</span>
|
||||
</label>
|
||||
<div className="flex items-center gap-2">
|
||||
<input
|
||||
type="text"
|
||||
value={formData.paoMonths}
|
||||
onChange={(e) => setFormData({ ...formData, paoMonths: e.target.value })}
|
||||
placeholder="مثال: 12 یا 6 یا ۲۴ ماه"
|
||||
className="w-full px-4 py-2.5 rounded-xl border border-gray-200 focus:border-purple-500 outline-none text-xs font-bold font-vazir"
|
||||
/>
|
||||
</div>
|
||||
<div className="flex items-center gap-1.5 flex-wrap pt-1">
|
||||
{['3', '6', '12', '24', 'بدون محدودیت'].map((pao) => (
|
||||
<button
|
||||
key={pao}
|
||||
type="button"
|
||||
onClick={() => setFormData({ ...formData, paoMonths: pao })}
|
||||
className={`px-2.5 py-1 text-[11px] font-bold rounded-lg border transition-all ${
|
||||
String(formData.paoMonths) === pao
|
||||
? 'bg-purple-600 text-white border-purple-600 shadow-xs'
|
||||
: 'bg-gray-50 text-gray-700 border-gray-200 hover:border-purple-300'
|
||||
}`}
|
||||
>
|
||||
{pao === 'بدون محدودیت' ? pao : `${pao} ماه`}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-bold text-gray-700 flex items-center justify-between">
|
||||
<span>شرایط استاندارد نگهداری</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setFormData({
|
||||
...formData,
|
||||
storageInfo: 'در جای خشک، خنک (دمای زیر ۲۵ درجه سانتیگراد) و دور از تابش مستقیم نور خورشید نگهداری شود.'
|
||||
})}
|
||||
className="text-[10px] text-purple-600 hover:underline font-bold"
|
||||
>
|
||||
درج پیشفرض Canina ⚡
|
||||
</button>
|
||||
</label>
|
||||
<textarea
|
||||
rows={3}
|
||||
value={formData.storageInfo}
|
||||
onChange={(e) => setFormData({ ...formData, storageInfo: e.target.value })}
|
||||
placeholder="در جای خشک، خنک (دمای زیر ۲۵ درجه سانتیگراد) و دور از تابش مستقیم نور خورشید نگهداری شود."
|
||||
className="w-full px-4 py-2.5 rounded-xl border border-gray-200 focus:border-purple-500 outline-none text-xs leading-relaxed font-vazir"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Safety & Precautions Card */}
|
||||
<div className="bg-white p-5 rounded-2xl border border-gray-200 shadow-sm space-y-4">
|
||||
<h4 className="text-sm font-black text-gray-800 flex items-center gap-2 border-b pb-2">
|
||||
<AlertTriangle className="w-4 h-4 text-amber-500" />
|
||||
<span>رده سنی، ایمنی و تداخلات دارویی</span>
|
||||
</h4>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-4">
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-bold text-gray-700 block">رده سنی و دوران بارداری/شیردهی</label>
|
||||
<input
|
||||
type="text"
|
||||
value={formData.lifeStage}
|
||||
onChange={(e) => setFormData({ ...formData, lifeStage: e.target.value })}
|
||||
placeholder="مثال: مناسب تمام سنین و دوران بارداری و شیردهی"
|
||||
className="w-full px-4 py-2.5 rounded-xl border border-gray-200 focus:border-purple-500 outline-none text-xs font-bold font-vazir"
|
||||
/>
|
||||
<div className="flex items-center gap-1.5 flex-wrap pt-1">
|
||||
{[
|
||||
'مناسب تمام سنین و دوران بارداری و شیردهی',
|
||||
'مخصوص سگ و گربههای بالغ',
|
||||
'مخصوص تولهها و دوران رشد',
|
||||
'مخصوص حیوانات مسن (Senior)'
|
||||
].map((stage) => (
|
||||
<button
|
||||
key={stage}
|
||||
type="button"
|
||||
onClick={() => setFormData({ ...formData, lifeStage: stage })}
|
||||
className="px-2 py-0.5 text-[10px] font-bold rounded-md bg-gray-100 text-gray-600 hover:bg-purple-50 hover:text-purple-700 transition-colors"
|
||||
>
|
||||
{stage}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="space-y-2">
|
||||
<label className="text-xs font-bold text-gray-700 flex items-center justify-between">
|
||||
<span>تداخلات دارویی و فواصل مصرف (Precautions)</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setFormData({
|
||||
...formData,
|
||||
precautions: 'دور از دسترس کودکان نگهداری شود. در صورت مصرف همزمان با سایر پمادها یا اسپریهای درمانی، حداقل ۲۰ دقیقه فاصله زمانی رعایت شود.'
|
||||
})}
|
||||
className="text-[10px] text-amber-700 hover:underline font-bold"
|
||||
>
|
||||
درج احتیاط استاندارد ⚡
|
||||
</button>
|
||||
</label>
|
||||
<textarea
|
||||
rows={3}
|
||||
value={formData.precautions}
|
||||
onChange={(e) => setFormData({ ...formData, precautions: e.target.value })}
|
||||
placeholder="دور از دسترس کودکان نگهداری شود. پس از هربار مصرف درب محصول را محکم ببندید."
|
||||
className="w-full px-4 py-2.5 rounded-xl border border-gray-200 focus:border-purple-500 outline-none text-xs leading-relaxed font-vazir"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Above-the-fold Highlights Card */}
|
||||
<div className="bg-white p-5 rounded-2xl border border-gray-200 shadow-sm space-y-4">
|
||||
<div className="flex items-center justify-between border-b pb-2">
|
||||
<h4 className="text-sm font-black text-gray-800 flex items-center gap-2">
|
||||
<Sparkles className="w-4 h-4 text-emerald-600" />
|
||||
<span>نکات کلیدی بالای صفحه (Above-the-Fold Key Highlights)</span>
|
||||
</h4>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setFormData({
|
||||
...formData,
|
||||
keyHighlights: [
|
||||
'۱۰۰٪ فرمولاسیون طبیعی و بدون نگهدارنده مضر',
|
||||
'ایمن و بدون سمیت در صورت لیسیدن محدود',
|
||||
'گرید دارویی و استاندارد صنعتی آلمان (GMP)',
|
||||
formData.lifeStage || 'مناسب تمام سنین و دوران بارداری و شیردهی'
|
||||
]
|
||||
})}
|
||||
className="text-xs text-emerald-700 hover:underline font-bold flex items-center gap-1"
|
||||
>
|
||||
درج ۴ ویژگی پیشنهادی ⚡
|
||||
</button>
|
||||
</div>
|
||||
<p className="text-[11px] text-gray-500 font-medium">
|
||||
این ۴ نکته با آیکون تیک سبز در بالای صفحه محصول کنار خلاصه و قیمت برای تصمیمگیری سریع خریدار نمایش داده میشوند.
|
||||
</p>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||||
{[0, 1, 2, 3].map((idx) => (
|
||||
<div key={idx} className="space-y-1">
|
||||
<label className="text-[11px] font-bold text-gray-600">نکته کلیدی {idx + 1}</label>
|
||||
<input
|
||||
type="text"
|
||||
value={formData.keyHighlights[idx] || ''}
|
||||
onChange={(e) => {
|
||||
const newHl = [...(formData.keyHighlights || ['', '', '', ''])];
|
||||
newHl[idx] = e.target.value;
|
||||
setFormData({ ...formData, keyHighlights: newHl });
|
||||
}}
|
||||
placeholder={`نکته کلیدی ${idx + 1}...`}
|
||||
className="w-full px-3 py-2 rounded-xl border border-gray-200 focus:border-emerald-500 outline-none text-xs font-bold font-vazir"
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* FAQ Tab */}
|
||||
<div className={activeTab === 'faq' ? 'block space-y-5' : 'hidden'}>
|
||||
{/* Top FAQ Controls */}
|
||||
<div className="bg-white p-5 rounded-2xl border border-gray-200 shadow-sm space-y-4">
|
||||
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-3 border-b pb-4">
|
||||
<div>
|
||||
<h4 className="text-sm font-black text-gray-800 flex items-center gap-2">
|
||||
<HelpCircle className="w-4 h-4 text-purple-600" />
|
||||
<span>بخش پرسش و پاسخهای متداول محصول (Product FAQs)</span>
|
||||
</h4>
|
||||
<p className="text-xs text-gray-500 mt-0.5">مدیریت آکاردئون پرسشهای متداول در صفحه کالا و ثبت خودکار در سئوی گوگل (FAQPage Schema)</p>
|
||||
</div>
|
||||
<div className="flex items-center gap-2 shrink-0">
|
||||
<label className="relative inline-flex items-center cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
className="sr-only peer"
|
||||
checked={formData.showFaqs}
|
||||
onChange={(e) => setFormData({ ...formData, showFaqs: 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>
|
||||
<span className="text-xs font-bold text-gray-700">
|
||||
{formData.showFaqs ? 'بخش FAQ فعال است' : 'بخش FAQ غیرفعال است'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center justify-between flex-wrap gap-2 pt-1">
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
size="sm"
|
||||
startIcon={Plus}
|
||||
onClick={() => {
|
||||
setFormData({
|
||||
...formData,
|
||||
faqs: [...(formData.faqs || []), { question: '', answer: '' }]
|
||||
});
|
||||
}}
|
||||
className="border-purple-200 text-purple-700 hover:bg-purple-50 text-xs font-bold"
|
||||
>
|
||||
افزودن سوال جدید
|
||||
</Button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
const name = formData.nameFa || 'این محصول';
|
||||
setFormData({
|
||||
...formData,
|
||||
faqs: [
|
||||
{
|
||||
question: `آیا لیسیدن ${name} توسط حیوان خطرناک است؟`,
|
||||
answer: `خیر، ترکیبات این محصول با استانداردهای دارویی آلمان فرموله شده و فاقد مواد نگهدارنده شیمیایی مضر است. لیسیدن محدود آن باعث مسمومیت نمیشود؛ اما جهت اثربخشی و جذب حداکثری، پیشنهاد میشود ۱۰ تا ۱۵ دقیقه حواس حیوان پرت شود.`
|
||||
},
|
||||
{
|
||||
question: `مدت زمان ماندگاری و شرایط نگهداری ${name} چگونه است؟`,
|
||||
answer: `این محصول در جای خشک، خنک (دمای زیر ۲۵ درجه سانتیگراد) و دور از تابش مستقیم نور خورشید نگهداری شود. مدت زمان مجاز مصرف پس از باز شدن درب (PAO) ${formData.paoMonths ? `${formData.paoMonths} ماه` : '۱۲ ماه'} میباشد.`
|
||||
},
|
||||
{
|
||||
question: `آیا برای تولهها و حیوانات باردار یا شیرده قابل استفاده است؟`,
|
||||
answer: `بله، با توجه به فرمولاسیون ۱۰۰٪ طبیعی و عدم وجود هورمون یا مواد شیمیایی سنتتیک، استفاده از این محصول برای تمامی ردههای سنی و دوران حساس بارداری و شیردهی طبق دستورالعمل ایمن است.`
|
||||
},
|
||||
{
|
||||
question: `در صورت استفاده همزمان با سایر داروها یا پمادها چه نکاتی باید رعایت شود؟`,
|
||||
answer: `جهت جلوگیری از تداخل در جذب، توصیه میشود بین استفاده از این محصول و سایر داروها، اسپریها یا مکملهای درمانی حداقل ۲۰ الی ۳۰ دقیقه فاصله زمانی رعایت شود.`
|
||||
}
|
||||
]
|
||||
});
|
||||
toast.success('سوالات متداول استاندارد کاتالوگ بارگذاری شدند');
|
||||
}}
|
||||
className="text-xs text-purple-600 hover:text-purple-800 font-bold flex items-center gap-1 hover:underline"
|
||||
>
|
||||
درج سوالات متداول پیشنهادی کاتالوگ Canina ⚡
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* FAQ Items List */}
|
||||
{formData.faqs && formData.faqs.length > 0 ? (
|
||||
<div className="space-y-3">
|
||||
{formData.faqs.map((faq, idx) => (
|
||||
<div key={idx} className="bg-white p-4 rounded-2xl border border-gray-200 shadow-xs space-y-3 relative group">
|
||||
<div className="flex items-center justify-between gap-2 border-b border-gray-100 pb-2">
|
||||
<span className="text-xs font-black text-purple-700 bg-purple-50 px-2.5 py-0.5 rounded-full">
|
||||
سوال {idx + 1}
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
const newFaqs = formData.faqs.filter((_, i) => i !== idx);
|
||||
setFormData({ ...formData, faqs: newFaqs });
|
||||
}}
|
||||
className="text-red-400 hover:text-red-600 p-1 rounded-lg hover:bg-red-50 transition-colors"
|
||||
title="حذف این سوال"
|
||||
>
|
||||
<Trash2 className="w-4 h-4" />
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs font-bold text-gray-700">متن پرسش:</label>
|
||||
<input
|
||||
type="text"
|
||||
value={faq.question}
|
||||
onChange={(e) => {
|
||||
const updated = [...formData.faqs];
|
||||
updated[idx].question = e.target.value;
|
||||
setFormData({ ...formData, faqs: updated });
|
||||
}}
|
||||
placeholder="مثال: آیا لیسیدن این محصول خطرناک است؟"
|
||||
className="w-full px-3 py-2 rounded-xl border border-gray-200 focus:border-purple-500 outline-none text-xs font-bold font-vazir"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="space-y-1.5">
|
||||
<label className="text-xs font-bold text-gray-700">متن پاسخ علمی و کامل:</label>
|
||||
<textarea
|
||||
rows={3}
|
||||
value={faq.answer}
|
||||
onChange={(e) => {
|
||||
const updated = [...formData.faqs];
|
||||
updated[idx].answer = e.target.value;
|
||||
setFormData({ ...formData, faqs: updated });
|
||||
}}
|
||||
placeholder="پاسخ کامل و علمی را وارد نمایید..."
|
||||
className="w-full px-3 py-2 rounded-xl border border-gray-200 focus:border-purple-500 outline-none text-xs leading-relaxed font-vazir"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</span>
|
||||
<span className="text-xs text-purple-600 font-bold">متن راهنمای بالینی</span>
|
||||
</label>
|
||||
<textarea
|
||||
rows={3}
|
||||
value={formData.dosageLogic}
|
||||
onChange={(e) => setFormData({ ...formData, dosageLogic: e.target.value })}
|
||||
placeholder="مثال: روزانه ۱ قرص به ازای هر ۱۰ کیلوگرم وزن بدن، همراه با وعده غذایی مصرف شود."
|
||||
className="w-full px-4 py-3 rounded-xl border border-gray-200 focus:border-purple-500 outline-none text-xs font-vazir"
|
||||
/>
|
||||
<p className="text-[11px] text-gray-400">
|
||||
این متن در بخش مشخصات علمی کالا، ماشینحساب دوز و کاتالوگ آنلاین برای پزشکان و خریداران نمایش داده میشود.
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
) : (
|
||||
<div className="bg-white p-8 rounded-2xl border border-dashed border-gray-300 text-center space-y-3">
|
||||
<div className="w-12 h-12 rounded-2xl bg-purple-50 text-purple-600 flex items-center justify-center mx-auto">
|
||||
<HelpCircle className="w-6 h-6" />
|
||||
</div>
|
||||
<div className="space-y-1">
|
||||
<h5 className="text-sm font-black text-gray-800">هیچ پرسش و پاسخی ثبت نشده است</h5>
|
||||
<p className="text-xs text-gray-500 max-w-md mx-auto">
|
||||
میتوانید با کلیک بر روی «درج سوالات متداول پیشنهادی»، پرسشهای متداول کاتالوگ دارویی را به صورت خودکار بارگذاری و سپس شخصیسازی نمایید.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Pricing Tab */}
|
||||
@ -1795,22 +2156,6 @@ export default function Products() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="space-y-2 col-span-1 md:col-span-2 pt-2">
|
||||
<label className="text-sm font-bold text-gray-700 flex items-center justify-between">
|
||||
<span>منطق و دوز دقیق مصرفی (Dosage Calculator Fields)</span>
|
||||
<span className="text-xs text-purple-600 font-bold">فرمت JSON یا راهنمای متنی</span>
|
||||
</label>
|
||||
<textarea
|
||||
rows={3}
|
||||
value={formData.dosageLogic}
|
||||
onChange={(e) => setFormData({ ...formData, dosageLogic: e.target.value })}
|
||||
placeholder='{"baseDosage": 1, "perKg": 10, "unit": "قرص", "maxPerDay": 3}'
|
||||
className="w-full px-4 py-3 rounded-xl border border-gray-200 focus:border-purple-500 outline-none font-mono text-xs"
|
||||
/>
|
||||
<p className="text-[11px] text-gray-400">
|
||||
این مقادیر توسط محاسبهگر هوشمند دوز مکمل در فرانتاند خوانده میشود.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
@ -243,34 +243,36 @@ export default async function ShopProductPage({ params }: { params: Promise<{ sl
|
||||
const graphEntities: Record<string, unknown>[] = [productJsonLd, breadcrumbJsonLd];
|
||||
|
||||
// 1. FAQPage Schema if faqs exist or derived
|
||||
const productFaqs = (product.faqs && product.faqs.length > 0) ? product.faqs : [
|
||||
{
|
||||
question: `آیا لیسیدن ${product.nameFa || product.name} توسط حیوان خطرناک است؟`,
|
||||
answer: `خیر، ترکیبات این محصول با استانداردهای دارویی آلمان فرموله شده و فاقد مواد نگهدارنده شیمیایی مضر است. لیسیدن محدود آن باعث مسمومیت نمیشود؛ اما جهت اثربخشی و جذب حداکثری، پیشنهاد میشود ۱۰ تا ۱۵ دقیقه حواس حیوان پرت شود یا از پاپوش/محافظ استفاده گردد.`
|
||||
},
|
||||
{
|
||||
question: `مدت زمان ماندگاری و شرایط نگهداری ${product.nameFa || product.name} چگونه است؟`,
|
||||
answer: `این محصول در جای خشک، خنک (دمای زیر ۲۵ درجه سانتیگراد) و دور از تابش مستقیم نور خورشید نگهداری شود. مدت زمان مجاز مصرف پس از باز شدن درب (PAO) ۱۲ ماه میباشد.`
|
||||
},
|
||||
{
|
||||
question: `آیا برای تولهها و سگهای باردار یا شیرده قابل استفاده است؟`,
|
||||
answer: `بله، با توجه به فرمولاسیون طبیعی و عدم وجود هورمون یا مواد شیمیایی سنگین، استفاده از این محصول برای تمامی ردههای سنی (تولهها، سگهای بالغ و مسن) و دوران حساس بارداری و شیردهی طبق دستورالعمل ایمن است.`
|
||||
}
|
||||
];
|
||||
if (product.showFaqs !== false) {
|
||||
const productFaqs = (product.faqs && Array.isArray(product.faqs) && product.faqs.length > 0) ? product.faqs : [
|
||||
{
|
||||
question: `آیا لیسیدن ${product.nameFa || product.name} توسط حیوان خطرناک است؟`,
|
||||
answer: `خیر، ترکیبات این محصول با استانداردهای دارویی آلمان فرموله شده و فاقد مواد نگهدارنده شیمیایی مضر است. لیسیدن محدود آن باعث مسمومیت نمیشود؛ اما جهت اثربخشی و جذب حداکثری، پیشنهاد میشود ۱۰ تا ۱۵ دقیقه حواس حیوان پرت شود یا از پاپوش/محافظ استفاده گردد.`
|
||||
},
|
||||
{
|
||||
question: `مدت زمان ماندگاری و شرایط نگهداری ${product.nameFa || product.name} چگونه است؟`,
|
||||
answer: `این محصول در جای خشک، خنک (دمای زیر ۲۵ درجه سانتیگراد) و دور از تابش مستقیم نور خورشید نگهداری شود. مدت زمان مجاز مصرف پس از باز شدن درب (PAO) ${product.paoMonths ? `${product.paoMonths} ماه` : '۱۲ ماه'} میباشد.`
|
||||
},
|
||||
{
|
||||
question: `آیا برای تولهها و سگهای باردار یا شیرده قابل استفاده است؟`,
|
||||
answer: `بله، با توجه به فرمولاسیون طبیعی و عدم وجود هورمون یا مواد شیمیایی سنگین، استفاده از این محصول برای تمامی ردههای سنی (تولهها، سگهای بالغ و مسن) و دوران حساس بارداری و شیردهی طبق دستورالعمل ایمن است.`
|
||||
}
|
||||
];
|
||||
|
||||
if (productFaqs.length > 0) {
|
||||
graphEntities.push({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'FAQPage',
|
||||
mainEntity: productFaqs.map(f => ({
|
||||
'@type': 'Question',
|
||||
name: f.question,
|
||||
acceptedAnswer: {
|
||||
'@type': 'Answer',
|
||||
text: f.answer
|
||||
}
|
||||
}))
|
||||
});
|
||||
if (productFaqs.length > 0) {
|
||||
graphEntities.push({
|
||||
'@context': 'https://schema.org',
|
||||
'@type': 'FAQPage',
|
||||
mainEntity: productFaqs.map(f => ({
|
||||
'@type': 'Question',
|
||||
name: f.question,
|
||||
acceptedAnswer: {
|
||||
'@type': 'Answer',
|
||||
text: f.answer
|
||||
}
|
||||
}))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 2. AudioObject Schema for AI Podcast
|
||||
|
||||
@ -688,32 +688,30 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
|
||||
)}
|
||||
|
||||
{/* Above-the-fold Fast Decision Highlights (CRO) */}
|
||||
<div className="w-full grid grid-cols-1 sm:grid-cols-2 gap-2 sm:gap-2.5 pt-2">
|
||||
<div className="flex items-center gap-2.5 p-2.5 sm:p-3 rounded-2xl bg-white border border-medical-gray-200/80 shadow-2xs text-right">
|
||||
<div className="w-6 h-6 rounded-lg bg-emerald-50 text-emerald-600 flex items-center justify-center shrink-0">
|
||||
<CheckCircle2 className="w-4 h-4" />
|
||||
{(() => {
|
||||
const defaultHighlights = [
|
||||
"۱۰۰٪ فرمولاسیون طبیعی و بدون نگهدارنده مضر",
|
||||
"ایمن و بدون سمیت در صورت لیسیدن محدود",
|
||||
"گرید دارویی و استاندارد صنعتی آلمان (GMP)",
|
||||
fullProduct.lifeStage || "مناسب تمام سنین و دوران بارداری و شیردهی"
|
||||
];
|
||||
const highlights = (fullProduct.keyHighlights && Array.isArray(fullProduct.keyHighlights) && fullProduct.keyHighlights.length > 0)
|
||||
? fullProduct.keyHighlights
|
||||
: defaultHighlights;
|
||||
|
||||
return (
|
||||
<div className="w-full grid grid-cols-1 sm:grid-cols-2 gap-2 sm:gap-2.5 pt-2">
|
||||
{highlights.map((hl, idx) => (
|
||||
<div key={idx} className="flex items-center gap-2.5 p-2.5 sm:p-3 rounded-2xl bg-white border border-medical-gray-200/80 shadow-2xs text-right">
|
||||
<div className="w-6 h-6 rounded-lg bg-emerald-50 text-emerald-600 flex items-center justify-center shrink-0">
|
||||
<CheckCircle2 className="w-4 h-4" />
|
||||
</div>
|
||||
<span className="text-xs font-black text-medical-gray-800 font-vazir">{hl}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<span className="text-xs font-black text-medical-gray-800 font-vazir">۱۰۰٪ فرمولاسیون طبیعی و بدون نگهدارنده مضر</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2.5 p-2.5 sm:p-3 rounded-2xl bg-white border border-medical-gray-200/80 shadow-2xs text-right">
|
||||
<div className="w-6 h-6 rounded-lg bg-emerald-50 text-emerald-600 flex items-center justify-center shrink-0">
|
||||
<CheckCircle2 className="w-4 h-4" />
|
||||
</div>
|
||||
<span className="text-xs font-black text-medical-gray-800 font-vazir">ایمن و بدون سمیت در صورت لیسیدن محدود</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2.5 p-2.5 sm:p-3 rounded-2xl bg-white border border-medical-gray-200/80 shadow-2xs text-right">
|
||||
<div className="w-6 h-6 rounded-lg bg-emerald-50 text-emerald-600 flex items-center justify-center shrink-0">
|
||||
<CheckCircle2 className="w-4 h-4" />
|
||||
</div>
|
||||
<span className="text-xs font-black text-medical-gray-800 font-vazir">گرید دارویی و استاندارد صنعتی آلمان (GMP)</span>
|
||||
</div>
|
||||
<div className="flex items-center gap-2.5 p-2.5 sm:p-3 rounded-2xl bg-white border border-medical-gray-200/80 shadow-2xs text-right">
|
||||
<div className="w-6 h-6 rounded-lg bg-emerald-50 text-emerald-600 flex items-center justify-center shrink-0">
|
||||
<CheckCircle2 className="w-4 h-4" />
|
||||
</div>
|
||||
<span className="text-xs font-black text-medical-gray-800 font-vazir">مناسب تمام سنین و دوران بارداری و شیردهی</span>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})()}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -1052,10 +1050,10 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
|
||||
<div>
|
||||
<h5 className="text-xs font-black text-medical-gray-900 mb-1">شرایط نگهداری و ماندگاری (PAO)</h5>
|
||||
<p className="text-[11px] text-medical-gray-500 font-bold leading-normal mb-1">
|
||||
{product.storage || "در جای خشک، خنک (دمای زیر ۲۵ درجه سانتیگراد) و دور از تابش مستقیم نور خورشید نگهداری شود."}
|
||||
{product.storageInfo || product.storage || "در جای خشک، خنک (دمای زیر ۲۵ درجه سانتیگراد) و دور از تابش مستقیم نور خورشید نگهداری شود."}
|
||||
</p>
|
||||
<span className="inline-flex items-center gap-1 text-[10px] font-black text-canina-blue bg-canina-blue/10 px-2 py-0.5 rounded-full">
|
||||
⏳ ماندگاری پس از باز شدن درب (PAO): ۱۲ ماه
|
||||
⏳ ماندگاری پس از باز شدن درب (PAO): {product.paoMonths ? `${product.paoMonths} ماه` : '۱۲ ماه'}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
@ -1065,7 +1063,7 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
|
||||
<div>
|
||||
<h5 className="text-xs font-black text-amber-900 mb-1">تداخلات و نکات احتیاطی (Precautions)</h5>
|
||||
<p className="text-[11px] text-amber-800 font-bold leading-normal mb-1">
|
||||
{product.contraindications?.join(" • ") || "دور از دسترس کودکان نگهداری شود. پس از هربار مصرف درب محصول را محکم ببندید."}
|
||||
{product.precautions || product.contraindications?.join(" • ") || "دور از دسترس کودکان نگهداری شود. پس از هربار مصرف درب محصول را محکم ببندید."}
|
||||
</p>
|
||||
<p className="text-[10px] text-amber-700 font-bold">
|
||||
⚠️ در صورت مصرف همزمان با سایر پمادها/اسپریهای درمانی، حداقل ۲۰ دقیقه فاصله زمانی رعایت شود.
|
||||
@ -1212,14 +1210,16 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
|
||||
|
||||
{/* FAQ Section */}
|
||||
{(() => {
|
||||
const displayFaqs = (product.faqs && product.faqs.length > 0) ? product.faqs : [
|
||||
if (product.showFaqs === false) return null;
|
||||
|
||||
const defaultFaqs = [
|
||||
{
|
||||
question: `آیا لیسیدن ${product.nameFa || product.name} توسط حیوان خطرناک است؟`,
|
||||
answer: `خیر، ترکیبات این محصول با استانداردهای دارویی آلمان فرموله شده و فاقد مواد نگهدارنده شیمیایی مضر است. لیسیدن محدود آن باعث مسمومیت نمیشود؛ اما جهت اثربخشی و جذب حداکثری، پیشنهاد میشود ۱۰ تا ۱۵ دقیقه حواس حیوان پرت شود یا از پاپوش/محافظ استفاده گردد.`
|
||||
},
|
||||
{
|
||||
question: `مدت زمان ماندگاری و شرایط نگهداری ${product.nameFa || product.name} چگونه است؟`,
|
||||
answer: `این محصول در جای خشک، خنک (دمای زیر ۲۵ درجه سانتیگراد) و دور از تابش مستقیم نور خورشید نگهداری شود. مدت زمان مجاز مصرف پس از باز شدن درب (PAO) ۱۲ ماه میباشد.`
|
||||
answer: `این محصول در جای خشک، خنک (دمای زیر ۲۵ درجه سانتیگراد) و دور از تابش مستقیم نور خورشید نگهداری شود. مدت زمان مجاز مصرف پس از باز شدن درب (PAO) ${product.paoMonths ? `${product.paoMonths} ماه` : '۱۲ ماه'} میباشد.`
|
||||
},
|
||||
{
|
||||
question: `آیا برای تولهها و سگهای باردار یا شیرده قابل استفاده است؟`,
|
||||
@ -1231,6 +1231,10 @@ export default function ProductPage({ productSlug }: { productSlug: string }) {
|
||||
}
|
||||
];
|
||||
|
||||
const displayFaqs = (product.faqs && Array.isArray(product.faqs) && product.faqs.length > 0)
|
||||
? product.faqs
|
||||
: defaultFaqs;
|
||||
|
||||
return (
|
||||
<section className="pt-10">
|
||||
<div className="flex items-center gap-4 mb-8">
|
||||
|
||||
@ -94,6 +94,13 @@ export interface Product {
|
||||
}>;
|
||||
relatedProducts?: string[];
|
||||
faqs?: FAQ[];
|
||||
showFaqs?: boolean;
|
||||
paoMonths?: number | string;
|
||||
storageInfo?: string;
|
||||
precautions?: string;
|
||||
lifeStage?: string;
|
||||
keyHighlights?: string[];
|
||||
dosageConfig?: Record<string, any>;
|
||||
}
|
||||
|
||||
export const INGREDIENTS_WIKI: IngredientInfo[] = [
|
||||
|
||||
@ -37,6 +37,8 @@ interface BackendProduct {
|
||||
onSetOfAction?: string;
|
||||
optimisticTemplate?: string;
|
||||
feedingAdvice?: string;
|
||||
dosageConfig?: Record<string, any>;
|
||||
faqs?: Array<{ question: string; answer: string }>;
|
||||
slug?: string;
|
||||
imageUrl?: string;
|
||||
image?: string;
|
||||
@ -130,11 +132,21 @@ export class ProductService {
|
||||
benefits: data.benefits || '',
|
||||
suitableFor: (data.suitableFor as PetType) || 'سگ',
|
||||
requiresRx: Boolean(data.requiresRx),
|
||||
storage: data.storage,
|
||||
storage: (data.dosageConfig as Record<string, any>)?.storageInfo || data.storage,
|
||||
specialBadge: data.specialBadge,
|
||||
onSetOfAction: data.onSetOfAction,
|
||||
optimisticTemplate: data.optimisticTemplate,
|
||||
feedingAdvice: data.dosageLogic || data.feedingAdvice || '',
|
||||
feedingAdvice: (data.dosageConfig as Record<string, any>)?.feedingAdvice || data.dosageLogic || data.feedingAdvice || '',
|
||||
showFaqs: (data.dosageConfig as Record<string, any>)?.showFaqs !== undefined ? Boolean((data.dosageConfig as Record<string, any>).showFaqs) : true,
|
||||
faqs: (data.dosageConfig as Record<string, any>)?.faqs && Array.isArray((data.dosageConfig as Record<string, any>).faqs) && (data.dosageConfig as Record<string, any>).faqs.length > 0
|
||||
? (data.dosageConfig as Record<string, any>).faqs
|
||||
: (local?.faqs || []),
|
||||
paoMonths: (data.dosageConfig as Record<string, any>)?.paoMonths || undefined,
|
||||
storageInfo: (data.dosageConfig as Record<string, any>)?.storageInfo || data.storage || undefined,
|
||||
precautions: (data.dosageConfig as Record<string, any>)?.precautions || undefined,
|
||||
lifeStage: (data.dosageConfig as Record<string, any>)?.lifeStage || undefined,
|
||||
keyHighlights: (data.dosageConfig as Record<string, any>)?.keyHighlights || undefined,
|
||||
dosageConfig: (data.dosageConfig as Record<string, any>) || undefined,
|
||||
slug: data.slug,
|
||||
image: (() => {
|
||||
if (!data.imageUrl) return local?.image || '/assets/images/hero-section-image.png';
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
"1": "app.module.ts",
|
||||
"2": "AdminTransactionFilterDto",
|
||||
"3": "productService.ts",
|
||||
"4": "api",
|
||||
"4": "PetProfile.tsx",
|
||||
"5": "CmsController",
|
||||
"6": "TicketsService",
|
||||
"7": "SmsSettingsPage.tsx",
|
||||
@ -13,7 +13,7 @@
|
||||
"11": "WikiController",
|
||||
"12": "index.ts",
|
||||
"13": "app-audit-verification.e2e-spec.js",
|
||||
"14": "UserDashboard.tsx",
|
||||
"14": "toPersian",
|
||||
"15": "src/services/api.ts",
|
||||
"16": "DoctorQueryDto",
|
||||
"17": "schema.ts",
|
||||
@ -57,7 +57,7 @@
|
||||
"55": "UITexts.tsx",
|
||||
"56": "Orders.tsx",
|
||||
"57": "Role & Core Objective",
|
||||
"58": "components/Skeleton.tsx",
|
||||
"58": "UserDashboard.tsx",
|
||||
"59": "compilerOptions",
|
||||
"60": "CreateUserDto",
|
||||
"61": "ProductPage.tsx",
|
||||
@ -89,10 +89,10 @@
|
||||
"87": "dependencies",
|
||||
"88": "payment.controller.ts",
|
||||
"89": "seed-products.ts",
|
||||
"90": "useCartStore",
|
||||
"90": "OrderService",
|
||||
"91": "Reconciled Audit Roles & Assignments",
|
||||
"92": "OrdersService",
|
||||
"93": "HomeClient.tsx",
|
||||
"93": "ArchivePage.tsx",
|
||||
"94": "Phase 3.1 — Human Review Preparation and Master Backlog Critique",
|
||||
"95": "wiki/[slug]/page.tsx",
|
||||
"96": "compilerOptions",
|
||||
@ -121,13 +121,13 @@
|
||||
"119": "compilerOptions",
|
||||
"120": "compilerOptions",
|
||||
"121": "backend/README.md",
|
||||
"122": "AdminService",
|
||||
"122": "AdminController",
|
||||
"123": "UsersService",
|
||||
"124": "Repository Map",
|
||||
"125": "validate_integrity.js",
|
||||
"126": "admin-panel/package.json",
|
||||
"127": "Sahel-Font",
|
||||
"128": "ProductDto",
|
||||
"128": "AdminService",
|
||||
"129": "Reports.tsx",
|
||||
"130": "Sahel-Font",
|
||||
"131": "Role & Core Objective",
|
||||
@ -144,13 +144,13 @@
|
||||
"142": "start-dev.js",
|
||||
"143": "generate-openapi.js",
|
||||
"144": "SafeImage.tsx",
|
||||
"145": "RouteErrorBoundary",
|
||||
"145": "ConfirmModal.tsx",
|
||||
"146": "System Discovery",
|
||||
"147": "HomeController",
|
||||
"148": "track/page.tsx",
|
||||
"149": "trust-seals/page.tsx",
|
||||
"150": "Product Requirement Document (PRD)",
|
||||
"151": "Body",
|
||||
"151": "AuthService",
|
||||
"152": "auth.service.ts",
|
||||
"153": "exclude",
|
||||
"154": "Baseline Command Plan & Reconciled Command History",
|
||||
@ -184,7 +184,7 @@
|
||||
"182": "🎨 Frontend & Admin Panel Technical Review (06_dev_frontend)",
|
||||
"183": "🚀 SEO & Content Strategy Review (12_seo_content)",
|
||||
"184": "MetricsController",
|
||||
"185": "eslint-config-prettier",
|
||||
"185": "eslint",
|
||||
"186": "seed-ui-texts.ts",
|
||||
"187": "seed-wiki.ts",
|
||||
"188": "update-blog.dto.ts",
|
||||
@ -196,8 +196,8 @@
|
||||
"194": "Raw Finding Verification & Disposition Report",
|
||||
"195": "React + TypeScript + Vite",
|
||||
"196": "Select.tsx",
|
||||
"197": "lib/services/api.ts",
|
||||
"198": "Reviews.tsx",
|
||||
"197": "userStore.ts",
|
||||
"198": "@tailwindcss/postcss",
|
||||
"199": "SmsLogQueryDto",
|
||||
"200": "application/README.md",
|
||||
"201": "deploy.sh",
|
||||
@ -293,7 +293,6 @@
|
||||
"292": "Production Docker Compose",
|
||||
"293": "Staging Docker Compose",
|
||||
"294": "ZibalService",
|
||||
"295": "eslint-config-next",
|
||||
"297": "ZibalEBankService",
|
||||
"298": ".initiateOrderPayment",
|
||||
"299": "@tailwindcss/postcss",
|
||||
|
||||
File diff suppressed because one or more lines are too long
@ -3,7 +3,7 @@
|
||||
"1": "app.module.ts",
|
||||
"2": "AdminTransactionFilterDto",
|
||||
"3": "productService.ts",
|
||||
"4": "PetProfile.tsx",
|
||||
"4": "api",
|
||||
"5": "CmsController",
|
||||
"6": "TicketsService",
|
||||
"7": "SmsSettingsPage.tsx",
|
||||
@ -13,7 +13,7 @@
|
||||
"11": "WikiController",
|
||||
"12": "index.ts",
|
||||
"13": "app-audit-verification.e2e-spec.js",
|
||||
"14": "toPersian",
|
||||
"14": "UserDashboard.tsx",
|
||||
"15": "src/services/api.ts",
|
||||
"16": "DoctorQueryDto",
|
||||
"17": "schema.ts",
|
||||
@ -57,7 +57,7 @@
|
||||
"55": "UITexts.tsx",
|
||||
"56": "Orders.tsx",
|
||||
"57": "Role & Core Objective",
|
||||
"58": "UserDashboard.tsx",
|
||||
"58": "components/Skeleton.tsx",
|
||||
"59": "compilerOptions",
|
||||
"60": "CreateUserDto",
|
||||
"61": "ProductPage.tsx",
|
||||
@ -89,10 +89,10 @@
|
||||
"87": "dependencies",
|
||||
"88": "payment.controller.ts",
|
||||
"89": "seed-products.ts",
|
||||
"90": "OrderService",
|
||||
"90": "useCartStore",
|
||||
"91": "Reconciled Audit Roles & Assignments",
|
||||
"92": "OrdersService",
|
||||
"93": "ArchivePage.tsx",
|
||||
"93": "HomeClient.tsx",
|
||||
"94": "Phase 3.1 — Human Review Preparation and Master Backlog Critique",
|
||||
"95": "wiki/[slug]/page.tsx",
|
||||
"96": "compilerOptions",
|
||||
@ -121,13 +121,13 @@
|
||||
"119": "compilerOptions",
|
||||
"120": "compilerOptions",
|
||||
"121": "backend/README.md",
|
||||
"122": "AdminController",
|
||||
"122": "AdminService",
|
||||
"123": "UsersService",
|
||||
"124": "Repository Map",
|
||||
"125": "validate_integrity.js",
|
||||
"126": "admin-panel/package.json",
|
||||
"127": "Sahel-Font",
|
||||
"128": "AdminService",
|
||||
"128": "ProductDto",
|
||||
"129": "Reports.tsx",
|
||||
"130": "Sahel-Font",
|
||||
"131": "Role & Core Objective",
|
||||
@ -150,7 +150,7 @@
|
||||
"148": "track/page.tsx",
|
||||
"149": "trust-seals/page.tsx",
|
||||
"150": "Product Requirement Document (PRD)",
|
||||
"151": "AuthService",
|
||||
"151": "Body",
|
||||
"152": "auth.service.ts",
|
||||
"153": "exclude",
|
||||
"154": "Baseline Command Plan & Reconciled Command History",
|
||||
@ -196,7 +196,7 @@
|
||||
"194": "Raw Finding Verification & Disposition Report",
|
||||
"195": "React + TypeScript + Vite",
|
||||
"196": "Select.tsx",
|
||||
"197": "userStore.ts",
|
||||
"197": "lib/services/api.ts",
|
||||
"198": "Reviews.tsx",
|
||||
"199": "SmsLogQueryDto",
|
||||
"200": "application/README.md",
|
||||
@ -232,6 +232,7 @@
|
||||
"230": "instructions.md",
|
||||
"231": "@nestjs/schematics",
|
||||
"232": "prisma",
|
||||
"233": "tailwindcss",
|
||||
"234": "source-map-support",
|
||||
"235": "ts-loader",
|
||||
"236": "ts-node",
|
||||
@ -293,7 +294,6 @@
|
||||
"293": "Staging Docker Compose",
|
||||
"294": "ZibalService",
|
||||
"295": "eslint-config-next",
|
||||
"296": "@tailwindcss/postcss",
|
||||
"297": "ZibalEBankService",
|
||||
"298": ".initiateOrderPayment",
|
||||
"299": "@tailwindcss/postcss",
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
# Graph Report - canina (2026-09-02)
|
||||
|
||||
## Corpus Check
|
||||
- 599 files · ~1,079,429 words
|
||||
- 599 files · ~1,079,434 words
|
||||
- Verdict: corpus is large enough that graph structure adds value.
|
||||
|
||||
## Summary
|
||||
- 4208 nodes · 7642 edges · 312 communities (211 shown, 101 thin omitted)
|
||||
- 4208 nodes · 7642 edges · 312 communities (214 shown, 98 thin omitted)
|
||||
- Extraction: 96% EXTRACTED · 4% INFERRED · 0% AMBIGUOUS · INFERRED: 288 edges (avg confidence: 0.79)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Graph Freshness
|
||||
- Built from commit: `3cbcad7b`
|
||||
- Built from commit: `6fa1f2c9`
|
||||
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
|
||||
- Run `graphify update .` after code changes (no API cost).
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
- app.module.ts
|
||||
- AdminTransactionFilterDto
|
||||
- productService.ts
|
||||
- PetProfile.tsx
|
||||
- api
|
||||
- CmsController
|
||||
- TicketsService
|
||||
- SmsSettingsPage.tsx
|
||||
@ -29,7 +29,7 @@
|
||||
- WikiController
|
||||
- index.ts
|
||||
- app-audit-verification.e2e-spec.js
|
||||
- toPersian
|
||||
- UserDashboard.tsx
|
||||
- src/services/api.ts
|
||||
- DoctorQueryDto
|
||||
- schema.ts
|
||||
@ -72,7 +72,7 @@
|
||||
- UITexts.tsx
|
||||
- Orders.tsx
|
||||
- Role & Core Objective
|
||||
- UserDashboard.tsx
|
||||
- components/Skeleton.tsx
|
||||
- compilerOptions
|
||||
- CreateUserDto
|
||||
- ProductPage.tsx
|
||||
@ -104,10 +104,10 @@
|
||||
- dependencies
|
||||
- payment.controller.ts
|
||||
- seed-products.ts
|
||||
- OrderService
|
||||
- useCartStore
|
||||
- Reconciled Audit Roles & Assignments
|
||||
- OrdersService
|
||||
- ArchivePage.tsx
|
||||
- HomeClient.tsx
|
||||
- Phase 3.1 — Human Review Preparation and Master Backlog Critique
|
||||
- wiki/[slug]/page.tsx
|
||||
- compilerOptions
|
||||
@ -136,13 +136,13 @@
|
||||
- compilerOptions
|
||||
- compilerOptions
|
||||
- backend/README.md
|
||||
- AdminController
|
||||
- AdminService
|
||||
- UsersService
|
||||
- Repository Map
|
||||
- validate_integrity.js
|
||||
- admin-panel/package.json
|
||||
- Sahel-Font
|
||||
- AdminService
|
||||
- ProductDto
|
||||
- Reports.tsx
|
||||
- Sahel-Font
|
||||
- Role & Core Objective
|
||||
@ -165,7 +165,7 @@
|
||||
- track/page.tsx
|
||||
- trust-seals/page.tsx
|
||||
- Product Requirement Document (PRD)
|
||||
- AuthService
|
||||
- Body
|
||||
- auth.service.ts
|
||||
- exclude
|
||||
- Baseline Command Plan & Reconciled Command History
|
||||
@ -210,7 +210,7 @@
|
||||
- Raw Finding Verification & Disposition Report
|
||||
- React + TypeScript + Vite
|
||||
- Select.tsx
|
||||
- userStore.ts
|
||||
- lib/services/api.ts
|
||||
- Reviews.tsx
|
||||
- SmsLogQueryDto
|
||||
- application/README.md
|
||||
@ -246,6 +246,7 @@
|
||||
- instructions.md
|
||||
- @nestjs/schematics
|
||||
- prisma
|
||||
- tailwindcss
|
||||
- source-map-support
|
||||
- ts-loader
|
||||
- ts-node
|
||||
@ -292,7 +293,6 @@
|
||||
- Staging Docker Compose
|
||||
- ZibalService
|
||||
- eslint-config-next
|
||||
- @tailwindcss/postcss
|
||||
- ZibalEBankService
|
||||
- .initiateOrderPayment
|
||||
- @tailwindcss/postcss
|
||||
@ -336,7 +336,7 @@
|
||||
- 3-file cycle: `frontend/application/lib/services/api.ts -> frontend/application/lib/store/userStore.ts -> frontend/application/lib/store/cartStore.ts -> frontend/application/lib/services/api.ts`
|
||||
- 4-file cycle: `frontend/application/lib/services/api.ts -> frontend/application/lib/store/userStore.ts -> frontend/application/lib/store/cartStore.ts -> frontend/application/lib/services/orderService.ts -> frontend/application/lib/services/api.ts`
|
||||
|
||||
## Communities (312 total, 101 thin omitted)
|
||||
## Communities (312 total, 98 thin omitted)
|
||||
|
||||
### Community 0 - "Roles"
|
||||
Cohesion: 0.24
|
||||
@ -352,11 +352,11 @@ Nodes (7): AdminTransactionFilterDto, ApiPropertyOptional, IsIn, IsNumber, IsOpt
|
||||
|
||||
### Community 3 - "productService.ts"
|
||||
Cohesion: 0.06
|
||||
Nodes (39): buildTorobProductSpec(), buildTorobProductTitle(), dynamic, GET(), revalidate, dynamic, GET(), revalidate (+31 more)
|
||||
Nodes (38): buildTorobProductSpec(), buildTorobProductTitle(), dynamic, GET(), revalidate, dynamic, GET(), revalidate (+30 more)
|
||||
|
||||
### Community 4 - "PetProfile.tsx"
|
||||
Cohesion: 0.12
|
||||
Nodes (18): metadata, FeaturedProducts(), ProductCard(), OrderSuccess(), PetProfile(), SearchResultsPage(), CURRENT_SYMPTOMS, MEDICAL_HISTORIES (+10 more)
|
||||
### Community 4 - "api"
|
||||
Cohesion: 0.13
|
||||
Nodes (14): metadata, ContactInfoItem, OrderDetailsModal(), OrderDetailsModalProps, CURRENT_SYMPTOMS, MEDICAL_HISTORIES, SmartAdvisor(), SmartAdvisorProps (+6 more)
|
||||
|
||||
### Community 5 - "CmsController"
|
||||
Cohesion: 0.10
|
||||
@ -394,9 +394,9 @@ Nodes (24): backend, frontend, playwright.config.ts, @playwright/test, tests/**/
|
||||
Cohesion: 0.07
|
||||
Nodes (26): EnvironmentVariables, IsNotEmpty, IsOptional, IsString, validateEnv(), CustomHttpExceptionFilter, Catch, PrismaExceptionFilter (+18 more)
|
||||
|
||||
### Community 14 - "toPersian"
|
||||
Cohesion: 0.17
|
||||
Nodes (20): HomeClient(), VerifyContent(), AddressFormData, AddressModal(), AddressModalProps, normalizeDigits(), validateAddressForm(), CheckoutPage() (+12 more)
|
||||
### Community 14 - "UserDashboard.tsx"
|
||||
Cohesion: 0.13
|
||||
Nodes (28): VerifyContent(), AddressFormData, AddressModal(), AddressModalProps, normalizeDigits(), validateAddressForm(), AuthModal(), AuthModalProps (+20 more)
|
||||
|
||||
### Community 15 - "src/services/api.ts"
|
||||
Cohesion: 0.06
|
||||
@ -415,7 +415,7 @@ Cohesion: 0.19
|
||||
Nodes (8): JwtAuthGuard, Injectable, ROLES_KEY, RequestWithUser, RolesGuard, Injectable, UserReqPayload, ScientificTermData
|
||||
|
||||
### Community 19 - "admin.controller.ts"
|
||||
Cohesion: 0.35
|
||||
Cohesion: 0.29
|
||||
Nodes (12): ApplyGlobalMarginsDto, BulkPriceAdjustmentDto, ApiProperty, ApiPropertyOptional, IsArray, IsBoolean, IsIn, IsNumber (+4 more)
|
||||
|
||||
### Community 20 - "CreateVideoDto"
|
||||
@ -532,7 +532,7 @@ Nodes (19): autoprefixer, devDependencies, autoprefixer, eslint, @eslint/js, glo
|
||||
|
||||
### Community 50 - "devDependencies"
|
||||
Cohesion: 0.12
|
||||
Nodes (17): devDependencies, eslint, jsdom, tailwindcss, @testing-library/jest-dom, @testing-library/react, @types/node, @types/react (+9 more)
|
||||
Nodes (17): devDependencies, eslint, jsdom, @tailwindcss/postcss, @testing-library/jest-dom, @testing-library/react, @types/node, @types/react (+9 more)
|
||||
|
||||
### Community 51 - "BlogsController"
|
||||
Cohesion: 0.14
|
||||
@ -562,21 +562,21 @@ Nodes (15): Badge(), BadgeProps, BadgeVariant, variantStyles, Skeleton(), Monito
|
||||
Cohesion: 0.09
|
||||
Nodes (22): CREATE MODE — Normal Operation, Expected JSON Output Schema, File Scope Boundary, Forbidden Actions, MODE 1: REVIEW (called during Review Phase), MODE 2: CONTENT CREATION (standalone task from backlog), Operating Modes, Operational Rules & Boundaries (+14 more)
|
||||
|
||||
### Community 58 - "UserDashboard.tsx"
|
||||
Cohesion: 0.12
|
||||
Nodes (11): DeleteConfirmModal(), DeleteConfirmModalProps, OrderDetailsModal(), OrderRowSkeleton(), PetProfileSkeleton(), Skeleton(), SkeletonProps, CreateTicketPayload (+3 more)
|
||||
### Community 58 - "components/Skeleton.tsx"
|
||||
Cohesion: 0.24
|
||||
Nodes (4): OrderRowSkeleton(), PetProfileSkeleton(), Skeleton(), SkeletonProps
|
||||
|
||||
### Community 59 - "compilerOptions"
|
||||
Cohesion: 0.06
|
||||
Nodes (30): compilerOptions, allowSyntheticDefaultImports, baseUrl, declaration, emitDecoratorMetadata, esModuleInterop, experimentalDecorators, forceConsistentCasingInFileNames (+22 more)
|
||||
|
||||
### Community 60 - "CreateUserDto"
|
||||
Cohesion: 0.23
|
||||
Cohesion: 0.24
|
||||
Nodes (10): CreateUserDto, ApiProperty, ApiPropertyOptional, IsEmail, IsNotEmpty, IsNumber, IsOptional, IsString (+2 more)
|
||||
|
||||
### Community 61 - "ProductPage.tsx"
|
||||
Cohesion: 0.10
|
||||
Nodes (19): ProductImageZoomModalProps, CalculatorState, GalleryMediaItem, ICON_MAP, isVideoUrl(), ProductImageZoomModal, ProductPage(), ProductReviews (+11 more)
|
||||
Cohesion: 0.09
|
||||
Nodes (20): PodcastInlinePlayer(), ProductImageZoomModalProps, CalculatorState, GalleryMediaItem, ICON_MAP, isVideoUrl(), ProductImageZoomModal, ProductPage() (+12 more)
|
||||
|
||||
### Community 62 - "RevalidationService"
|
||||
Cohesion: 0.14
|
||||
@ -591,20 +591,20 @@ Cohesion: 0.10
|
||||
Nodes (20): compilerOptions, allowImportingTsExtensions, erasableSyntaxOnly, lib, module, moduleDetection, moduleResolution, noEmit (+12 more)
|
||||
|
||||
### Community 65 - "admin.service.ts"
|
||||
Cohesion: 0.14
|
||||
Nodes (15): CouponTargetInput, PaginationQuery, ProductDto, ApiPropertyOptional, IsArray, IsBoolean, IsNumber, IsOptional (+7 more)
|
||||
Cohesion: 0.22
|
||||
Nodes (8): CouponTargetInput, PaginationQuery, applyRounding(), calculateSellingPrice(), DEFAULT_PRICING_SETTINGS, PricingSettings, RoundingMode, CANONICAL_ALIASES
|
||||
|
||||
### Community 66 - "AdminQueryDto"
|
||||
Cohesion: 0.13
|
||||
Nodes (8): ApiQuery, Get, Query, AdminProductQueryDto, AdminQueryDto, ApiPropertyOptional, IsOptional, IsString
|
||||
Cohesion: 0.18
|
||||
Nodes (7): ApiQuery, Query, AdminProductQueryDto, AdminQueryDto, ApiPropertyOptional, IsOptional, IsString
|
||||
|
||||
### Community 67 - "admin.module.ts"
|
||||
Cohesion: 0.13
|
||||
Nodes (13): AdminModule, Module, ReportsController, ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Controller (+5 more)
|
||||
|
||||
### Community 68 - "useSettingsStore"
|
||||
Cohesion: 0.08
|
||||
Nodes (29): HomeClientProps, B2BLandingClient(), BlogPost, BlogPreviewSection(), BrandLogo(), BrandLogoProps, ContactInfoItem, FAQItem (+21 more)
|
||||
Cohesion: 0.10
|
||||
Nodes (22): AuthModal, B2BPortal, CartDrawer, ClientLayout(), B2BLandingClient(), BrandLogo(), BrandLogoProps, FAQItem (+14 more)
|
||||
|
||||
### Community 69 - "Required Review Group Closures"
|
||||
Cohesion: 0.10
|
||||
@ -690,6 +690,10 @@ Nodes (19): CreateEBankCheckoutDto, ApiProperty, ApiPropertyOptional, IsNotEmpty
|
||||
Cohesion: 0.17
|
||||
Nodes (12): prisma, main(), prisma, determineSuitableFor(), findOrCreateCategory(), getProductImageUrl(), main(), parseSize() (+4 more)
|
||||
|
||||
### Community 90 - "useCartStore"
|
||||
Cohesion: 0.07
|
||||
Nodes (27): ArchivePage(), ArchiveProductCard(), CATEGORY_MAP, ICON_MAP, CartDrawer(), DeleteConfirmModal(), DeleteConfirmModalProps, FeaturedProducts() (+19 more)
|
||||
|
||||
### Community 91 - "Reconciled Audit Roles & Assignments"
|
||||
Cohesion: 0.12
|
||||
Nodes (15): 10. Documentation Engineer, 1. Lead Architect / Orchestrator, 2. React / Vite Storefront Auditor, 3. NestJS Backend Auditor, 4. Admin Features Auditor, 5. Database & Data Integrity Auditor, 6. Security Auditor, 7. TypeScript & Code Quality Auditor (+7 more)
|
||||
@ -698,9 +702,9 @@ Nodes (15): 10. Documentation Engineer, 1. Lead Architect / Orchestrator, 2. Rea
|
||||
Cohesion: 0.07
|
||||
Nodes (35): CreateOrderDto, OrderItemDto, ApiProperty, ApiPropertyOptional, IsArray, IsNotEmpty, IsNumber, IsOptional (+27 more)
|
||||
|
||||
### Community 93 - "ArchivePage.tsx"
|
||||
Cohesion: 0.13
|
||||
Nodes (15): ArchivePage(), ArchiveProductCard(), CATEGORY_MAP, ICON_MAP, BannerPlacement(), BannerPlacementProps, ProductCardSkeleton(), B2BInquiry (+7 more)
|
||||
### Community 93 - "HomeClient.tsx"
|
||||
Cohesion: 0.12
|
||||
Nodes (17): HomeClient(), HomeClientProps, BannerPlacement(), BannerPlacementProps, BlogPreviewSection(), Hero(), StatCounter(), TestimonialsSection() (+9 more)
|
||||
|
||||
### Community 94 - "Phase 3.1 — Human Review Preparation and Master Backlog Critique"
|
||||
Cohesion: 0.13
|
||||
@ -810,9 +814,9 @@ 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 122 - "AdminController"
|
||||
Cohesion: 0.17
|
||||
Nodes (12): AdminController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Param (+4 more)
|
||||
### Community 122 - "AdminService"
|
||||
Cohesion: 0.10
|
||||
Nodes (12): AdminController, ApiBearerAuth, ApiOperation, ApiTags, Controller, Delete, Get, Param (+4 more)
|
||||
|
||||
### Community 123 - "UsersService"
|
||||
Cohesion: 0.07
|
||||
@ -834,6 +838,10 @@ 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 128 - "ProductDto"
|
||||
Cohesion: 0.16
|
||||
Nodes (7): ProductDto, ApiPropertyOptional, IsArray, IsBoolean, IsNumber, IsOptional, IsString
|
||||
|
||||
### Community 129 - "Reports.tsx"
|
||||
Cohesion: 0.20
|
||||
Nodes (7): BestSellerItem, CategoryDistItem, COLORS, CustomTooltipProps, ReportData, TopCouponItem, Reports
|
||||
@ -895,8 +903,8 @@ Cohesion: 0.25
|
||||
Nodes (6): app_module_1, core_1, fs, path, swagger_1, yaml
|
||||
|
||||
### Community 144 - "SafeImage.tsx"
|
||||
Cohesion: 0.10
|
||||
Nodes (20): BackButton(), BackButtonProps, BlogPostClientProps, PLAYBACK_RATES, PodcastInlinePlayer(), PodcastInlinePlayerProps, PLAYBACK_RATES, PodcastPlayerModal() (+12 more)
|
||||
Cohesion: 0.08
|
||||
Nodes (23): BackButton(), BackButtonProps, BlogCategory, BlogPostItem, BlogPostClientProps, BlogPost, ProductDetailModalProps, PLAYBACK_RATES (+15 more)
|
||||
|
||||
### Community 145 - "RouteErrorBoundary"
|
||||
Cohesion: 0.22
|
||||
@ -914,6 +922,10 @@ Nodes (10): HomeController, ApiOkResponse, ApiOperation, ApiTags, Controller, Ge
|
||||
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 151 - "Body"
|
||||
Cohesion: 0.21
|
||||
Nodes (3): Body, Post, CouponInput
|
||||
|
||||
### Community 152 - "auth.service.ts"
|
||||
Cohesion: 0.08
|
||||
Nodes (13): AppModule, Module, AdminLoginInput, AuthService, LoginInput, RegisterInput, Injectable, normalizeMobile() (+5 more)
|
||||
@ -1058,9 +1070,9 @@ Nodes (3): Expanding the ESLint configuration, React Compiler, React + TypeScrip
|
||||
Cohesion: 0.50
|
||||
Nodes (3): Select, SelectOption, SelectProps
|
||||
|
||||
### Community 197 - "userStore.ts"
|
||||
Cohesion: 0.08
|
||||
Nodes (37): AuthModal, B2BPortal, CartDrawer, ClientLayout(), LoginModal, AuthModal(), AuthModalProps, extractOtpFromText() (+29 more)
|
||||
### Community 197 - "lib/services/api.ts"
|
||||
Cohesion: 0.09
|
||||
Nodes (17): LoginModal, B2BPortal(), LoginModal(), LoginModalProps, PrescriptionUploadModal(), PrescriptionUploadModalProps, ApiErrorPayload, baseURL (+9 more)
|
||||
|
||||
### Community 198 - "Reviews.tsx"
|
||||
Cohesion: 0.40
|
||||
@ -1101,7 +1113,7 @@ Nodes (3): GET(), handleRevalidate(), POST()
|
||||
## Knowledge Gaps
|
||||
- **1347 isolated node(s):** `$schema`, `collection`, `sourceRoot`, `deleteOutDir`, `name` (+1342 more)
|
||||
These have ≤1 connection - possible missing edges or undocumented components.
|
||||
- **101 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
||||
- **98 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
||||
|
||||
## Suggested Questions
|
||||
_Questions this graph is uniquely positioned to answer:_
|
||||
@ -1117,6 +1129,6 @@ _Questions this graph is uniquely positioned to answer:_
|
||||
- **Should `app.module.ts` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.055299539170506916 - nodes in this community are weakly interconnected._
|
||||
- **Should `productService.ts` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.05780885780885781 - nodes in this community are weakly interconnected._
|
||||
- **Should `PetProfile.tsx` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.11822660098522167 - nodes in this community are weakly interconnected._
|
||||
_Cohesion score 0.06299603174603174 - nodes in this community are weakly interconnected._
|
||||
- **Should `api` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.12648221343873517 - 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-09-02)
|
||||
|
||||
## Corpus Check
|
||||
- 599 files · ~1,079,434 words
|
||||
- 599 files · ~1,081,381 words
|
||||
- Verdict: corpus is large enough that graph structure adds value.
|
||||
|
||||
## Summary
|
||||
- 4208 nodes · 7642 edges · 312 communities (214 shown, 98 thin omitted)
|
||||
- 4208 nodes · 7642 edges · 311 communities (210 shown, 101 thin omitted)
|
||||
- Extraction: 96% EXTRACTED · 4% INFERRED · 0% AMBIGUOUS · INFERRED: 288 edges (avg confidence: 0.79)
|
||||
- Token cost: 0 input · 0 output
|
||||
|
||||
## Graph Freshness
|
||||
- Built from commit: `6fa1f2c9`
|
||||
- Built from commit: `ddd0dcba`
|
||||
- Run `git rev-parse HEAD` and compare to check if the graph is stale.
|
||||
- Run `graphify update .` after code changes (no API cost).
|
||||
|
||||
@ -19,7 +19,7 @@
|
||||
- app.module.ts
|
||||
- AdminTransactionFilterDto
|
||||
- productService.ts
|
||||
- api
|
||||
- PetProfile.tsx
|
||||
- CmsController
|
||||
- TicketsService
|
||||
- SmsSettingsPage.tsx
|
||||
@ -29,7 +29,7 @@
|
||||
- WikiController
|
||||
- index.ts
|
||||
- app-audit-verification.e2e-spec.js
|
||||
- UserDashboard.tsx
|
||||
- toPersian
|
||||
- src/services/api.ts
|
||||
- DoctorQueryDto
|
||||
- schema.ts
|
||||
@ -72,7 +72,7 @@
|
||||
- UITexts.tsx
|
||||
- Orders.tsx
|
||||
- Role & Core Objective
|
||||
- components/Skeleton.tsx
|
||||
- UserDashboard.tsx
|
||||
- compilerOptions
|
||||
- CreateUserDto
|
||||
- ProductPage.tsx
|
||||
@ -104,10 +104,10 @@
|
||||
- dependencies
|
||||
- payment.controller.ts
|
||||
- seed-products.ts
|
||||
- useCartStore
|
||||
- OrderService
|
||||
- Reconciled Audit Roles & Assignments
|
||||
- OrdersService
|
||||
- HomeClient.tsx
|
||||
- ArchivePage.tsx
|
||||
- Phase 3.1 — Human Review Preparation and Master Backlog Critique
|
||||
- wiki/[slug]/page.tsx
|
||||
- compilerOptions
|
||||
@ -136,13 +136,13 @@
|
||||
- compilerOptions
|
||||
- compilerOptions
|
||||
- backend/README.md
|
||||
- AdminService
|
||||
- AdminController
|
||||
- UsersService
|
||||
- Repository Map
|
||||
- validate_integrity.js
|
||||
- admin-panel/package.json
|
||||
- Sahel-Font
|
||||
- ProductDto
|
||||
- AdminService
|
||||
- Reports.tsx
|
||||
- Sahel-Font
|
||||
- Role & Core Objective
|
||||
@ -159,13 +159,13 @@
|
||||
- start-dev.js
|
||||
- generate-openapi.js
|
||||
- SafeImage.tsx
|
||||
- RouteErrorBoundary
|
||||
- ConfirmModal.tsx
|
||||
- System Discovery
|
||||
- HomeController
|
||||
- track/page.tsx
|
||||
- trust-seals/page.tsx
|
||||
- Product Requirement Document (PRD)
|
||||
- Body
|
||||
- AuthService
|
||||
- auth.service.ts
|
||||
- exclude
|
||||
- Baseline Command Plan & Reconciled Command History
|
||||
@ -198,7 +198,7 @@
|
||||
- 🎨 Frontend & Admin Panel Technical Review (06_dev_frontend)
|
||||
- 🚀 SEO & Content Strategy Review (12_seo_content)
|
||||
- MetricsController
|
||||
- eslint-config-prettier
|
||||
- eslint
|
||||
- seed-ui-texts.ts
|
||||
- seed-wiki.ts
|
||||
- update-blog.dto.ts
|
||||
@ -210,8 +210,8 @@
|
||||
- Raw Finding Verification & Disposition Report
|
||||
- React + TypeScript + Vite
|
||||
- Select.tsx
|
||||
- lib/services/api.ts
|
||||
- Reviews.tsx
|
||||
- userStore.ts
|
||||
- @tailwindcss/postcss
|
||||
- SmsLogQueryDto
|
||||
- application/README.md
|
||||
- deploy.sh
|
||||
@ -292,7 +292,6 @@
|
||||
- Production Docker Compose
|
||||
- Staging Docker Compose
|
||||
- ZibalService
|
||||
- eslint-config-next
|
||||
- ZibalEBankService
|
||||
- .initiateOrderPayment
|
||||
- @tailwindcss/postcss
|
||||
@ -336,7 +335,7 @@
|
||||
- 3-file cycle: `frontend/application/lib/services/api.ts -> frontend/application/lib/store/userStore.ts -> frontend/application/lib/store/cartStore.ts -> frontend/application/lib/services/api.ts`
|
||||
- 4-file cycle: `frontend/application/lib/services/api.ts -> frontend/application/lib/store/userStore.ts -> frontend/application/lib/store/cartStore.ts -> frontend/application/lib/services/orderService.ts -> frontend/application/lib/services/api.ts`
|
||||
|
||||
## Communities (312 total, 98 thin omitted)
|
||||
## Communities (311 total, 101 thin omitted)
|
||||
|
||||
### Community 0 - "Roles"
|
||||
Cohesion: 0.24
|
||||
@ -352,11 +351,11 @@ Nodes (7): AdminTransactionFilterDto, ApiPropertyOptional, IsIn, IsNumber, IsOpt
|
||||
|
||||
### Community 3 - "productService.ts"
|
||||
Cohesion: 0.06
|
||||
Nodes (38): buildTorobProductSpec(), buildTorobProductTitle(), dynamic, GET(), revalidate, dynamic, GET(), revalidate (+30 more)
|
||||
Nodes (39): buildTorobProductSpec(), buildTorobProductTitle(), dynamic, GET(), revalidate, dynamic, GET(), revalidate (+31 more)
|
||||
|
||||
### Community 4 - "api"
|
||||
Cohesion: 0.13
|
||||
Nodes (14): metadata, ContactInfoItem, OrderDetailsModal(), OrderDetailsModalProps, CURRENT_SYMPTOMS, MEDICAL_HISTORIES, SmartAdvisor(), SmartAdvisorProps (+6 more)
|
||||
### Community 4 - "PetProfile.tsx"
|
||||
Cohesion: 0.12
|
||||
Nodes (18): metadata, FeaturedProducts(), ProductCard(), OrderSuccess(), PetProfile(), SearchResultsPage(), CURRENT_SYMPTOMS, MEDICAL_HISTORIES (+10 more)
|
||||
|
||||
### Community 5 - "CmsController"
|
||||
Cohesion: 0.10
|
||||
@ -376,7 +375,7 @@ Nodes (17): SettingsController, ApiBearerAuth, ApiOkResponse, ApiOperation, ApiT
|
||||
|
||||
### Community 9 - "devDependencies"
|
||||
Cohesion: 0.08
|
||||
Nodes (25): devDependencies, eslint, @eslint/eslintrc, eslint-plugin-prettier, globals, @nestjs/cli, @nestjs/testing, prettier (+17 more)
|
||||
Nodes (25): devDependencies, eslint-config-prettier, @eslint/eslintrc, eslint-plugin-prettier, globals, @nestjs/cli, @nestjs/testing, prettier (+17 more)
|
||||
|
||||
### Community 10 - "CreateReviewDto"
|
||||
Cohesion: 0.07
|
||||
@ -394,13 +393,13 @@ Nodes (24): backend, frontend, playwright.config.ts, @playwright/test, tests/**/
|
||||
Cohesion: 0.07
|
||||
Nodes (26): EnvironmentVariables, IsNotEmpty, IsOptional, IsString, validateEnv(), CustomHttpExceptionFilter, Catch, PrismaExceptionFilter (+18 more)
|
||||
|
||||
### Community 14 - "UserDashboard.tsx"
|
||||
Cohesion: 0.13
|
||||
Nodes (28): VerifyContent(), AddressFormData, AddressModal(), AddressModalProps, normalizeDigits(), validateAddressForm(), AuthModal(), AuthModalProps (+20 more)
|
||||
### Community 14 - "toPersian"
|
||||
Cohesion: 0.17
|
||||
Nodes (20): HomeClient(), VerifyContent(), AddressFormData, AddressModal(), AddressModalProps, normalizeDigits(), validateAddressForm(), CheckoutPage() (+12 more)
|
||||
|
||||
### Community 15 - "src/services/api.ts"
|
||||
Cohesion: 0.06
|
||||
Nodes (36): Layout(), ProtectedRoute(), MenuGroup, Sidebar(), SidebarProps, SubMenuItem, LiveMonitoringSummary, SEARCHABLE_PAGES (+28 more)
|
||||
Nodes (38): Layout(), ProtectedRoute(), MenuGroup, Sidebar(), SidebarProps, SubMenuItem, LiveMonitoringSummary, SEARCHABLE_PAGES (+30 more)
|
||||
|
||||
### Community 16 - "DoctorQueryDto"
|
||||
Cohesion: 0.09
|
||||
@ -415,7 +414,7 @@ Cohesion: 0.19
|
||||
Nodes (8): JwtAuthGuard, Injectable, ROLES_KEY, RequestWithUser, RolesGuard, Injectable, UserReqPayload, ScientificTermData
|
||||
|
||||
### Community 19 - "admin.controller.ts"
|
||||
Cohesion: 0.29
|
||||
Cohesion: 0.35
|
||||
Nodes (12): ApplyGlobalMarginsDto, BulkPriceAdjustmentDto, ApiProperty, ApiPropertyOptional, IsArray, IsBoolean, IsIn, IsNumber (+4 more)
|
||||
|
||||
### Community 20 - "CreateVideoDto"
|
||||
@ -460,7 +459,7 @@ Nodes (31): Acceptance Criteria, Affected Application, Affected Files, Alternati
|
||||
|
||||
### Community 32 - "adminRoutes.tsx"
|
||||
Cohesion: 0.07
|
||||
Nodes (21): App(), ContactInfoItem, ContactSubmission, CategoryDist, DashboardData, SslStatus, Ticket, TicketMessage (+13 more)
|
||||
Nodes (16): App(), Props, RouteErrorBoundary, State, HeroBanner, VetTestimonial, SslStatus, AdminRouteConfig (+8 more)
|
||||
|
||||
### Community 33 - "WholesaleApplyDto"
|
||||
Cohesion: 0.10
|
||||
@ -532,7 +531,7 @@ Nodes (19): autoprefixer, devDependencies, autoprefixer, eslint, @eslint/js, glo
|
||||
|
||||
### Community 50 - "devDependencies"
|
||||
Cohesion: 0.12
|
||||
Nodes (17): devDependencies, eslint, jsdom, @tailwindcss/postcss, @testing-library/jest-dom, @testing-library/react, @types/node, @types/react (+9 more)
|
||||
Nodes (17): eslint-config-next, devDependencies, eslint, eslint-config-next, jsdom, @testing-library/jest-dom, @testing-library/react, @types/node (+9 more)
|
||||
|
||||
### Community 51 - "BlogsController"
|
||||
Cohesion: 0.14
|
||||
@ -547,8 +546,8 @@ Cohesion: 0.13
|
||||
Nodes (14): SmartAdvisorController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Get (+6 more)
|
||||
|
||||
### Community 54 - "Button.tsx"
|
||||
Cohesion: 0.10
|
||||
Nodes (16): ButtonProps, ButtonSize, ButtonVariant, ConfirmModal(), ConfirmModalProps, HeroBanner, VetTestimonial, FAQ (+8 more)
|
||||
Cohesion: 0.07
|
||||
Nodes (24): ButtonProps, ButtonSize, ButtonVariant, maxWidthClasses, Modal(), ModalProps, ContactInfoItem, ContactSubmission (+16 more)
|
||||
|
||||
### Community 55 - "UITexts.tsx"
|
||||
Cohesion: 0.07
|
||||
@ -562,21 +561,21 @@ Nodes (15): Badge(), BadgeProps, BadgeVariant, variantStyles, Skeleton(), Monito
|
||||
Cohesion: 0.09
|
||||
Nodes (22): CREATE MODE — Normal Operation, Expected JSON Output Schema, File Scope Boundary, Forbidden Actions, MODE 1: REVIEW (called during Review Phase), MODE 2: CONTENT CREATION (standalone task from backlog), Operating Modes, Operational Rules & Boundaries (+14 more)
|
||||
|
||||
### Community 58 - "components/Skeleton.tsx"
|
||||
Cohesion: 0.24
|
||||
Nodes (4): OrderRowSkeleton(), PetProfileSkeleton(), Skeleton(), SkeletonProps
|
||||
### Community 58 - "UserDashboard.tsx"
|
||||
Cohesion: 0.12
|
||||
Nodes (11): DeleteConfirmModal(), DeleteConfirmModalProps, OrderDetailsModal(), OrderRowSkeleton(), PetProfileSkeleton(), Skeleton(), SkeletonProps, CreateTicketPayload (+3 more)
|
||||
|
||||
### Community 59 - "compilerOptions"
|
||||
Cohesion: 0.06
|
||||
Nodes (30): compilerOptions, allowSyntheticDefaultImports, baseUrl, declaration, emitDecoratorMetadata, esModuleInterop, experimentalDecorators, forceConsistentCasingInFileNames (+22 more)
|
||||
|
||||
### Community 60 - "CreateUserDto"
|
||||
Cohesion: 0.24
|
||||
Cohesion: 0.23
|
||||
Nodes (10): CreateUserDto, ApiProperty, ApiPropertyOptional, IsEmail, IsNotEmpty, IsNumber, IsOptional, IsString (+2 more)
|
||||
|
||||
### Community 61 - "ProductPage.tsx"
|
||||
Cohesion: 0.09
|
||||
Nodes (20): PodcastInlinePlayer(), ProductImageZoomModalProps, CalculatorState, GalleryMediaItem, ICON_MAP, isVideoUrl(), ProductImageZoomModal, ProductPage() (+12 more)
|
||||
Cohesion: 0.10
|
||||
Nodes (19): ProductImageZoomModalProps, CalculatorState, GalleryMediaItem, ICON_MAP, isVideoUrl(), ProductImageZoomModal, ProductPage(), ProductReviews (+11 more)
|
||||
|
||||
### Community 62 - "RevalidationService"
|
||||
Cohesion: 0.14
|
||||
@ -591,20 +590,20 @@ Cohesion: 0.10
|
||||
Nodes (20): compilerOptions, allowImportingTsExtensions, erasableSyntaxOnly, lib, module, moduleDetection, moduleResolution, noEmit (+12 more)
|
||||
|
||||
### Community 65 - "admin.service.ts"
|
||||
Cohesion: 0.22
|
||||
Nodes (8): CouponTargetInput, PaginationQuery, applyRounding(), calculateSellingPrice(), DEFAULT_PRICING_SETTINGS, PricingSettings, RoundingMode, CANONICAL_ALIASES
|
||||
Cohesion: 0.14
|
||||
Nodes (15): CouponTargetInput, PaginationQuery, ProductDto, ApiPropertyOptional, IsArray, IsBoolean, IsNumber, IsOptional (+7 more)
|
||||
|
||||
### Community 66 - "AdminQueryDto"
|
||||
Cohesion: 0.18
|
||||
Nodes (7): ApiQuery, Query, AdminProductQueryDto, AdminQueryDto, ApiPropertyOptional, IsOptional, IsString
|
||||
Cohesion: 0.13
|
||||
Nodes (8): ApiQuery, Get, Query, AdminProductQueryDto, AdminQueryDto, ApiPropertyOptional, IsOptional, IsString
|
||||
|
||||
### Community 67 - "admin.module.ts"
|
||||
Cohesion: 0.13
|
||||
Nodes (13): AdminModule, Module, ReportsController, ApiBearerAuth, ApiOperation, ApiQuery, ApiTags, Controller (+5 more)
|
||||
|
||||
### Community 68 - "useSettingsStore"
|
||||
Cohesion: 0.10
|
||||
Nodes (22): AuthModal, B2BPortal, CartDrawer, ClientLayout(), B2BLandingClient(), BrandLogo(), BrandLogoProps, FAQItem (+14 more)
|
||||
Cohesion: 0.08
|
||||
Nodes (29): HomeClientProps, B2BLandingClient(), BlogPost, BlogPreviewSection(), BrandLogo(), BrandLogoProps, ContactInfoItem, FAQItem (+21 more)
|
||||
|
||||
### Community 69 - "Required Review Group Closures"
|
||||
Cohesion: 0.10
|
||||
@ -690,10 +689,6 @@ Nodes (19): CreateEBankCheckoutDto, ApiProperty, ApiPropertyOptional, IsNotEmpty
|
||||
Cohesion: 0.17
|
||||
Nodes (12): prisma, main(), prisma, determineSuitableFor(), findOrCreateCategory(), getProductImageUrl(), main(), parseSize() (+4 more)
|
||||
|
||||
### Community 90 - "useCartStore"
|
||||
Cohesion: 0.07
|
||||
Nodes (27): ArchivePage(), ArchiveProductCard(), CATEGORY_MAP, ICON_MAP, CartDrawer(), DeleteConfirmModal(), DeleteConfirmModalProps, FeaturedProducts() (+19 more)
|
||||
|
||||
### Community 91 - "Reconciled Audit Roles & Assignments"
|
||||
Cohesion: 0.12
|
||||
Nodes (15): 10. Documentation Engineer, 1. Lead Architect / Orchestrator, 2. React / Vite Storefront Auditor, 3. NestJS Backend Auditor, 4. Admin Features Auditor, 5. Database & Data Integrity Auditor, 6. Security Auditor, 7. TypeScript & Code Quality Auditor (+7 more)
|
||||
@ -702,9 +697,9 @@ Nodes (15): 10. Documentation Engineer, 1. Lead Architect / Orchestrator, 2. Rea
|
||||
Cohesion: 0.07
|
||||
Nodes (35): CreateOrderDto, OrderItemDto, ApiProperty, ApiPropertyOptional, IsArray, IsNotEmpty, IsNumber, IsOptional (+27 more)
|
||||
|
||||
### Community 93 - "HomeClient.tsx"
|
||||
Cohesion: 0.12
|
||||
Nodes (17): HomeClient(), HomeClientProps, BannerPlacement(), BannerPlacementProps, BlogPreviewSection(), Hero(), StatCounter(), TestimonialsSection() (+9 more)
|
||||
### Community 93 - "ArchivePage.tsx"
|
||||
Cohesion: 0.13
|
||||
Nodes (15): ArchivePage(), ArchiveProductCard(), CATEGORY_MAP, ICON_MAP, BannerPlacement(), BannerPlacementProps, ProductCardSkeleton(), B2BInquiry (+7 more)
|
||||
|
||||
### Community 94 - "Phase 3.1 — Human Review Preparation and Master Backlog Critique"
|
||||
Cohesion: 0.13
|
||||
@ -743,8 +738,8 @@ Cohesion: 0.15
|
||||
Nodes (12): 10. `TASK-VERIFY-001`, 1. `TASK-SEC-001`, 2. `TASK-SEC-002`, 3. `TASK-SEC-003`, 4. `TASK-FIN-001`, 5. `TASK-BUILD-001`, 6. `TASK-AUTH-001`, 7. `TASK-FE-001` (+4 more)
|
||||
|
||||
### Community 104 - "Products.tsx"
|
||||
Cohesion: 0.10
|
||||
Nodes (24): Input, InputProps, formatPriceWithCommas(), PriceInput(), PriceInputProps, toEnglishDigits(), Coupon, CouponFormData (+16 more)
|
||||
Cohesion: 0.09
|
||||
Nodes (25): Input, InputProps, formatPriceWithCommas(), PriceInput(), PriceInputProps, toEnglishDigits(), Coupon, CouponFormData (+17 more)
|
||||
|
||||
### Community 105 - "Operational Rules & Boundaries"
|
||||
Cohesion: 0.17
|
||||
@ -787,8 +782,8 @@ Cohesion: 0.29
|
||||
Nodes (5): AppController, Controller, Get, AppService, Injectable
|
||||
|
||||
### Community 115 - "Spinner.tsx"
|
||||
Cohesion: 0.07
|
||||
Nodes (36): ImagePreviewModal(), ImagePreviewModalProps, getFileType(), Media, MediaSelector(), MediaSelectorProps, maxWidthClasses, Modal() (+28 more)
|
||||
Cohesion: 0.10
|
||||
Nodes (22): ImagePreviewModal(), ImagePreviewModalProps, getFileType(), Media, MediaSelector(), MediaSelectorProps, Spinner(), Doctor (+14 more)
|
||||
|
||||
### Community 116 - "Vazirmatn Changelog"
|
||||
Cohesion: 0.18
|
||||
@ -814,9 +809,9 @@ 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 122 - "AdminService"
|
||||
Cohesion: 0.10
|
||||
Nodes (12): AdminController, ApiBearerAuth, ApiOperation, ApiTags, Controller, Delete, Get, Param (+4 more)
|
||||
### Community 122 - "AdminController"
|
||||
Cohesion: 0.17
|
||||
Nodes (12): AdminController, ApiBearerAuth, ApiOperation, ApiTags, Body, Controller, Delete, Param (+4 more)
|
||||
|
||||
### Community 123 - "UsersService"
|
||||
Cohesion: 0.07
|
||||
@ -838,10 +833,6 @@ 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 128 - "ProductDto"
|
||||
Cohesion: 0.16
|
||||
Nodes (7): ProductDto, ApiPropertyOptional, IsArray, IsBoolean, IsNumber, IsOptional, IsString
|
||||
|
||||
### Community 129 - "Reports.tsx"
|
||||
Cohesion: 0.20
|
||||
Nodes (7): BestSellerItem, CategoryDistItem, COLORS, CustomTooltipProps, ReportData, TopCouponItem, Reports
|
||||
@ -903,12 +894,12 @@ Cohesion: 0.25
|
||||
Nodes (6): app_module_1, core_1, fs, path, swagger_1, yaml
|
||||
|
||||
### Community 144 - "SafeImage.tsx"
|
||||
Cohesion: 0.08
|
||||
Nodes (23): BackButton(), BackButtonProps, BlogCategory, BlogPostItem, BlogPostClientProps, BlogPost, ProductDetailModalProps, PLAYBACK_RATES (+15 more)
|
||||
Cohesion: 0.10
|
||||
Nodes (20): BackButton(), BackButtonProps, BlogPostClientProps, PLAYBACK_RATES, PodcastInlinePlayer(), PodcastInlinePlayerProps, PLAYBACK_RATES, PodcastPlayerModal() (+12 more)
|
||||
|
||||
### Community 145 - "RouteErrorBoundary"
|
||||
Cohesion: 0.22
|
||||
Nodes (3): Props, RouteErrorBoundary, State
|
||||
### Community 145 - "ConfirmModal.tsx"
|
||||
Cohesion: 0.10
|
||||
Nodes (16): ConfirmModal(), ConfirmModalProps, Pagination(), PaginationProps, Category, Pet, DoctorOption, Video (+8 more)
|
||||
|
||||
### Community 146 - "System Discovery"
|
||||
Cohesion: 0.25
|
||||
@ -922,10 +913,6 @@ Nodes (10): HomeController, ApiOkResponse, ApiOperation, ApiTags, Controller, Ge
|
||||
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 151 - "Body"
|
||||
Cohesion: 0.21
|
||||
Nodes (3): Body, Post, CouponInput
|
||||
|
||||
### Community 152 - "auth.service.ts"
|
||||
Cohesion: 0.08
|
||||
Nodes (13): AppModule, Module, AdminLoginInput, AuthService, LoginInput, RegisterInput, Injectable, normalizeMobile() (+5 more)
|
||||
@ -1070,13 +1057,9 @@ Nodes (3): Expanding the ESLint configuration, React Compiler, React + TypeScrip
|
||||
Cohesion: 0.50
|
||||
Nodes (3): Select, SelectOption, SelectProps
|
||||
|
||||
### Community 197 - "lib/services/api.ts"
|
||||
Cohesion: 0.09
|
||||
Nodes (17): LoginModal, B2BPortal(), LoginModal(), LoginModalProps, PrescriptionUploadModal(), PrescriptionUploadModalProps, ApiErrorPayload, baseURL (+9 more)
|
||||
|
||||
### Community 198 - "Reviews.tsx"
|
||||
Cohesion: 0.40
|
||||
Nodes (5): BlogCommentItem, ProductReview, Reviews(), toPersianDigits(), Reviews
|
||||
### Community 197 - "userStore.ts"
|
||||
Cohesion: 0.08
|
||||
Nodes (37): AuthModal, B2BPortal, CartDrawer, ClientLayout(), LoginModal, AuthModal(), AuthModalProps, extractOtpFromText() (+29 more)
|
||||
|
||||
### Community 199 - "SmsLogQueryDto"
|
||||
Cohesion: 0.25
|
||||
@ -1113,7 +1096,7 @@ Nodes (3): GET(), handleRevalidate(), POST()
|
||||
## Knowledge Gaps
|
||||
- **1347 isolated node(s):** `$schema`, `collection`, `sourceRoot`, `deleteOutDir`, `name` (+1342 more)
|
||||
These have ≤1 connection - possible missing edges or undocumented components.
|
||||
- **98 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
||||
- **101 thin communities (<3 nodes) omitted from report** — run `graphify query` to explore isolated nodes.
|
||||
|
||||
## Suggested Questions
|
||||
_Questions this graph is uniquely positioned to answer:_
|
||||
@ -1129,6 +1112,6 @@ _Questions this graph is uniquely positioned to answer:_
|
||||
- **Should `app.module.ts` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.055299539170506916 - nodes in this community are weakly interconnected._
|
||||
- **Should `productService.ts` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.06299603174603174 - nodes in this community are weakly interconnected._
|
||||
- **Should `api` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.12648221343873517 - nodes in this community are weakly interconnected._
|
||||
_Cohesion score 0.05780885780885781 - nodes in this community are weakly interconnected._
|
||||
- **Should `PetProfile.tsx` be split into smaller, more focused modules?**
|
||||
_Cohesion score 0.11822660098522167 - nodes in this community are weakly interconnected._
|
||||
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