blob: 68c3424fe96dc3c007a0569bdfd6c94b8f5365e0 [file] [log] [blame]
idilloncab81d72022-11-08 12:20:00 -05001/*
2 * Copyright (C) 2022 Savoir-faire Linux Inc.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Affero General Public License as
6 * published by the Free Software Foundation; either version 3 of the
7 * License, or (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Affero General Public License for more details.
13 *
14 * You should have received a copy of the GNU Affero General Public
15 * License along with this program. If not, see
16 * <https://www.gnu.org/licenses/>.
17 */
18import { AttachFile } from '@mui/icons-material';
19import { IconButton, IconButtonProps, Stack, Typography } from '@mui/material';
20import * as mime from 'mime';
21import { useRef } from 'react';
22
23import { FileHandler } from '../utils/files';
24import { useDataSizeUnits } from '../utils/units';
25import { SaltireIcon } from './SvgIcon';
26
27interface FilePreviewIconProps {
28 fileHandler: FileHandler;
29 size: string;
30}
31
32const FilePreviewIcon = ({ fileHandler, size }: FilePreviewIconProps) => {
33 if (fileHandler.file.type.split('/')[0] === 'image') {
34 return (
35 <img
36 src={fileHandler.url}
37 alt={fileHandler.file.name}
38 style={{ height: size, width: size, objectFit: 'cover' }}
39 />
40 );
41 }
42
43 const paddedSize = parseInt(size) * 0.8 + 'px';
44 return <AttachFile sx={{ fontSize: paddedSize }} />;
45};
46
47interface FilePreviewInfosProps {
48 fileHandler: FileHandler;
49}
50
51const FilePreviewInfos = ({ fileHandler }: FilePreviewInfosProps) => {
52 const file = fileHandler.file;
53 const fileSize = useDataSizeUnits(file.size);
54 const fileType = mime.getExtension(file.type)?.toUpperCase() || '';
55 return (
56 <Stack overflow="hidden">
57 <Typography variant="body1" fontWeight="bold" overflow="hidden" textOverflow="ellipsis" whiteSpace="nowrap">
58 {file.name}
59 </Typography>
60 <Typography variant="body1">{`${fileType} ${fileSize}`}</Typography>
61 </Stack>
62 );
63};
64
65const RemoveButton = (props: IconButtonProps) => {
66 const removeButtonSize = '24px';
67 const paddingPart = 0.25;
68 return (
69 <IconButton
70 {...props}
71 aria-label="remove file"
72 disableRipple={true}
73 sx={{
74 position: 'absolute',
75 height: removeButtonSize,
76 width: removeButtonSize,
77 right: -parseInt(removeButtonSize) * paddingPart + 'px',
78 top: -parseInt(removeButtonSize) * paddingPart + 'px',
79 fontSize: parseInt(removeButtonSize) * paddingPart * 2 + 'px',
80 color: 'black',
81 backgroundColor: 'white',
82 borderRadius: '100%',
83 boxShadow: '3px 3px 7px #00000029',
84 '&:hover': {
85 background: (theme) => theme.palette.primary.light,
86 },
87 }}
88 >
89 <SaltireIcon fontSize="inherit" />
90 </IconButton>
91 );
92};
93
94interface FilePreviewDeletableProps {
95 fileHandler: FileHandler;
96 remove: () => void;
97 borderColor: string;
98}
99
100export const FilePreviewRemovable = ({ fileHandler, remove, borderColor }: FilePreviewDeletableProps) => {
101 const linkRef = useRef<HTMLAnchorElement>(null);
102 const iconSize = '57px';
103
104 return (
105 <Stack
106 direction="row"
107 sx={{
108 flex: '1 1 200px',
109 minWidth: '100px',
110 maxWidth: '300px',
111 cursor: 'pointer',
112 }}
113 onClick={() => linkRef.current?.click()}
114 >
115 <a ref={linkRef} href={fileHandler.url} download hidden />
116 <Stack
117 sx={{
118 position: 'relative',
119 height: iconSize,
120 width: iconSize,
121 minWidth: iconSize,
122 marginRight: '16px',
123 borderRadius: '5px',
124 borderWidth: '3px',
125 borderColor: borderColor,
126 borderStyle: 'solid',
127 justifyContent: 'center',
128 alignItems: 'center',
129 }}
130 >
131 <RemoveButton
132 onClick={(e) => {
133 // Prevent the parent's link to be triggered
134 e.preventDefault();
135 e.stopPropagation();
136 remove();
137 }}
138 />
139 <FilePreviewIcon fileHandler={fileHandler} size={iconSize} />
140 </Stack>
141 <FilePreviewInfos fileHandler={fileHandler} />
142 </Stack>
143 );
144};