Files
twenty/packages/twenty-front/src/modules/views/hooks/internal/usePersistView.ts
T
Raphaël Bosi 4faed25624 [PAGE LAYOUTS] Add widgets validation (#16635)
- Add widget validation
- Remove 'None' option for primary axis group by
- Fix error message parsing by passing the operation type in
`useMetadataErrorHandler`
2026-01-07 15:00:13 +00:00

170 lines
4.7 KiB
TypeScript

import { useCallback } from 'react';
import { useMetadataErrorHandler } from '@/metadata-error-handler/hooks/useMetadataErrorHandler';
import { type MetadataRequestResult } from '@/object-metadata/types/MetadataRequestResult.type';
import { useSnackBar } from '@/ui/feedback/snack-bar-manager/hooks/useSnackBar';
import { useViewsSideEffectsOnViewGroups } from '@/views/hooks/useViewsSideEffectsOnViewGroups';
import { ApolloError } from '@apollo/client';
import { t } from '@lingui/core/macro';
import { CrudOperationType } from 'twenty-shared/types';
import { isDefined } from 'twenty-shared/utils';
import { v4 } from 'uuid';
import {
type CreateCoreViewMutationVariables,
type DestroyCoreViewMutationVariables,
type UpdateCoreViewMutationVariables,
useCreateCoreViewMutation,
useDestroyCoreViewMutation,
useUpdateCoreViewMutation,
ViewType,
} from '~/generated/graphql';
export const usePersistView = () => {
const [createCoreViewMutation] = useCreateCoreViewMutation();
const [updateCoreViewMutation] = useUpdateCoreViewMutation();
const [destroyCoreViewMutation] = useDestroyCoreViewMutation();
const { triggerViewGroupOptimisticEffectAtViewCreation } =
useViewsSideEffectsOnViewGroups();
const { handleMetadataError } = useMetadataErrorHandler();
const { enqueueErrorSnackBar } = useSnackBar();
const createView = useCallback(
async (
variables: CreateCoreViewMutationVariables,
objectMetadataItemId: string,
): Promise<
MetadataRequestResult<Awaited<ReturnType<typeof createCoreViewMutation>>>
> => {
try {
const newViewId = variables.input.id ?? v4();
if (variables.input.type === ViewType.KANBAN) {
triggerViewGroupOptimisticEffectAtViewCreation({
newViewId,
objectMetadataItemId: objectMetadataItemId,
mainGroupByFieldMetadataId:
variables.input.mainGroupByFieldMetadataId,
});
}
const result = await createCoreViewMutation({
variables: {
input: {
...variables.input,
id: newViewId,
},
},
});
const newView = result.data?.createCoreView;
if (!isDefined(newView)) {
return {
status: 'failed',
error: new Error('Failed to create view'),
};
}
return {
status: 'successful',
response: result,
};
} catch (error) {
if (error instanceof ApolloError) {
handleMetadataError(error, {
primaryMetadataName: 'view',
operationType: CrudOperationType.CREATE,
});
} else {
enqueueErrorSnackBar({ message: t`An error occurred.` });
}
return {
status: 'failed',
error,
};
}
},
[
createCoreViewMutation,
triggerViewGroupOptimisticEffectAtViewCreation,
handleMetadataError,
enqueueErrorSnackBar,
],
);
const updateView = useCallback(
async (
variables: UpdateCoreViewMutationVariables,
): Promise<
MetadataRequestResult<Awaited<ReturnType<typeof updateCoreViewMutation>>>
> => {
try {
const result = await updateCoreViewMutation({
variables,
});
return {
status: 'successful',
response: result,
};
} catch (error) {
if (error instanceof ApolloError) {
handleMetadataError(error, {
primaryMetadataName: 'view',
operationType: CrudOperationType.UPDATE,
});
} else {
enqueueErrorSnackBar({ message: t`An error occurred.` });
}
return {
status: 'failed',
error,
};
}
},
[updateCoreViewMutation, handleMetadataError, enqueueErrorSnackBar],
);
const destroyView = useCallback(
async (
variables: DestroyCoreViewMutationVariables,
): Promise<
MetadataRequestResult<Awaited<ReturnType<typeof destroyCoreViewMutation>>>
> => {
try {
const result = await destroyCoreViewMutation({
variables,
});
return {
status: 'successful',
response: result,
};
} catch (error) {
if (error instanceof ApolloError) {
handleMetadataError(error, {
primaryMetadataName: 'view',
operationType: CrudOperationType.DELETE,
});
} else {
enqueueErrorSnackBar({ message: t`An error occurred.` });
}
return {
status: 'failed',
error,
};
}
},
[destroyCoreViewMutation, handleMetadataError, enqueueErrorSnackBar],
);
return {
createView,
updateView,
destroyView,
};
};