9.3 KiB
9.3 KiB
استقلال کامل بخش Teammates از Media
تضمین استقلال ✅
بخش teammates در هر دو فرم (ImageForm و ImageVideoForm) کاملاً مستقل از بخش انتخاب رسانه (تصویر/ویدیو) است.
State Management
✅ Teammates State (مستقل)
const [teammates, setTeammates] = useState<string[]>([""]);
ویژگیها:
- هیچ وابستگی به
mediaTypeندارد - هیچ وابستگی به
uploadedImageندارد - هیچ وابستگی به
uploadedVideoندارد - هیچ وابستگی به
videoCoverندارد - هیچگاه reset نمیشود مگر توسط خود کاربر
Handlers (هندلرها)
✅ handleAddTeammate
const handleAddTeammate = () => setTeammates([...teammates, ""]);
- فقط به
teammatesدسترسی دارد - هیچ وابستگی به media ندارد
✅ handleRemoveTeammate
const handleRemoveTeammate = (index: number) => {
const next = teammates.filter((_, i) => i !== index);
setTeammates(next.length > 0 ? next : [""]);
};
- فقط به
teammatesدسترسی دارد - هیچ وابستگی به media ندارد
✅ handleTeammateChange
const handleTeammateChange = (index: number, value: string) => {
const next = [...teammates];
next[index] = value;
setTeammates(next);
};
- فقط به
teammatesدسترسی دارد - هیچ وابستگی به media ندارد
Media Handlers (هندلرهای رسانه)
✅ handleSwitchMediaType (ImageVideoForm)
const handleSwitchMediaType = (type: "image" | "video") => {
setMediaType(type); // ✅ فقط media
setUploadedImage(null); // ✅ فقط media
setUploadedVideo(null); // ✅ فقط media
setVideoCover(null); // ✅ فقط media
// ❌ teammates لمس نمیشود!
};
تضمین: teammates هیچگاه reset نمیشود
✅ handleImageUpload
const handleImageUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) {
const reader = new FileReader();
reader.onloadend = () => setUploadedImage(reader.result as string);
reader.readAsDataURL(file);
}
// ❌ teammates لمس نمیشود!
};
✅ handleVideoUpload
const handleVideoUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
const file = e.target.files?.[0];
if (file) {
const url = URL.createObjectURL(file);
setUploadedVideo({ url, name: file.name });
setVideoCover(null);
}
// ❌ teammates لمس نمیشود!
};
Rendering (رندر)
✅ TeammatesSection - مشروط اما مستقل
{topicConfig.requiresTeammates && (
<TeammatesSection
teammates={teammates}
onAdd={handleAddTeammate}
onRemove={handleRemoveTeammate}
onChange={handleTeammateChange}
/>
)}
ویژگیها:
- فقط بر اساس
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. نتیجه: همتیمیها دستنخورده باقی میمانند ✅
کد بررسی سریع
❌ الگوهای ممنوع (که وجود ندارند):
// ❌ این الگوها در کد وجود ندارند:
const handleSwitchMediaType = () => {
setTeammates([""]); // ❌ NEVER!
};
const handleImageUpload = () => {
setTeammates([]); // ❌ NEVER!
};
useEffect(() => {
if (mediaType === "video") {
setTeammates([""]); // ❌ NEVER!
}
}, [mediaType]);
✅ الگوهای صحیح (که پیادهسازی شده):
// ✅ 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 کاهش یابد
تست شده و تضمین شده ✅