'use client';
import {
ActionIcon,
Button,
Card,
Combobox,
Divider,
Group,
Input,
ScrollArea,
Stack,
Text,
Textarea,
ThemeIcon,
Tooltip,
useCombobox,
VisuallyHidden,
} from '@mantine/core';
import { useForm } from '@mantine/form';
import { notifications } from '@mantine/notifications';
import { useRef } from 'react';
import useCreateConnection from '../../lib/mutations/useCreateConnection';
import {} from 'react-icons/io';
import { LuChevronsUpDown, LuArrowUpDown } from 'react-icons/lu';
import { CONNECTION_TYPES } from '../../const/connectionTypes';
import UrlSearchInput from './UrlSearchInput';
import SourceCardPreview from './SourceCardPreview';
import { BsCheck, BsExclamation } from 'react-icons/bs';
import { BiSolidChevronDown } from 'react-icons/bi';
interface Props {
onClose: () => void;
/** When provided the source is fixed (connecting from a card). When omitted both URLs are searchable. */
sourceUrl?: string;
/** When provided the target is prefilled. */
targetUrl?: string;
}
export default function AddConnectionForm(props: Props) {
const hasFixedSource = !!props.sourceUrl;
const createConnection = useCreateConnection();
// Track the raw input values so we can auto-confirm valid URLs on submit
const rawSourceInput = useRef(props.sourceUrl ?? '');
const rawTargetInput = useRef(props.targetUrl ?? '');
const typeCombobox = useCombobox({
onDropdownClose: () => typeCombobox.resetSelectedOption(),
});
const form = useForm({
initialValues: {
sourceUrl: props.sourceUrl ?? '',
targetUrl: props.targetUrl ?? '',
connectionType: 'RELATED',
note: '',
},
validateInputOnChange: false,
validateInputOnBlur: true,
validate: {
sourceUrl: (value) => {
if (!value || value.trim() === '') {
return 'Source URL is required';
}
try {
new URL(value);
return null;
} catch {
return 'Please enter a valid URL';
}
},
targetUrl: (value) => {
if (!value || value.trim() === '') {
return 'Please enter a URL';
}
try {
new URL(value);
return null;
} catch {
return 'Please enter a valid URL';
}
},
},
});
const MAX_NOTE_LENGTH = 500;
const handleSwapUrls = () => {
const currentSource = form.values.sourceUrl;
const currentTarget = form.values.targetUrl;
form.setFieldValue('sourceUrl', currentTarget);
form.setFieldValue('targetUrl', currentSource);
};
const handleSubmit = (e: React.FormEvent) => {
e.preventDefault();
// Auto-confirm valid URLs that were typed/pasted but not explicitly selected
if (!form.values.sourceUrl && rawSourceInput.current) {
try {
new URL(rawSourceInput.current);
form.setFieldValue('sourceUrl', rawSourceInput.current);
} catch {
// not a valid URL, let validation handle it
}
}
if (!form.values.targetUrl && rawTargetInput.current) {
try {
new URL(rawTargetInput.current);
form.setFieldValue('targetUrl', rawTargetInput.current);
} catch {
// not a valid URL, let validation handle it
}
}
const validation = form.validate();
if (validation.hasErrors) {
return;
}
const values = form.getValues();
if (values.sourceUrl === values.targetUrl) {
notifications.show({
id: 'same-url-error',
title: 'A link cannot be connected to itself',
message: 'Please choose a different link to connect',
});
return;
}
createConnection.mutate(
{
sourceUrl: values.sourceUrl,
targetUrl: values.targetUrl,
connectionType: values.connectionType
? (values.connectionType as any)
: undefined,
note: values.note || undefined,
},
{
onSuccess: () => {
props.onClose();
notifications.show({
color: 'green',
title: 'Success!',
message: 'Connection created',
position: 'top-center',
loading: false,
autoClose: 2000,
icon: