NextJS; TypeError: handleComplete is not a function

Although i transferred props properly, i keep getting “is not function” error. I’ve worked a lot on that but i couldn’t find a solution. When I try to move(I do necessary implementings) handleComplete function to ProductAddTemplate.tsx, this time i get setIsSubmitting() is not function error.

enter image description here

AddProduct.tsx:

"use client";
import React, { useState } from "react";
import PageBreadcrumb from "@/components/common/PageBreadCrumb";
import { ProductAddTemplate } from "../templates/ProductAddTemplate";
import { Product } from "../types/types";
import { Step } from "../types/types";
import { motion } from "framer-motion";
import { FileSpreadsheet, Edit, CheckCircle, ArrowRight } from "lucide-react";
import { ProductService } from "@/utils/api/services/productService";
import {toast} from "sonner";

export default function AddProduct(): React.ReactElement {
    const [currentStep, setCurrentStep] = useState<number>(0);
    const [selectedMethod, setSelectedMethod] = useState<"manual" | "excel" | null>(null);
    const [productName, setProductName] = useState<string>("");
    const [selectedProducts, setSelectedProducts] = useState<Product[]>([]);
    const [isSubmitting, setIsSubmitting] = useState<boolean>(false);

    // Adımları tanımlayalım - renkli ve ikonlu
    const steps: Step[] = [
        {
            id: 0,
            title: "Yükleme Yöntemi",
            icon: <ArrowRight className="h-5 w-5" />,
            color: "bg-blue-500"
        },
        {
            id: 1,
            title: "Ürün Bilgileri",
            icon: <Edit className="h-5 w-5" />,
            color: "bg-purple-500"
        },
        {
            id: 2,
            title: "Önizleme",
            icon: <FileSpreadsheet className="h-5 w-5" />,
            color: "bg-amber-500"
        },
        {
            id: 3,
            title: "Tamamlandı",
            icon: <CheckCircle className="h-5 w-5" />,
            color: "bg-green-500"
        }
    ];

    // Yükleme yöntemini seçme işlevi
    const handleSelectMethod = (method: "manual" | "excel"): void => {
        setSelectedMethod(method);
        // Animasyon için timeout
        setTimeout(() => {
            setCurrentStep(1); // Bir sonraki adıma geç
        }, 300);
    };

    // Ürün ekleme
    const handleAddProduct = (): void => {
        if (productName.trim() === "") return;
        // Basit bir ürün oluştur (gerçek uygulamada API'den gelecek)
        const newProduct: Product = {
            id: Date.now(), // Geçici ID
            name: productName
        };
        // Animasyonlu ekleme
        setSelectedProducts(prev => [...prev, newProduct]);
        setProductName(""); // Input'u temizle
    };

    // Ürün kaldırma
    const handleRemoveProduct = (productId: number): void => {
        setSelectedProducts(selectedProducts.filter(p => p.id !== productId));
    };

    // Sıfırlama işlevi
    const handleReset = (): void => {
        setCurrentStep(0);
        setSelectedProducts([]);
        setProductName("");
        setSelectedMethod(null);
    };

    // Son adıma geçildiğinde ürünleri API'ye gönder ve konfeti efekti
    // Ürün ekleme işlemini tamamla
    // Ürün ekleme işlemini tamamla
    const handleComplete = async (): Promise<void> => {
        // Ürün kontrolü
        if (selectedMethod === "manual" && selectedProducts.length === 0) {
            toast.warning('Lütfen en az bir ürün ekleyin.');
            return;
        }
        // Yükleme durumunu başlat
        setIsSubmitting(true);
        // Ürün verilerini hazırla
        interface ProductData {
            productNames: string[];
            method: "manual" | "excel" | null;
        }
        const productData: ProductData = {
            productNames: selectedProducts.map((product: Product) => product.name),
            method: selectedMethod
        };
        try {
            // API çağrısını yap
            let success: boolean = false;
            if (selectedMethod === "manual") {
                // Manuel ekleme için API çağrısı
                interface ApiResponse {
                    isSuccessful: boolean;
                    errorMessages?: string[];
                    data?: any;
                }
                const response: ApiResponse | undefined = await ProductService.create(productData);
                success = Boolean(response && response.isSuccessful);
            } else {
                // Excel yükleme için farklı bir API çağrısı (örnek)
                // const response = await ProductService.uploadExcel(excelFile);
                // success = Boolean(response && response.isSuccessful);
                // Şimdilik Excel yüklemesini başarılı sayalım
                success = true;
            }
            // Sonuca göre işlem yap
            if (success) {
                // Başarılı olursa son adıma geç
                setCurrentStep(3);
                // Konfeti efekti
                // Başarı mesajı
                const productCount: number | string = selectedMethod === "manual"
                    ? selectedProducts.length
                    : "Excel'den yüklenen";
                toast.success(`${productCount} ürün başarıyla eklendi.`);
            } else {
                // Hata mesajı
                toast.error("Ürünler eklenirken bir hata oluştu. Lütfen tekrar deneyin.");
            }
        } catch (error: unknown) {
            // Hata durumunda
            console.error("Ürün ekleme işlemi başarısız:", error);
            // Hata mesajını daha detaylı göster
            if (error instanceof Error) {
                toast.error(`Hata: ${error.message}`);
            } else {
                toast.error("Bir hata oluştu. Lütfen daha sonra tekrar deneyin.");
            }
        } finally {
            // Her durumda yükleme durumunu sonlandır
            setIsSubmitting(false);
        }
    };
    return (
        <motion.div
            initial={{ opacity: 0, y: 20 }}
            animate={{ opacity: 1, y: 0 }}
            transition={{ duration: 0.5 }}
            className="min-h-screen bg-gradient-to-br from-white to-blue-50"
        >
            <PageBreadcrumb pageTitle="Ürün Ekle" />
            <motion.div
                className="space-y-4 max-w-5xl mx-auto p-6"
                initial={{ scale: 0.95 }}
                animate={{ scale: 1 }}
                transition={{ duration: 0.3 }}
            >
                <ProductAddTemplate
                    currentStep={currentStep}
                    steps={steps}
                    selectedMethod={selectedMethod}
                    productName={productName}
                    setProductName={setProductName}
                    selectedProducts={selectedProducts}
                    handleSelectMethod={handleSelectMethod}
                    handleAddProduct={handleAddProduct}
                    handleRemoveProduct={handleRemoveProduct}
                    setCurrentStep={setCurrentStep}
                    handleReset={handleReset}
                    isSubmitting={isSubmitting}
                    handleComplete={handleComplete}
                />
            </motion.div>
        </motion.div>
    );
}

