Files
twenty_crm/packages/twenty-front/src/modules/activities/files/components/Attachments.tsx
Marie 9cfabd81cb Fix missing New Note / New Task button (#12513)
New Note button was missing because of the wrong condition being applied
to display it
<img width="492" alt="Capture d’écran 2025-06-10 à 10 26 57"
src="https://github.com/user-attachments/assets/dafd10e3-b3a8-497c-9a00-c395f20cecbb"
/>
2025-06-10 09:12:41 +00:00

146 lines
4.5 KiB
TypeScript

import styled from '@emotion/styled';
import { ChangeEvent, useRef, useState } from 'react';
import { SkeletonLoader } from '@/activities/components/SkeletonLoader';
import { AttachmentList } from '@/activities/files/components/AttachmentList';
import { DropZone } from '@/activities/files/components/DropZone';
import { useAttachments } from '@/activities/files/hooks/useAttachments';
import { useUploadAttachmentFile } from '@/activities/files/hooks/useUploadAttachmentFile';
import { ActivityTargetableObject } from '@/activities/types/ActivityTargetableEntity';
import { useObjectMetadataItem } from '@/object-metadata/hooks/useObjectMetadataItem';
import { useObjectPermissionsForObject } from '@/object-record/hooks/useObjectPermissionsForObject';
import { isDefined } from 'twenty-shared/utils';
import { IconPlus } from 'twenty-ui/display';
import { Button } from 'twenty-ui/input';
import {
AnimatedPlaceholder,
AnimatedPlaceholderEmptyContainer,
AnimatedPlaceholderEmptySubTitle,
AnimatedPlaceholderEmptyTextContainer,
AnimatedPlaceholderEmptyTitle,
EMPTY_PLACEHOLDER_TRANSITION_PROPS,
} from 'twenty-ui/layout';
const StyledAttachmentsContainer = styled.div`
display: flex;
flex: 1;
flex-direction: column;
height: 100%;
overflow: auto;
`;
const StyledFileInput = styled.input`
display: none;
`;
const StyledDropZoneContainer = styled.div`
height: 100%;
`;
export const Attachments = ({
targetableObject,
}: {
targetableObject: ActivityTargetableObject;
}) => {
const inputFileRef = useRef<HTMLInputElement>(null);
const { attachments, loading } = useAttachments(targetableObject);
const { uploadAttachmentFile } = useUploadAttachmentFile();
const [isDraggingFile, setIsDraggingFile] = useState(false);
const handleFileChange = (e: ChangeEvent<HTMLInputElement>) => {
if (isDefined(e.target.files)) onUploadFile?.(e.target.files[0]);
};
const handleUploadFileClick = () => {
inputFileRef?.current?.click?.();
};
const onUploadFile = async (file: File) => {
await uploadAttachmentFile(file, targetableObject);
};
const isAttachmentsEmpty = !attachments || attachments.length === 0;
const { objectMetadataItem } = useObjectMetadataItem({
objectNameSingular: targetableObject.targetObjectNameSingular,
});
const objectPermissions = useObjectPermissionsForObject(
objectMetadataItem.id,
);
const hasObjectUpdatePermissions = objectPermissions.canUpdateObjectRecords;
if (loading && isAttachmentsEmpty) {
return <SkeletonLoader />;
}
if (isAttachmentsEmpty) {
return (
<StyledDropZoneContainer onDragEnter={() => setIsDraggingFile(true)}>
{isDraggingFile ? (
<DropZone
setIsDraggingFile={setIsDraggingFile}
onUploadFile={onUploadFile}
/>
) : (
<AnimatedPlaceholderEmptyContainer
// eslint-disable-next-line react/jsx-props-no-spreading
{...EMPTY_PLACEHOLDER_TRANSITION_PROPS}
>
<AnimatedPlaceholder type="noFile" />
<AnimatedPlaceholderEmptyTextContainer>
<AnimatedPlaceholderEmptyTitle>
No Files
</AnimatedPlaceholderEmptyTitle>
<AnimatedPlaceholderEmptySubTitle>
There are no associated files with this record.
</AnimatedPlaceholderEmptySubTitle>
</AnimatedPlaceholderEmptyTextContainer>
<StyledFileInput
ref={inputFileRef}
onChange={handleFileChange}
type="file"
/>
{!hasObjectUpdatePermissions && (
<Button
Icon={IconPlus}
title="Add file"
variant="secondary"
onClick={handleUploadFileClick}
/>
)}
</AnimatedPlaceholderEmptyContainer>
)}
</StyledDropZoneContainer>
);
}
return (
<StyledAttachmentsContainer>
<StyledFileInput
ref={inputFileRef}
onChange={handleFileChange}
type="file"
/>
<AttachmentList
targetableObject={targetableObject}
title="All"
attachments={attachments ?? []}
button={
hasObjectUpdatePermissions && (
<Button
Icon={IconPlus}
size="small"
variant="secondary"
title="Add file"
onClick={handleUploadFileClick}
></Button>
)
}
/>
</StyledAttachmentsContainer>
);
};