'use client'; import React, { useState, useEffect } from 'react' import currencyCodes from 'currency-codes'; import { useOrg } from '@components/Contexts/OrgContext'; import { useLHSession } from '@components/Contexts/LHSessionContext'; import useSWR, { mutate } from 'swr'; import { getProducts, updateProduct, archiveProduct } from '@services/payments/products'; import { Plus, Pencil, Info, RefreshCcw, SquareCheck, ChevronDown, ChevronUp, Archive } from 'lucide-react'; import Modal from '@components/Objects/StyledElements/Modal/Modal'; import ConfirmationModal from '@components/Objects/StyledElements/ConfirmationModal/ConfirmationModal'; import toast from 'react-hot-toast'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@components/ui/select" import { Button } from "@components/ui/button" import { Input } from "@components/ui/input" import { Textarea } from "@components/ui/textarea" import { Formik, Form, Field, ErrorMessage } from 'formik'; import * as Yup from 'yup'; import { Label } from '@components/ui/label'; import { Badge } from '@components/ui/badge'; import { getPaymentConfigs } from '@services/payments/payments'; import ProductLinkedCourses from './SubComponents/ProductLinkedCourses'; import { usePaymentsEnabled } from '@hooks/usePaymentsEnabled'; import UnconfiguredPaymentsDisclaimer from '@components/Pages/Payments/UnconfiguredPaymentsDisclaimer'; import CreateProductForm from './SubComponents/CreateProductForm'; const validationSchema = Yup.object().shape({ name: Yup.string().required('Name is required'), description: Yup.string().required('Description is required'), amount: Yup.number().min(0, 'Amount must be positive').required('Amount is required'), benefits: Yup.string(), currency: Yup.string().required('Currency is required'), }); function PaymentsProductPage() { const org = useOrg() as any; const session = useLHSession() as any; const [isCreateModalOpen, setIsCreateModalOpen] = useState(false); const [editingProductId, setEditingProductId] = useState(null); const [expandedProducts, setExpandedProducts] = useState<{ [key: string]: boolean }>({}); const [isStripeEnabled, setIsStripeEnabled] = useState(false); const { isEnabled, isLoading } = usePaymentsEnabled(); const { data: products, error } = useSWR( () => org && session ? [`/payments/${org.id}/products`, session.data?.tokens?.access_token] : null, ([url, token]) => getProducts(org.id, token) ); const { data: paymentConfigs, error: paymentConfigError } = useSWR( () => org && session ? [`/payments/${org.id}/config`, session.data?.tokens?.access_token] : null, ([url, token]) => getPaymentConfigs(org.id, token) ); useEffect(() => { if (paymentConfigs) { const stripeConfig = paymentConfigs.find((config: any) => config.provider === 'stripe'); setIsStripeEnabled(!!stripeConfig); } }, [paymentConfigs]); const handleArchiveProduct = async (productId: string) => { const res = await archiveProduct(org.id, productId, session.data?.tokens?.access_token); mutate([`/payments/${org.id}/products`, session.data?.tokens?.access_token]); if (res.status === 200) { toast.success('Product archived successfully'); } else { toast.error(res.data.detail); } } const toggleProductExpansion = (productId: string) => { setExpandedProducts(prev => ({ ...prev, [productId]: !prev[productId] })); }; if (!isEnabled && !isLoading) { return ( ); } if (error) return
Failed to load products
; if (!products) return
Loading...
; return (
setIsCreateModalOpen(false)} /> } />
{products.data.map((product: any) => (
{editingProductId === product.id ? ( setEditingProductId(null)} onCancel={() => setEditingProductId(null)} /> ) : (
{product.product_type === 'subscription' ? : } {product.product_type === 'subscription' ? 'Subscription' : 'One-time payment'}

{product.name}

} functionToExecute={() => handleArchiveProduct(product.id)} status="warning" />

{product.description}

{product.benefits && (

Benefits:

{product.benefits}

)}
Price: {new Intl.NumberFormat('en-US', { style: 'currency', currency: product.currency }).format(product.amount)}
)}
))}
{products.data.length === 0 && (

No products available. Create a new product to get started.

)}
) } const EditProductForm = ({ product, onSuccess, onCancel }: { product: any, onSuccess: () => void, onCancel: () => void }) => { const org = useOrg() as any; const session = useLHSession() as any; const [currencies, setCurrencies] = useState<{ code: string; name: string }[]>([]); useEffect(() => { const allCurrencies = currencyCodes.data.map(currency => ({ code: currency.code, name: `${currency.code} - ${currency.currency}` })); setCurrencies(allCurrencies); }, []); const initialValues = { name: product.name, description: product.description, amount: product.amount, benefits: product.benefits || '', currency: product.currency || '', product_type: product.product_type, }; const handleSubmit = async (values: typeof initialValues, { setSubmitting }: { setSubmitting: (isSubmitting: boolean) => void }) => { try { await updateProduct(org.id, product.id, values, session.data?.tokens?.access_token); mutate([`/payments/${org.id}/products`, session.data?.tokens?.access_token]); onSuccess(); toast.success('Product updated successfully'); } catch (error) { toast.error('Failed to update product'); } finally { setSubmitting(false); } }; return ( {({ isSubmitting, values, setFieldValue }) => (
)}
); }; export default PaymentsProductPage