diff --git a/package-lock.json b/package-lock.json index 1e2c7061..e9be2eb4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -26,6 +26,7 @@ "js-cookie": "^3.0.5", "lightweight-charts": "^4.1.3", "next": "^14.1.1", + "papaparse": "^5.4.1", "postcss": "^8.4.32", "react": "^18.2.0", "react-dom": "18.2.0", @@ -42,6 +43,7 @@ "@testing-library/react": "^14.2.2", "@types/big.js": "^6.2.2", "@types/js-cookie": "^3.0.6", + "@types/papaparse": "^5.3.14", "@typescript-eslint/eslint-plugin": "^5.60.1", "@typescript-eslint/parser": "^5.60.1", "@vitejs/plugin-react": "^4.2.1", @@ -1898,6 +1900,15 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.3.3.tgz", "integrity": "sha512-wheIYdr4NYML61AjC8MKj/2jrR/kDQri/CIpVoZwldwhnIrD/j9jIU5bJ8yBKuB2VhpFV7Ab6G2XkBjv9r9Zzw==" }, + "node_modules/@types/papaparse": { + "version": "5.3.14", + "resolved": "https://registry.npmjs.org/@types/papaparse/-/papaparse-5.3.14.tgz", + "integrity": "sha512-LxJ4iEFcpqc6METwp9f6BV6VVc43m6MfH0VqFosHvrUgfXiFe6ww7R3itkOQ+TCK6Y+Iv/+RnnvtRZnkc5Kc9g==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/prop-types": { "version": "15.7.5", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", @@ -7342,6 +7353,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/papaparse": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/papaparse/-/papaparse-5.4.1.tgz", + "integrity": "sha512-HipMsgJkZu8br23pW15uvo6sib6wne/4woLZPlFf3rpDyMe9ywEXUsuD7+6K9PRkJlVT51j/sCOYDKGGS3ZJrw==" + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", diff --git a/package.json b/package.json index df11b90e..82f09c86 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "js-cookie": "^3.0.5", "lightweight-charts": "^4.1.3", "next": "^14.1.1", + "papaparse": "^5.4.1", "postcss": "^8.4.32", "react": "^18.2.0", "react-dom": "18.2.0", @@ -49,6 +50,7 @@ "@testing-library/react": "^14.2.2", "@types/big.js": "^6.2.2", "@types/js-cookie": "^3.0.6", + "@types/papaparse": "^5.3.14", "@typescript-eslint/eslint-plugin": "^5.60.1", "@typescript-eslint/parser": "^5.60.1", "@vitejs/plugin-react": "^4.2.1", diff --git a/src/app/components/AccountHistory.tsx b/src/app/components/AccountHistory.tsx index aa634525..3f587af7 100644 --- a/src/app/components/AccountHistory.tsx +++ b/src/app/components/AccountHistory.tsx @@ -27,6 +27,7 @@ import { calculateAvgFilled, calculateTotalFees, } from "../utils"; +import Papa from "papaparse"; function createOrderReceiptAddressLookup( pairsList: PairInfo[] @@ -237,7 +238,22 @@ function DisplayTable() { ))} - {tableToShow.rows} + + {tableToShow.rows} + {selectedTable === Tables.ORDER_HISTORY && ( + + + + + {headers[Tables.ORDER_HISTORY].slice(1).map((_, index) => ( + + ))} + + + + + )} + ); @@ -540,3 +556,58 @@ const OrderHistoryRow = ({ order }: { order: any }) => { ); }; + +const ExportCsvButton = () => { + const { orderHistory } = useAppSelector((state) => state.accountHistory); + + const handleExport = () => { + try { + const formatedOrderHistory = orderHistory.map((order) => { + return { + ...order, + specifiedToken: order.specifiedToken.symbol, + unclaimedToken: order.unclaimedToken.symbol, + }; + }); + + // Convert orderHistory array to CSV format + const csv = Papa.unparse(formatedOrderHistory); + + // Create a blob from the CSV data + const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" }); + + // Create a link element and trigger the download + const link = document.createElement("a"); + if (link.download !== undefined) { + const url = URL.createObjectURL(blob); + link.setAttribute("href", url); + const filename = `dexter-order-history-${ + new Date().toISOString().split("T")[0] + }.csv`; + link.setAttribute("download", filename); + document.body.appendChild(link); + link.click(); + document.body.removeChild(link); + } + } catch (error) { + // TODO: add toast notification ? + console.error("Error exporting CSV:", error); + } + }; + + // do not display the button if orderHistory is empty + if (!orderHistory || orderHistory.length === 0) { + return null; + } + + return ( + + ); +}; + +export default ExportCsvButton;