/
File.tsx
163 lines (152 loc) · 5.03 KB
/
File.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
import * as React from "react";
import { useState } from "react";
import Stack from "@mui/material/Stack";
import TextField from "@mui/material/TextField";
import IconButton from "@mui/material/IconButton";
import InputAdornment from "@mui/material/InputAdornment";
import CloseIcon from "@mui/icons-material/Close";
import ActionButton from "../../../../ActionButton";
import { IFileSlot } from "../../../slots/FileSlot";
import { useOnePayload } from "../../../context/PayloadProvider";
import { useOneState } from "../../../context/StateProvider";
import chooseFile from "../../../../../utils/chooseFile";
import openBlank from "../../../../../utils/openBlank";
const LOADING_LABEL = "Loading";
/**
* FileField component is a form field for selecting and displaying a file.
*
* @param props - The input props for the FileField component.
* @param props.invalid - Defines if the file is invalid.
* @param props.incorrect - Defines if the file is incorrect.
* @param props.value - The current value of the file field.
* @param props.disabled - Defines if the file field is disabled.
* @param props.readonly - Defines if the file field is read-only.
* @param props.description - The description or helper text of the file field.
* @param props.outlined - Defines if the file field is outlined.
* @param props.labelShrink - Defines if the label should shrink.
* @param props.title - The title or label of the file field.
* @param props.placeholder - The placeholder for the file field.
* @param props.dirty - Defines if the file field has been changed.
* @param props.loading - Defines if the file field is in loading state.
* @param props.inputRef - A ref to the file field's input element.
* @param props.onChange - The callback function called when the file value changes.
* @param props.fileAccept - The accepted file types for file selection.
* @param props.name - The name of the file field.
* @param props.upload - The function called when a file is uploaded.
* The function takes a file as input and returns the uploaded file's name.
* @param props.view - The function called when the file is viewed.
* The function takes the file path as input.
* @returns - Returns the JSX element of the FileField component.
*/
export const FileField = ({
invalid,
incorrect,
value,
disabled,
readonly,
description = "",
outlined = false,
labelShrink,
title = "",
placeholder = "No file chosen",
dirty,
loading: upperLoading,
inputRef,
onChange,
fileAccept,
name,
upload = (file) => {
if (file instanceof File) {
return file.name;
}
return name;
},
view = (filePath) => {
openBlank(filePath);
},
}: IFileSlot) => {
const [currentLoading, setCurrentLoading] = useState(false);
const payload = useOnePayload();
const { object } = useOneState();
const loading = upperLoading || currentLoading;
return (
<Stack
direction="row"
alignItems={outlined ? "stretch" : "center"}
spacing={1}
>
<TextField
sx={{
flex: 1,
...(!outlined && {
position: "relative",
mt: 1,
"& .MuiFormHelperText-root": {
position: "absolute",
top: "100%",
},
}),
}}
inputRef={inputRef}
variant={outlined ? "outlined" : "standard"}
helperText={(dirty && (invalid || incorrect)) || description}
error={dirty && (invalid !== null || incorrect !== null)}
InputProps={{
readOnly: readonly,
endAdornment: (
<InputAdornment sx={{ position: "relative" }} position="end">
<IconButton
edge="end"
disabled={disabled || !value}
onClick={() => {
onChange(null);
}}
>
<CloseIcon />
</IconButton>
</InputAdornment>
),
}}
InputLabelProps={
labelShrink
? {
shrink: labelShrink,
}
: undefined
}
value={loading ? LOADING_LABEL : value ? String(value) : ""}
placeholder={placeholder}
label={title}
disabled={disabled}
/>
{!!value && (
<ActionButton
variant="outlined"
onLoadStart={() => setCurrentLoading(true)}
onLoadEnd={() => setCurrentLoading(false)}
onClick={async () => {
await view(value, object, payload);
}}
>
View
</ActionButton>
)}
<ActionButton
variant="outlined"
onLoadStart={() => setCurrentLoading(true)}
onLoadEnd={() => setCurrentLoading(false)}
onClick={async () => {
const fileBlob = await chooseFile(fileAccept);
if (fileBlob) {
const fileName = await upload(fileBlob, object, payload);
onChange(fileName);
}
}}
>
{loading && "Uploading"}
{!loading && "Choose"}
</ActionButton>
</Stack>
);
};
export default FileField;