# استقلال کامل بخش Teammates از Media ## تضمین استقلال ✅ بخش teammates در هر دو فرم (`ImageForm` و `ImageVideoForm`) **کاملاً مستقل** از بخش انتخاب رسانه (تصویر/ویدیو) است. --- ## State Management ### ✅ Teammates State (مستقل) ```typescript const [teammates, setTeammates] = useState([""]); ``` **ویژگی‌ها:** - هیچ وابستگی به `mediaType` ندارد - هیچ وابستگی به `uploadedImage` ندارد - هیچ وابستگی به `uploadedVideo` ندارد - هیچ وابستگی به `videoCover` ندارد - هیچگاه reset نمی‌شود مگر توسط خود کاربر --- ## Handlers (هندلرها) ### ✅ handleAddTeammate ```typescript const handleAddTeammate = () => setTeammates([...teammates, ""]); ``` - **فقط** به `teammates` دسترسی دارد - هیچ وابستگی به media ندارد ### ✅ handleRemoveTeammate ```typescript const handleRemoveTeammate = (index: number) => { const next = teammates.filter((_, i) => i !== index); setTeammates(next.length > 0 ? next : [""]); }; ``` - **فقط** به `teammates` دسترسی دارد - هیچ وابستگی به media ندارد ### ✅ handleTeammateChange ```typescript const handleTeammateChange = (index: number, value: string) => { const next = [...teammates]; next[index] = value; setTeammates(next); }; ``` - **فقط** به `teammates` دسترسی دارد - هیچ وابستگی به media ندارد --- ## Media Handlers (هندلرهای رسانه) ### ✅ handleSwitchMediaType (ImageVideoForm) ```typescript const handleSwitchMediaType = (type: "image" | "video") => { setMediaType(type); // ✅ فقط media setUploadedImage(null); // ✅ فقط media setUploadedVideo(null); // ✅ فقط media setVideoCover(null); // ✅ فقط media // ❌ teammates لمس نمی‌شود! }; ``` **تضمین:** teammates هیچگاه reset نمی‌شود ### ✅ handleImageUpload ```typescript const handleImageUpload = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (file) { const reader = new FileReader(); reader.onloadend = () => setUploadedImage(reader.result as string); reader.readAsDataURL(file); } // ❌ teammates لمس نمی‌شود! }; ``` ### ✅ handleVideoUpload ```typescript const handleVideoUpload = (e: React.ChangeEvent) => { const file = e.target.files?.[0]; if (file) { const url = URL.createObjectURL(file); setUploadedVideo({ url, name: file.name }); setVideoCover(null); } // ❌ teammates لمس نمی‌شود! }; ``` --- ## Rendering (رندر) ### ✅ TeammatesSection - مشروط اما مستقل ```typescript {topicConfig.requiresTeammates && ( )} ``` **ویژگی‌ها:** - فقط بر اساس `topicConfig.requiresTeammates` نمایش داده می‌شود - هیچ ارتباطی با `mediaType` ندارد - هیچ ارتباطی با media uploads ندارد - اگر نمایش داده شود، کاملاً مستقل عمل می‌کند --- ## سناریوهای تست ### ✅ سناریو 1: تعویض Media Type ``` 1. کاربر 3 هم‌تیمی اضافه می‌کند 2. کاربر از "عکس" به "ویدیو" تغییر می‌دهد 3. نتیجه: هم‌تیمی‌ها حفظ می‌شوند ✅ ``` ### ✅ سناریو 2: آپلود تصویر ``` 1. کاربر 2 هم‌تیمی اضافه می‌کند 2. کاربر یک تصویر آپلود می‌کند 3. نتیجه: هم‌تیمی‌ها حفظ می‌شوند ✅ ``` ### ✅ سناریو 3: حذف تصویر ``` 1. کاربر هم‌تیمی وارد می‌کند 2. کاربر تصویر آپلود و سپس حذف می‌کند 3. نتیجه: اطلاعات هم‌تیمی حفظ می‌شود ✅ ``` ### ✅ سناریو 4: آپلود ویدیو + کاور ``` 1. کاربر 4 هم‌تیمی با شماره تلفن وارد می‌کند 2. کاربر ویدیو آپلود می‌کند 3. کاربر کاور ویدیو آپلود می‌کند 4. نتیجه: تمام اطلاعات هم‌تیمی‌ها حفظ می‌شوند ✅ ``` ### ✅ سناریو 5: تعویض چند باره ``` 1. کاربر هم‌تیمی اضافه می‌کند 2. کاربر 10 بار بین عکس/ویدیو تعویض می‌کند 3. نتیجه: هم‌تیمی‌ها دست‌نخورده باقی می‌مانند ✅ ``` --- ## کد بررسی سریع ### ❌ الگوهای ممنوع (که وجود ندارند): ```typescript // ❌ این الگوها در کد وجود ندارند: const handleSwitchMediaType = () => { setTeammates([""]); // ❌ NEVER! }; const handleImageUpload = () => { setTeammates([]); // ❌ NEVER! }; useEffect(() => { if (mediaType === "video") { setTeammates([""]); // ❌ NEVER! } }, [mediaType]); ``` ### ✅ الگوهای صحیح (که پیاده‌سازی شده): ```typescript // ✅ teammates فقط توسط teammate handlers تغییر می‌کند const handleAddTeammate = () => setTeammates([...teammates, ""]); const handleRemoveTeammate = (index) => { /* ... */ }; const handleTeammateChange = (index, value) => { /* ... */ }; // ✅ media handlers فقط media state را تغییر می‌دهند const handleSwitchMediaType = () => { setMediaType(type); setUploadedImage(null); setUploadedVideo(null); setVideoCover(null); // teammates untouched! }; ``` --- ## دیاگرام استقلال ``` ┌─────────────────────────────────────────┐ │ Form Component │ ├─────────────────────────────────────────┤ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │ Media State │ │Teammates State│ │ │ │ │ │ │ │ │ │ mediaType │ │ teammates[] │ │ │ │ uploadedImage│ │ │ │ │ │ uploadedVideo│ │ │ │ │ │ videoCover │ │ │ │ │ └──────┬───────┘ └───────┬───────┘ │ │ │ NO │ │ │ │ INTERACTION │ │ │ │ ✘ │ │ │ └─────────────────────┘ │ │ │ │ ┌──────────────┐ ┌──────────────┐ │ │ │Media Handlers│ │Teammate │ │ │ │ │ │Handlers │ │ │ │ handleSwitch │ │ handleAdd │ │ │ │ handleImage │ │ handleRemove │ │ │ │ handleVideo │ │ handleChange │ │ │ │ handleCover │ │ │ │ │ └──────────────┘ └──────────────┘ │ │ ↓ ↓ │ │ ONLY Media ONLY Teammates │ │ │ └─────────────────────────────────────────┘ ``` --- ## تضمین‌های معماری ### ✅ تضمین 1: State Isolation - State های media و teammates جدا از هم هستند - هیچ shared state وجود ندارد ### ✅ تضمین 2: Handler Isolation - Media handlers فقط media state را تغییر می‌دهند - Teammate handlers فقط teammate state را تغییر می‌دهند ### ✅ تضمین 3: No Side Effects - تغییر mediaType هیچ side effect روی teammates ندارد - آپلود/حذف media هیچ side effect روی teammates ندارد ### ✅ تضمین 4: Independent Rendering - نمایش TeammatesSection فقط به config بستگی دارد - نه به mediaType، نه به uploaded files ### ✅ تضمین 5: Data Integrity - اطلاعات teammates تا زمان submit حفظ می‌شود - فقط کاربر می‌تواند teammates را تغییر دهد - هیچ کد دیگری teammates را reset نمی‌کند --- ## نتیجه‌گیری ✅ **بخش teammates کاملاً مستقل است** - ❌ هیچ وابستگی به media type - ❌ هیچ وابستگی به uploaded files - ❌ هیچ reset خودکار - ❌ هیچ side effect - ✅ کنترل کامل توسط کاربر - ✅ Data integrity تضمین شده - ✅ معماری تمیز و قابل نگهداری --- **این استقلال باعث می‌شود:** - کاربر بتواند آزادانه بین media type ها تعویض کند - اطلاعات هم‌تیمی‌ها هیچوقت از دست نرود - فرم رفتار قابل پیش‌بینی داشته باشد - باگ‌های مربوط به state management کاهش یابد **تست شده و تضمین شده** ✅