diff --git a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/components/chat-deploy/chat-deploy.tsx b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/components/chat-deploy/chat-deploy.tsx index 56f583aca98..150591aa3b1 100644 --- a/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/components/chat-deploy/chat-deploy.tsx +++ b/apps/sim/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/components/chat-deploy/chat-deploy.tsx @@ -1,18 +1,28 @@ 'use client' import { useEffect, useRef, useState } from 'react' -import { AlertTriangle } from 'lucide-react' +import { AlertTriangle, Loader2 } from 'lucide-react' import { Alert, AlertDescription, + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, Card, CardContent, + ImageUpload, Input, Label, Skeleton, Textarea, } from '@/components/ui' import { createLogger } from '@/lib/logs/console/logger' +import { getEmailDomain } from '@/lib/urls/utils' import { AuthSelector } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/components/chat-deploy/components/auth-selector' import { SubdomainInput } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/components/chat-deploy/components/subdomain-input' import { SuccessView } from '@/app/workspace/[workspaceId]/w/[workflowId]/components/control-bar/components/deploy-modal/components/chat-deploy/components/success-view' @@ -32,6 +42,9 @@ interface ChatDeployProps { setChatSubmitting: (submitting: boolean) => void onValidationChange?: (isValid: boolean) => void onPreDeployWorkflow?: () => Promise + showDeleteConfirmation?: boolean + setShowDeleteConfirmation?: (show: boolean) => void + onDeploymentComplete?: () => void } interface ExistingChat { @@ -56,9 +69,27 @@ export function ChatDeploy({ setChatSubmitting, onValidationChange, onPreDeployWorkflow, + showDeleteConfirmation: externalShowDeleteConfirmation, + setShowDeleteConfirmation: externalSetShowDeleteConfirmation, + onDeploymentComplete, }: ChatDeployProps) { const [isLoading, setIsLoading] = useState(false) const [existingChat, setExistingChat] = useState(null) + const [imageUrl, setImageUrl] = useState(null) + const [imageUploadError, setImageUploadError] = useState(null) + const [isDeleting, setIsDeleting] = useState(false) + const [isImageUploading, setIsImageUploading] = useState(false) + const [internalShowDeleteConfirmation, setInternalShowDeleteConfirmation] = useState(false) + const [showSuccessView, setShowSuccessView] = useState(false) + + // Use external state for delete confirmation if provided + const showDeleteConfirmation = + externalShowDeleteConfirmation !== undefined + ? externalShowDeleteConfirmation + : internalShowDeleteConfirmation + + const setShowDeleteConfirmation = + externalSetShowDeleteConfirmation || setInternalShowDeleteConfirmation const { formData, errors, updateField, setError, validateForm, setFormData } = useChatForm() const { deployedUrl, deployChat } = useChatDeployment() @@ -115,10 +146,18 @@ export function ChatDeploy({ : [], }) + // Set image URL if it exists + if (chatDetail.customizations?.imageUrl) { + setImageUrl(chatDetail.customizations.imageUrl) + } + setImageUploadError(null) + onChatExistsChange?.(true) } } else { setExistingChat(null) + setImageUrl(null) + setImageUploadError(null) onChatExistsChange?.(false) } } @@ -150,9 +189,14 @@ export function ChatDeploy({ return } - await deployChat(workflowId, formData, deploymentInfo, existingChat?.id) + await deployChat(workflowId, formData, deploymentInfo, existingChat?.id, imageUrl) onChatExistsChange?.(true) + setShowSuccessView(true) + + // Fetch the updated chat data immediately after deployment + // This ensures existingChat is available when switching back to edit mode + await fetchExistingChat() } catch (error: any) { if (error.message?.includes('subdomain')) { setError('subdomain', error.message) @@ -164,111 +208,263 @@ export function ChatDeploy({ } } + const handleDelete = async () => { + if (!existingChat || !existingChat.id) return + + try { + setIsDeleting(true) + + const response = await fetch(`/api/chat/edit/${existingChat.id}`, { + method: 'DELETE', + }) + + if (!response.ok) { + const error = await response.json() + throw new Error(error.error || 'Failed to delete chat') + } + + // Update state + setExistingChat(null) + setImageUrl(null) + setImageUploadError(null) + onChatExistsChange?.(false) + + // Notify parent of successful deletion + onDeploymentComplete?.() + } catch (error: any) { + logger.error('Failed to delete chat:', error) + setError('general', error.message || 'An unexpected error occurred while deleting') + } finally { + setIsDeleting(false) + setShowDeleteConfirmation(false) + } + } + if (isLoading) { return } - if (deployedUrl) { - return + if (deployedUrl && showSuccessView) { + return ( + <> +
+ setShowDeleteConfirmation(true)} + onUpdate={() => setShowSuccessView(false)} + /> +
+ + {/* Delete Confirmation Dialog */} + + + + Delete Chat? + + This will permanently delete your chat deployment at{' '} + + {existingChat?.subdomain}.{getEmailDomain()} + + . + + All users will lose access immediately, and this action cannot be undone. + + + + + Cancel + + {isDeleting ? ( + + + Deleting... + + ) : ( + 'Delete' + )} + + + + + + ) } return ( -
- {errors.general && ( - - - {errors.general} - - )} - -
- updateField('subdomain', value)} - originalSubdomain={existingChat?.subdomain} - disabled={chatSubmitting} - onValidationChange={setIsSubdomainValid} - /> -
- - updateField('title', e.target.value)} - required + <> + + {errors.general && ( + + + {errors.general} + + )} + +
+ updateField('subdomain', value)} + originalSubdomain={existingChat?.subdomain || undefined} disabled={chatSubmitting} + onValidationChange={setIsSubdomainValid} + isEditingExisting={!!existingChat} /> - {errors.title &&

{errors.title}

} -
-
- -