-
Notifications
You must be signed in to change notification settings - Fork 11
Expand file tree
/
Copy pathExportButton.js
More file actions
119 lines (113 loc) · 3.54 KB
/
ExportButton.js
File metadata and controls
119 lines (113 loc) · 3.54 KB
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
import React from 'react'
import {
Button,
ButtonGroup,
Flex,
FocusLock,
FormControl,
FormLabel,
Input,
Stack,
Text,
useDisclosure,
} from '@chakra-ui/react'
import { arrayOf, object, string, func } from 'prop-types'
import { json2csvAsync } from 'json-2-csv'
import { t } from "@lingui/core/macro"
import { Trans } from "@lingui/react/macro"
import { any } from 'prop-types'
import { Popover, PopoverTrigger, PopoverContent, PopoverArrow, PopoverCloseButton } from '@chakra-ui/react'
import { ABTestWrapper, ABTestVariant } from '../app/ABTestWrapper'
export function ExportButton({ jsonData, fileName, dataFunction, children = t`Export to CSV`, ...props }) {
const { onOpen, onClose, isOpen } = useDisclosure()
const firstFieldRef = React.useRef(null)
function sanitizeFileName(name) {
// Remove invalid characters
let sanitized = name.replace(/[/\\:*?"<>|]+/g, '')
// Trim whitespace and limit length
sanitized = sanitized.trim().substring(0, 100)
// Fallback to default if empty
return sanitized || fileName
}
const download = async (name) => {
try {
let data
if (jsonData) {
data = await json2csvAsync(jsonData)
} else if (dataFunction) {
data = await dataFunction()
}
const sanitizedName = sanitizeFileName(name)
const a = document.createElement('a')
a.href = 'data:text/csv;charset=utf-8,' + encodeURI(data)
a.download = `${sanitizedName}.csv`
document.body.appendChild(a)
a.click()
document.body.removeChild(a)
onClose()
} catch (err) {
console.log(err)
}
}
return (
<ABTestWrapper insiderVariantName="B">
<ABTestVariant name="A">
<Button {...props} variant="primary" onClick={() => download(fileName)}>
{children}
</Button>
</ABTestVariant>
<ABTestVariant name="B">
<Popover
isOpen={isOpen}
initialFocusRef={firstFieldRef}
onOpen={onOpen}
onClose={onClose}
placement="right"
closeOnBlur={false}
>
<PopoverTrigger>
<Button {...props} variant="primary">
{children}
</Button>
</PopoverTrigger>
<PopoverContent p={5}>
<FocusLock returnFocus persistentFocus={false}>
<PopoverArrow />
<PopoverCloseButton />
<Stack spacing={4}>
<FormControl>
<FormLabel htmlFor="file-name">
<Trans>File name:</Trans>
</FormLabel>
<Flex align="center">
<Input ref={firstFieldRef} id="file-name" defaultValue={fileName} mr="1" />
<Text>.csv</Text>
</Flex>
</FormControl>
<ButtonGroup display="flex" justifyContent="flex-end">
<Button variant="outline" onClick={onClose}>
<Trans>Cancel</Trans>
</Button>
<Button
variant="primary"
onClick={() => {
download(firstFieldRef.current?.value || fileName)
}}
>
<Trans>Download</Trans>
</Button>
</ButtonGroup>
</Stack>
</FocusLock>
</PopoverContent>
</Popover>
</ABTestVariant>
</ABTestWrapper>
)
}
ExportButton.propTypes = {
jsonData: arrayOf(object),
fileName: string,
dataFunction: func,
children: any,
}