Files
twenty/packages/twenty-front/src/modules/settings/accounts/hooks/useImapConnectionForm.ts
nitin d2ddd6f473 Separate system operations from core objects in GraphQL endpoints (#12977)
Moves system-level operations (auth, billing, admin) to use the
/metadata endpoint instead of /graphql.

This cleans up the endpoint separation so /graphql is purely for core
objects (Company, People, etc.) and /metadata handles all system
operations.

Part of prep work for webhook/API key core migration.
2025-07-01 18:29:32 +02:00

141 lines
4.1 KiB
TypeScript

import { zodResolver } from '@hookform/resolvers/zod';
import { useForm } from 'react-hook-form';
import { useRecoilValue } from 'recoil';
import { z } from 'zod';
import { SettingsPath } from '@/types/SettingsPath';
import { SnackBarVariant } from '@/ui/feedback/snack-bar-manager/components/SnackBar';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { useLingui } from '@lingui/react/macro';
import {
ConnectionParameters,
useSaveImapSmtpCaldavMutation,
} from '~/generated-metadata/graphql';
import { useNavigateSettings } from '~/hooks/useNavigateSettings';
import { currentWorkspaceMemberState } from '~/modules/auth/states/currentWorkspaceMemberState';
import { currentWorkspaceState } from '~/modules/auth/states/currentWorkspaceState';
const imapConnectionFormSchema = z.object({
handle: z.string().email('Invalid email address'),
host: z.string().min(1, 'IMAP server is required'),
port: z.number().int().positive('Port must be a positive number'),
secure: z.boolean(),
password: z.string().min(1, 'Password is required'),
});
type ImapConnectionFormValues = z.infer<typeof imapConnectionFormSchema>;
type UseImapConnectionFormProps = {
initialData?: ImapConnectionFormValues;
isEditing?: boolean;
connectedAccountId?: string;
};
export const useImapConnectionForm = ({
initialData,
isEditing = false,
connectedAccountId,
}: UseImapConnectionFormProps = {}) => {
const { t } = useLingui();
const navigate = useNavigateSettings();
const { enqueueSnackBar } = useSnackBar();
const currentWorkspace = useRecoilValue(currentWorkspaceState);
const currentWorkspaceMember = useRecoilValue(currentWorkspaceMemberState);
const [saveImapConnection, { loading: saveLoading }] =
useSaveImapSmtpCaldavMutation();
const resolver = zodResolver(imapConnectionFormSchema);
const defaultValues = {
handle: initialData?.handle || '',
host: initialData?.host || '',
port: initialData?.port || 993,
secure: initialData?.secure ?? true,
password: initialData?.password || '',
};
const formMethods = useForm<ConnectionParameters & { handle: string }>({
mode: 'onSubmit',
resolver,
defaultValues,
});
const { handleSubmit, formState } = formMethods;
const { isValid, isSubmitting } = formState;
const canSave = isValid && !isSubmitting;
const loading = saveLoading;
const handleSave = async (
formValues: ConnectionParameters & { handle: string },
) => {
if (!currentWorkspace?.id) {
enqueueSnackBar('Workspace ID is missing', {
variant: SnackBarVariant.Error,
});
return;
}
if (!currentWorkspaceMember?.id) {
enqueueSnackBar('Workspace member ID is missing', {
variant: SnackBarVariant.Error,
});
return;
}
try {
const variables = {
...(isEditing && connectedAccountId ? { id: connectedAccountId } : {}),
accountOwnerId: currentWorkspaceMember.id,
handle: formValues.handle,
host: formValues.host,
port: formValues.port,
secure: formValues.secure,
password: formValues.password,
};
await saveImapConnection({
variables: {
accountOwnerId: variables.accountOwnerId,
handle: variables.handle,
accountType: {
type: 'IMAP',
},
connectionParameters: {
host: variables.host,
port: variables.port,
secure: variables.secure,
password: variables.password,
username: variables.handle,
},
...(variables.id ? { id: variables.id } : {}),
},
});
enqueueSnackBar(
connectedAccountId
? t`IMAP connection successfully updated`
: t`IMAP connection successfully created`,
{
variant: SnackBarVariant.Success,
},
);
navigate(SettingsPath.Accounts);
} catch (error) {
enqueueSnackBar((error as Error).message, {
variant: SnackBarVariant.Error,
});
}
};
return {
formMethods,
handleSave,
handleSubmit,
canSave,
isSubmitting,
loading,
};
};