ProductAddTemplate.tsx:

import React from "react";
import { StepIndicator } from "../molecules/StepIndicator";
import { MethodSelection } from "../organisms/MethodSelection";
import { StepHeader } from "../organisms/StepHeader";
import { ManualProductEntry } from "../organisms/ManualProductEntry";
import { ExcelUpload } from "../organisms/ExcelUpload";
import { ProductPreview } from "../organisms/ProductPreview";
import { CompletionMessage } from "../organisms/CompletionMessage";
import ComponentCard from "@/components/common/ComponentCard";
import { Step } from "../types/types";
import { Product } from "../types/types";
import { useRouter } from 'next/navigation';
import { motion, AnimatePresence } from "framer-motion";
import { ArrowRight, ArrowLeft, CheckCircle } from "lucide-react";
import {toast} from "sonner";
import ProductService from "@/utils/api/services/productService";

interface ProductAddTemplateProps {
    currentStep: number;
    steps: Step[];
    selectedMethod: "manual" | "excel" | null;
    productName: string;
    setProductName: (name: string) => void;
    selectedProducts: Product[];
    handleSelectMethod: (method: "manual" | "excel") => void;
    handleAddProduct: () => void;
    handleRemoveProduct: (productId: number) => void;
    setCurrentStep: (step: number) => void;
    handleReset: () => void;
    isSubmitting?: boolean;
    handleComplete: () => Promise<void>;
}

