Hamdast1/TEAMMATES_INDEPENDENCE.md
2026-05-20 12:31:48 +03:30

9.3 KiB
Raw Permalink Blame History

استقلال کامل بخش 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 کاهش یابد

تست شده و تضمین شده