217 lines
7.7 KiB
TypeScript
217 lines
7.7 KiB
TypeScript
import { useState } from "react";
|
|
import { motion } from "motion/react";
|
|
import { SubmitFormProps, getTopicConfig } from "../../../config/topicConfig";
|
|
import { MediaUploadBox } from "./shared/MediaUploadBox";
|
|
import { TeammatesSection, Teammate } from "./shared/TeammatesSection";
|
|
import { FormInput } from "./shared/FormInput";
|
|
import { uploadImage, submitMission } from "../../../services/feedService";
|
|
import { useProfile } from "../../context/ProfileContext";
|
|
|
|
// Helper function to generate unique IDs
|
|
const generateId = () => `teammate-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
|
|
export function ImageForm({ topicId, topicTitle, onSubmit }: SubmitFormProps) {
|
|
const topicConfig = getTopicConfig(topicId);
|
|
const { refreshProfile } = useProfile();
|
|
|
|
// ===== Form Fields State =====
|
|
const [title, setTitle] = useState("");
|
|
const [learnings, setLearnings] = useState("");
|
|
|
|
// ===== Teammates State (with unique IDs and verification) =====
|
|
const [teammates, setTeammates] = useState<Teammate[]>([{ id: generateId(), phone: "" }]);
|
|
|
|
// ===== Media State =====
|
|
const [uploadedImage, setUploadedImage] = useState<string | null>(null);
|
|
const [uploadedImageFile, setUploadedImageFile] = useState<File | null>(null);
|
|
|
|
// ===== Loading State =====
|
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
const [uploadProgress, setUploadProgress] = useState<string>("");
|
|
|
|
// ===== Media Handler =====
|
|
const handleImageUpload = (e: React.ChangeEvent<HTMLInputElement>) => {
|
|
const file = e.target.files?.[0];
|
|
if (file) {
|
|
setUploadedImageFile(file);
|
|
const reader = new FileReader();
|
|
reader.onloadend = () => setUploadedImage(reader.result as string);
|
|
reader.readAsDataURL(file);
|
|
}
|
|
};
|
|
|
|
// ===== Teammates Handlers =====
|
|
const handleAddTeammate = () => {
|
|
setTeammates([...teammates, { id: generateId(), phone: "" }]);
|
|
};
|
|
|
|
const handleRemoveTeammate = (id: string) => {
|
|
const filtered = teammates.filter((t) => t.id !== id);
|
|
setTeammates(filtered.length > 0 ? filtered : [{ id: generateId(), phone: "" }]);
|
|
};
|
|
|
|
const handleTeammateChange = (id: string, value: string) => {
|
|
setTeammates(teammates.map((t) => (t.id === id ? { ...t, phone: value, fullName: undefined, userId: undefined, error: undefined } : t)));
|
|
};
|
|
|
|
const handleTeammateVerify = (id: string, fullName: string, userId: string, error?: string) => {
|
|
setTeammates(teammates.map((t) => (t.id === id ? { ...t, fullName, userId, error } : t)));
|
|
};
|
|
|
|
const handleSubmit = async () => {
|
|
if (isSubmitting) return;
|
|
|
|
setIsSubmitting(true);
|
|
|
|
try {
|
|
// آپلود تصویر اگر وجود دارد
|
|
let imageFilename = "";
|
|
if (uploadedImageFile) {
|
|
setUploadProgress("در حال آپلود تصویر...");
|
|
const filename = await uploadImage(uploadedImageFile);
|
|
if (filename) {
|
|
imageFilename = filename;
|
|
} else {
|
|
alert("خطا در آپلود تصویر");
|
|
setIsSubmitting(false);
|
|
setUploadProgress("");
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Get verified user IDs and join with comma
|
|
const verifiedUserIds = teammates
|
|
.filter((t) => t.userId)
|
|
.map((t) => t.userId)
|
|
.join(",");
|
|
|
|
// Get workflow_ID from localStorage
|
|
const workflowID = localStorage.getItem("current_workflow_ID") || "";
|
|
|
|
// ثبت نهایی ماموریت
|
|
setUploadProgress("در حال ثبت ماموریت...");
|
|
const result = await submitMission({
|
|
title: title || "",
|
|
mission_type: topicTitle,
|
|
mission_done_workflowID: workflowID,
|
|
description: learnings || "",
|
|
film: "",
|
|
image: imageFilename,
|
|
audio: "",
|
|
team_member: verifiedUserIds,
|
|
});
|
|
|
|
if (result.success) {
|
|
// بروزرسانی پروفایل (برای سکههای جدید)
|
|
await refreshProfile();
|
|
|
|
// فراخوانی onSubmit برای نمایش modal و هدایت به feed
|
|
onSubmit({
|
|
topicId,
|
|
title,
|
|
learnings,
|
|
teammates: verifiedUserIds ? [verifiedUserIds] : [],
|
|
mediaType: "image",
|
|
uploadedImage,
|
|
});
|
|
} else {
|
|
alert(result.message || "خطا در ثبت ماموریت");
|
|
}
|
|
} catch (error) {
|
|
console.error("Error submitting:", error);
|
|
alert("خطا در ثبت ماموریت");
|
|
} finally {
|
|
setIsSubmitting(false);
|
|
setUploadProgress("");
|
|
}
|
|
};
|
|
|
|
return (
|
|
<div className="space-y-6" dir="rtl">
|
|
{/* Image Upload */}
|
|
<MediaUploadBox
|
|
type="image"
|
|
uploadedFile={uploadedImage}
|
|
onUpload={handleImageUpload}
|
|
onRemove={() => setUploadedImage(null)}
|
|
label="تصویر چالش"
|
|
/>
|
|
|
|
{/* Teammates - Only show if config requires it */}
|
|
{topicConfig.requiresTeammates && (
|
|
<TeammatesSection
|
|
teammates={teammates}
|
|
onAdd={handleAddTeammate}
|
|
onRemove={handleRemoveTeammate}
|
|
onChange={handleTeammateChange}
|
|
onVerify={handleTeammateVerify}
|
|
/>
|
|
)}
|
|
|
|
{/* Title */}
|
|
<FormInput
|
|
label="عنوان چالش"
|
|
value={title}
|
|
onChange={setTitle}
|
|
placeholder="عنوان چالش خود را وارد کنید..."
|
|
/>
|
|
|
|
{/* Learnings */}
|
|
<FormInput
|
|
label="از این چالش چه چیزی یاد گرفتیم"
|
|
value={learnings}
|
|
onChange={setLearnings}
|
|
placeholder="توضیحات خود را وارد کنید..."
|
|
multiline
|
|
rows={6}
|
|
/>
|
|
|
|
{/* Submit Button */}
|
|
<motion.button
|
|
whileTap={{ scale: 0.95 }}
|
|
onClick={handleSubmit}
|
|
disabled={isSubmitting}
|
|
className="w-full py-4 rounded-full text-white text-base font-bold mb-6"
|
|
style={{
|
|
backgroundImage: isSubmitting
|
|
? "linear-gradient(145deg, rgba(72, 58, 105, 0.72) 0%, rgba(42, 35, 77, 0.76) 100%)"
|
|
: "linear-gradient(90deg, rgba(255,139,91,1) 0%, rgba(238,91,166,1) 45%, rgba(147,78,255,1) 100%), linear-gradient(120deg, #7c3aed 0%, #f97316 58%, #facc15 100%)",
|
|
backgroundOrigin: "border-box",
|
|
backgroundClip: "padding-box, border-box",
|
|
boxShadow: isSubmitting
|
|
? "inset 0 1px 0 rgba(255,255,255,0.12)"
|
|
: "0 10px 26px rgba(196, 87, 255, 0.35), inset 0 1px 0 rgba(255,255,255,0.35)",
|
|
border: "1px solid transparent",
|
|
opacity: isSubmitting ? 0.7 : 1,
|
|
cursor: isSubmitting ? "not-allowed" : "pointer",
|
|
}}
|
|
>
|
|
{isSubmitting ? "در حال ثبت..." : "ثبت نهایی چالش"}
|
|
</motion.button>
|
|
|
|
{/* Upload Progress Message */}
|
|
{uploadProgress && (
|
|
<motion.div
|
|
initial={{ opacity: 0, y: -10 }}
|
|
animate={{ opacity: 1, y: 0 }}
|
|
className="text-center mb-4 p-4 rounded-2xl"
|
|
style={{
|
|
backgroundImage: "linear-gradient(180deg, rgba(46, 27, 61, 0.88) 0%, rgba(35, 24, 62, 0.92) 100%), linear-gradient(120deg, #7c3aed 0%, #f97316 58%, #facc15 100%)",
|
|
backgroundOrigin: "border-box",
|
|
backgroundClip: "padding-box, border-box",
|
|
border: "0.5px solid transparent",
|
|
}}
|
|
>
|
|
<div className="flex items-center justify-center gap-3">
|
|
<motion.div
|
|
animate={{ rotate: 360 }}
|
|
transition={{ duration: 1, repeat: Infinity, ease: "linear" }}
|
|
className="w-5 h-5 border-2 border-[#D8B4FE] border-t-transparent rounded-full"
|
|
/>
|
|
<span className="text-[#FBE7F5] font-bold text-sm">{uploadProgress}</span>
|
|
</div>
|
|
</motion.div>
|
|
)}
|
|
</div>
|
|
);
|
|
} |