export const ProductAddTemplate: React.FC<ProductAddTemplateProps> = ({
                                                                          currentStep,
                                                                          steps,
                                                                          selectedMethod,
                                                                          productName,
                                                                          setProductName,
                                                                          selectedProducts,
                                                                          handleSelectMethod,
                                                                          handleAddProduct,
                                                                          handleRemoveProduct,
                                                                          setCurrentStep,
                                                                          handleReset,
                                                                          isSubmitting = false,
                                                                          handleComplete
                                                                      }) => {
    const router = useRouter();

    // Adım geçişleri için animasyon varyantları
    const variants = {
        hidden: { opacity: 0, x: 50 },
        visible: { opacity: 1, x: 0 },
        exit: { opacity: 0, x: -50 }
    };

    // Adım başlıklarını ve renklerini belirle
    const getStepColor = (stepId: number) => {
        const colors = ["bg-blue-500", "bg-purple-500", "bg-amber-500", "bg-green-500"];
        return colors[stepId] || colors[0];
    };

    // Adım 3'e geçiş için işlev - async olarak işaretlendi
    const goToFinalStep = async (): Promise<void> => {
        console.log("handleComplete type:", typeof handleComplete);
        await handleComplete();
    };

    return (
        <ComponentCard
            title="Ürün Ekle"
            className="border shadow-lg rounded-xl overflow-hidden"
        >
            {/* Adım göstergesi - renkli ve animasyonlu */}
            <div className="mb-8 px-4">
                <StepIndicator
                    steps={steps}
                    currentStep={currentStep}
                    activeColor={getStepColor(currentStep)}
                />
            </div>

            <AnimatePresence mode="wait">
                {/* Adım 0: Yükleme Yöntemi Seçimi */}
                {currentStep === 0 && (
                    <motion.div
                        key="step0"
                        initial="hidden"
                        animate="visible"
                        exit="exit"
                        variants={variants}
                        transition={{ duration: 0.3 }}
                        className="py-4"
                    >
                        <MethodSelection
                            onSelectMethod={handleSelectMethod}
                        />
                    </motion.div>
                )}

                {/* Adım 1: Ürün Bilgileri */}
                {currentStep === 1 && (
                    <motion.div
                        key="step1"
                        initial="hidden"
                        animate="visible"
                        exit="exit"
                        variants={variants}
                        transition={{ duration: 0.3 }}
                        className="flex flex-col gap-6 w-full py-4"
                    >
                        <StepHeader
                            title={selectedMethod === "manual" ? "Ürün Bilgilerini Girin" : "Excel Dosyasını Yükleyin"}
                            subtitle={selectedMethod === "manual"
                                ? "Eklemek istediğiniz ürünlerin bilgilerini girin"
                                : "Ürün bilgilerini içeren Excel dosyasını yükleyin"}
                            icon={selectedMethod === "manual" ? "edit" : "file-spreadsheet"}
                            color={getStepColor(1)}
                            onBack={() => setCurrentStep(0)}
                        />

                        {selectedMethod === "manual" ? (
                            <ManualProductEntry
                                productName={productName}
                                setProductName={setProductName}
                                selectedProducts={selectedProducts}
                                handleAddProduct={handleAddProduct}
                                handleRemoveProduct={handleRemoveProduct}
                                onContinue={() => setCurrentStep(2)}
                                buttonColor={getStepColor(1)}
                            />
                        ) : (
                            <ExcelUpload
                                onContinue={() => setCurrentStep(2)}
                                buttonColor={getStepColor(1)}
                            />
                        )}
                    </motion.div>
                )}

                {/* Adım 2: Önizleme */}
                {currentStep === 2 && (
                    <motion.div
                        key="step2"
                        initial="hidden"
                        animate="visible"
                        exit="exit"
                        variants={variants}
                        transition={{ duration: 0.3 }}
                        className="flex flex-col gap-6 w-full py-4"
                    >
                        <StepHeader
                            title="Ürün Bilgilerini Önizleyin"
                            subtitle="Eklediğiniz ürünleri kontrol edin ve onaylayın"
                            icon="eye"
                            color={getStepColor(2)}
                            onBack={() => setCurrentStep(1)}
                        />

                        <ProductPreview
                            selectedMethod={selectedMethod}
                            selectedProducts={selectedProducts}
                            onEdit={() => setCurrentStep(1)}
                            onConfirm={goToFinalStep}
                            buttonColor={getStepColor(2)}
                            isSubmitting={isSubmitting}
                        />
                    </motion.div>
                )}

                {/* Adım 3: Tamamlandı */}
                {currentStep === 3 && (
                    <motion.div
                        key="step3"
                        initial="hidden"
                        animate="visible"
                        variants={variants}
                        transition={{ duration: 0.3 }}
                        className="py-4"
                    >
                        <CompletionMessage
                            selectedMethod={selectedMethod}
                            productCount={selectedProducts.length}
                            onAddNew={handleReset}
                            onGoToList={() => router.push('/products')}
                            color={getStepColor(3)}
                            isProcessing={isSubmitting}
                        />
                    </motion.div>
                )}
            </AnimatePresence>

            {/* İlerleme göstergesi */}
            <div className="mt-8 flex justify-between items-center text-sm text-gray-500 border-t pt-4">
                <div>
                    {currentStep > 0 && currentStep < 3 && (
                        <button
                            onClick={() => setCurrentStep(currentStep - 1)}
                            className="flex items-center text-gray-600 hover:text-gray-900 transition-colors"
                            disabled={isSubmitting}
                        >
                            <ArrowLeft className="h-4 w-4 mr-1" />
                            Geri
                        </button>
                    )}
                </div>

                <div className="flex items-center">
                    <span className={`font-medium ${getStepColor(currentStep).replace('bg-', 'text-')}`}>
                        Adım {currentStep + 1}/{steps.length}
                    </span>
                    {currentStep === 3 && (
                        <CheckCircle className="h-4 w-4 ml-2 text-green-500" />
                    )}
                </div>

                <div>
                    {currentStep < 2 && currentStep > 0 && (
                        <button
                            onClick={() => setCurrentStep(currentStep + 1)}
                            className="flex items-center text-gray-600 hover:text-gray-900 transition-colors"
                            disabled={isSubmitting}
                        >
                            İleri
                            <ArrowRight className="h-4 w-4 ml-1" />
                        </button>
                    )}
                </div>
            </div>
        </ComponentCard>
    );
};