strapi-plugin-payone-provider 5.6.13 → 5.6.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/admin/src/index.js +14 -20
- package/admin/src/pages/App/components/AppHeader.jsx +16 -17
- package/admin/src/pages/App/components/AppTabs.jsx +14 -15
- package/admin/src/pages/App/components/ApplePayBtn.jsx +9 -14
- package/admin/src/pages/App/components/ApplePayConfig.jsx +25 -26
- package/admin/src/pages/App/components/ApplePayConfigPanel.jsx +4 -4
- package/admin/src/pages/App/components/DocsPanel.jsx +8 -21
- package/admin/src/pages/App/components/GooglePayConfig.jsx +16 -14
- package/admin/src/pages/App/components/GooglePayConfigPanel.jsx +4 -4
- package/admin/src/pages/App/components/GooglePaybutton.jsx +6 -5
- package/admin/src/pages/App/components/configuration/ConfigurationFields.jsx +39 -47
- package/admin/src/pages/App/components/configuration/ConfigurationPanel.jsx +5 -4
- package/admin/src/pages/App/components/configuration/TestConnection.jsx +19 -36
- package/admin/src/pages/App/components/payment-actions/ApplePayPanel.jsx +4 -4
- package/admin/src/pages/App/components/payment-actions/AuthorizationForm.jsx +12 -19
- package/admin/src/pages/App/components/payment-actions/CaptureForm.jsx +15 -23
- package/admin/src/pages/App/components/payment-actions/CardDetailsInput.jsx +20 -19
- package/admin/src/pages/App/components/payment-actions/PaymentActionsPanel.jsx +13 -24
- package/admin/src/pages/App/components/payment-actions/PaymentMethodSelector.jsx +8 -6
- package/admin/src/pages/App/components/payment-actions/PaymentResult.jsx +6 -10
- package/admin/src/pages/App/components/payment-actions/PreauthorizationForm.jsx +12 -19
- package/admin/src/pages/App/components/payment-actions/RefundForm.jsx +15 -22
- package/admin/src/pages/App/components/transaction-history/FiltersPanel.jsx +83 -84
- package/admin/src/pages/App/components/transaction-history/HistoryPanel.jsx +7 -17
- package/admin/src/pages/App/components/transaction-history/ImportExportBar.jsx +153 -0
- package/admin/src/pages/App/components/transaction-history/TransactionTable.jsx +22 -15
- package/admin/src/pages/hooks/usePluginTranslations.js +12 -0
- package/admin/src/pages/utils/api.js +27 -0
- package/admin/src/translations/de.json +235 -0
- package/admin/src/translations/en.json +235 -0
- package/admin/src/translations/fr.json +235 -0
- package/admin/src/translations/ru.json +235 -0
- package/admin/src/utils/prefixPluginTranslations.js +13 -0
- package/package.json +2 -2
- package/server/controllers/payone.js +70 -0
- package/server/routes/index.js +16 -0
- package/server/services/payone.js +8 -0
- package/server/services/transactionService.js +80 -1
- package/server/utils/csvTransactions.js +82 -0
|
@@ -1,8 +1,12 @@
|
|
|
1
|
-
import
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Box } from "@strapi/design-system";
|
|
2
3
|
import RenderInput from "../RenderInput";
|
|
3
|
-
import {
|
|
4
|
+
import { usePluginTranslations } from "../../../hooks/usePluginTranslations";
|
|
5
|
+
import ImportExportBar from "./ImportExportBar";
|
|
6
|
+
|
|
7
|
+
const FiltersPanel = ({ filters, handleFiltersChange , loadTransactionHistory}) => {
|
|
8
|
+
const { t } = usePluginTranslations();
|
|
4
9
|
|
|
5
|
-
const FiltersPanel = ({ filters, handleFiltersChange }) => {
|
|
6
10
|
const handleReset = () => {
|
|
7
11
|
handleFiltersChange({
|
|
8
12
|
search: "",
|
|
@@ -14,73 +18,72 @@ const FiltersPanel = ({ filters, handleFiltersChange }) => {
|
|
|
14
18
|
});
|
|
15
19
|
};
|
|
16
20
|
|
|
17
|
-
const filterOptions =
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
"Search by reference or transaction ID to filter transactions",
|
|
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
|
-
];
|
|
21
|
+
const filterOptions = React.useMemo(
|
|
22
|
+
() => [
|
|
23
|
+
{
|
|
24
|
+
name: "search",
|
|
25
|
+
label: t("filters.search", "Search"),
|
|
26
|
+
type: "text",
|
|
27
|
+
inputType: "textInput",
|
|
28
|
+
placeholder: t("filters.searchPlaceholder", "Search by reference or transaction ID"),
|
|
29
|
+
tooltipContent: t("filters.searchTooltip", "Search by reference or transaction ID to filter transactions"),
|
|
30
|
+
flex: 1,
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: "status",
|
|
34
|
+
label: t("filters.status", "Status"),
|
|
35
|
+
type: "enumeration",
|
|
36
|
+
inputType: "select",
|
|
37
|
+
placeholder: "",
|
|
38
|
+
tooltipContent: t("filters.statusTooltip", "Filter transactions by their status (Approved, Error, Redirect, Invalid, Pending, Cancelled)"),
|
|
39
|
+
options: [
|
|
40
|
+
{ value: "", label: t("filters.allStatuses", "All Statuses") },
|
|
41
|
+
{ value: "APPROVED", label: t("status.approved", "Approved") },
|
|
42
|
+
{ value: "ERROR", label: t("status.error", "Error") },
|
|
43
|
+
{ value: "REDIRECT", label: t("status.redirect", "Redirect") },
|
|
44
|
+
{ value: "INVALID", label: t("status.invalid", "Invalid") },
|
|
45
|
+
{ value: "PENDING", label: t("status.pending", "Pending") },
|
|
46
|
+
{ value: "CANCELLED", label: t("status.cancelled", "Cancelled") },
|
|
47
|
+
],
|
|
48
|
+
flex: 1,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: "request_type",
|
|
52
|
+
label: t("filters.requestType", "Request Type"),
|
|
53
|
+
type: "enumeration",
|
|
54
|
+
inputType: "select",
|
|
55
|
+
placeholder: t("filters.allTypes", "All Types"),
|
|
56
|
+
tooltipContent: t("filters.requestTypeTooltip", "Filter transactions by request type (Preauthorization, Authorization, Capture, Refund)"),
|
|
57
|
+
options: [
|
|
58
|
+
{ value: "", label: t("filters.allTypes", "All Types") },
|
|
59
|
+
{ value: "preauthorization", label: t("requestType.preauthorization", "Preauthorization") },
|
|
60
|
+
{ value: "authorization", label: t("requestType.authorization", "Authorization") },
|
|
61
|
+
{ value: "capture", label: t("requestType.capture", "Capture") },
|
|
62
|
+
{ value: "refund", label: t("requestType.refund", "Refund") },
|
|
63
|
+
],
|
|
64
|
+
flex: 1,
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
name: "payment_method",
|
|
68
|
+
label: t("filters.paymentMethod", "Payment Method"),
|
|
69
|
+
type: "enumeration",
|
|
70
|
+
inputType: "select",
|
|
71
|
+
placeholder: t("filters.allMethods", "All Methods"),
|
|
72
|
+
tooltipContent: t("filters.paymentMethodTooltip", "Filter transactions by payment method (Credit Card, PayPal, Google Pay, Apple Pay, Sofort Banking, SEPA Direct Debit)"),
|
|
73
|
+
options: [
|
|
74
|
+
{ value: "", label: t("filters.allMethods", "All Methods") },
|
|
75
|
+
{ value: "credit_card", label: t("paymentMethod.creditCard", "Credit Card") },
|
|
76
|
+
{ value: "paypal", label: t("paymentMethod.paypal", "PayPal") },
|
|
77
|
+
{ value: "google_pay", label: t("paymentMethod.googlePay", "Google Pay") },
|
|
78
|
+
{ value: "apple_pay", label: t("paymentMethod.applePay", "Apple Pay") },
|
|
79
|
+
{ value: "sofort", label: t("paymentMethod.sofort", "Sofort Banking") },
|
|
80
|
+
{ value: "sepa", label: t("paymentMethod.sepa", "SEPA Direct Debit") },
|
|
81
|
+
],
|
|
82
|
+
flex: 1,
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
[t]
|
|
86
|
+
);
|
|
84
87
|
|
|
85
88
|
return (
|
|
86
89
|
<Box
|
|
@@ -88,7 +91,7 @@ const FiltersPanel = ({ filters, handleFiltersChange }) => {
|
|
|
88
91
|
display: "grid",
|
|
89
92
|
gridTemplateColumns: "repeat(auto-fit, minmax(220px, 1fr))",
|
|
90
93
|
gap: "16px",
|
|
91
|
-
alignItems:
|
|
94
|
+
alignItems:"start"
|
|
92
95
|
}}
|
|
93
96
|
>
|
|
94
97
|
{filterOptions.map((filter) => (
|
|
@@ -117,8 +120,8 @@ const FiltersPanel = ({ filters, handleFiltersChange }) => {
|
|
|
117
120
|
value={filters.date_from || ""}
|
|
118
121
|
onChange={(e) => handleFiltersChange({ date_from: e.target.value })}
|
|
119
122
|
inputType="dateInput"
|
|
120
|
-
label="Date From"
|
|
121
|
-
tooltipContent="Filter transactions from this date onwards. Select the starting date for the date range filter."
|
|
123
|
+
label={t("filters.dateFrom", "Date From")}
|
|
124
|
+
tooltipContent={t("filters.dateFromTooltip", "Filter transactions from this date onwards. Select the starting date for the date range filter.")}
|
|
122
125
|
/>
|
|
123
126
|
|
|
124
127
|
<RenderInput
|
|
@@ -126,19 +129,15 @@ const FiltersPanel = ({ filters, handleFiltersChange }) => {
|
|
|
126
129
|
value={filters.date_to || ""}
|
|
127
130
|
onChange={(e) => handleFiltersChange({ date_to: e.target.value })}
|
|
128
131
|
inputType="dateInput"
|
|
129
|
-
label="Date To"
|
|
130
|
-
tooltipContent="Filter transactions up to this date. Select the ending date for the date range filter."
|
|
132
|
+
label={t("filters.dateTo", "Date To")}
|
|
133
|
+
tooltipContent={t("filters.dateToTooltip", "Filter transactions up to this date. Select the ending date for the date range filter.")}
|
|
131
134
|
/>
|
|
132
135
|
|
|
133
|
-
<
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
maxWidth="100px"
|
|
139
|
-
>
|
|
140
|
-
Reset
|
|
141
|
-
</Button>
|
|
136
|
+
<ImportExportBar
|
|
137
|
+
filters={filters}
|
|
138
|
+
handleReset={handleReset}
|
|
139
|
+
onImportDone={loadTransactionHistory}
|
|
140
|
+
/>
|
|
142
141
|
</Box>
|
|
143
142
|
);
|
|
144
143
|
};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import * as React from "react";
|
|
2
2
|
import { Box, Flex, Typography, Divider } from "@strapi/design-system";
|
|
3
3
|
import TransactionTable from "./TransactionTable";
|
|
4
|
+
import { usePluginTranslations } from "../../../hooks/usePluginTranslations";
|
|
4
5
|
|
|
5
6
|
const HistoryPanel = () => {
|
|
7
|
+
const { t } = usePluginTranslations();
|
|
6
8
|
return (
|
|
7
9
|
<Box
|
|
8
10
|
className="payment-container"
|
|
@@ -13,21 +15,11 @@ const HistoryPanel = () => {
|
|
|
13
15
|
>
|
|
14
16
|
<Flex direction="column" alignItems="stretch" gap={8}>
|
|
15
17
|
<Box>
|
|
16
|
-
<Typography
|
|
17
|
-
|
|
18
|
-
as="h2"
|
|
19
|
-
className="payment-title"
|
|
20
|
-
style={{ fontSize: "20px", marginBottom: "4px" }}
|
|
21
|
-
>
|
|
22
|
-
Transaction Management
|
|
18
|
+
<Typography variant="beta" as="h2" className="payment-title" style={{ fontSize: "20px", marginBottom: "4px" }}>
|
|
19
|
+
{t("history.title", "Transaction Management")}
|
|
23
20
|
</Typography>
|
|
24
|
-
<Typography
|
|
25
|
-
|
|
26
|
-
textColor="neutral600"
|
|
27
|
-
className="payment-subtitle"
|
|
28
|
-
style={{ fontSize: "14px", marginTop: "4px" }}
|
|
29
|
-
>
|
|
30
|
-
View and filter all payment transactions processed through Payone
|
|
21
|
+
<Typography variant="pi" textColor="neutral600" className="payment-subtitle" style={{ fontSize: "14px", marginTop: "4px" }}>
|
|
22
|
+
{t("history.subtitle", "View and filter all payment transactions processed through Payone")}
|
|
31
23
|
</Typography>
|
|
32
24
|
</Box>
|
|
33
25
|
|
|
@@ -37,9 +29,7 @@ const HistoryPanel = () => {
|
|
|
37
29
|
|
|
38
30
|
<Box paddingTop={4}>
|
|
39
31
|
<Typography variant="sigma" textColor="neutral600">
|
|
40
|
-
|
|
41
|
-
plugin. Transactions are automatically logged with detailed
|
|
42
|
-
request/response data.
|
|
32
|
+
{t("history.note", "This shows all Payone transactions processed through this plugin. Transactions are automatically logged with detailed request/response data.")}
|
|
43
33
|
</Typography>
|
|
44
34
|
</Box>
|
|
45
35
|
</Flex>
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import { Box, Button, Flex } from "@strapi/design-system";
|
|
3
|
+
import { ArrowsCounterClockwise, Download, Upload } from "@strapi/icons";
|
|
4
|
+
import { useNotification } from "@strapi/strapi/admin";
|
|
5
|
+
import { usePluginTranslations } from "../../../hooks/usePluginTranslations";
|
|
6
|
+
import usePayoneRequests from "../../../utils/api";
|
|
7
|
+
|
|
8
|
+
const ImportExportBar = ({ filters, sortBy = "createdAt", sortOrder = "desc", onImportDone, handleReset }) => {
|
|
9
|
+
const { t } = usePluginTranslations();
|
|
10
|
+
const { toggleNotification } = useNotification();
|
|
11
|
+
const { exportTransactions, importTransactions } = usePayoneRequests();
|
|
12
|
+
const [exporting, setExporting] = React.useState(false);
|
|
13
|
+
const [importing, setImporting] = React.useState(false);
|
|
14
|
+
const fileInputRef = React.useRef(null);
|
|
15
|
+
|
|
16
|
+
const handleExport = async (format) => {
|
|
17
|
+
setExporting(true);
|
|
18
|
+
try {
|
|
19
|
+
const res = await exportTransactions({
|
|
20
|
+
format,
|
|
21
|
+
filters,
|
|
22
|
+
sort_by: sortBy,
|
|
23
|
+
sort_order: sortOrder,
|
|
24
|
+
});
|
|
25
|
+
const blob = res?.data ?? res;
|
|
26
|
+
if (!(blob instanceof Blob)) {
|
|
27
|
+
throw new Error("Invalid export response");
|
|
28
|
+
}
|
|
29
|
+
const url = URL.createObjectURL(blob);
|
|
30
|
+
const a = document.createElement("a");
|
|
31
|
+
a.href = url;
|
|
32
|
+
a.download = `transactions.${format}`;
|
|
33
|
+
a.click();
|
|
34
|
+
URL.revokeObjectURL(url);
|
|
35
|
+
toggleNotification({ type: "success", message: t("export.success", "Export completed") });
|
|
36
|
+
} catch (err) {
|
|
37
|
+
console.error("Export failed:", err);
|
|
38
|
+
toggleNotification({ type: "danger", message: t("export.error", "Export failed") });
|
|
39
|
+
} finally {
|
|
40
|
+
setExporting(false);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const handleImportClick = () => {
|
|
45
|
+
fileInputRef.current?.click();
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const handleImportFile = async (e) => {
|
|
49
|
+
const file = e.target.files?.[0];
|
|
50
|
+
if (!file) return;
|
|
51
|
+
setImporting(true);
|
|
52
|
+
try {
|
|
53
|
+
const text = await new Promise((resolve, reject) => {
|
|
54
|
+
const r = new FileReader();
|
|
55
|
+
r.onload = () => resolve(r.result ?? "");
|
|
56
|
+
r.onerror = reject;
|
|
57
|
+
r.readAsText(file, "utf-8");
|
|
58
|
+
});
|
|
59
|
+
const ext = (file.name || "").toLowerCase();
|
|
60
|
+
let payload;
|
|
61
|
+
if (ext.endsWith(".csv")) {
|
|
62
|
+
payload = { format: "csv", data: text };
|
|
63
|
+
} else {
|
|
64
|
+
const parsed = JSON.parse(text);
|
|
65
|
+
payload = Array.isArray(parsed) ? parsed : (parsed?.data ?? []);
|
|
66
|
+
if (!Array.isArray(payload)) payload = [];
|
|
67
|
+
payload = { data: payload };
|
|
68
|
+
}
|
|
69
|
+
const res = await importTransactions(payload);
|
|
70
|
+
const data = res?.data ?? res;
|
|
71
|
+
const imported = data?.imported ?? 0;
|
|
72
|
+
const failed = data?.failed ?? 0;
|
|
73
|
+
if (typeof onImportDone === "function") onImportDone();
|
|
74
|
+
if (failed > 0) {
|
|
75
|
+
toggleNotification({
|
|
76
|
+
type: "warning",
|
|
77
|
+
message: t("import.partial", "Import completed: {{imported}} imported, {{failed}} failed.", { imported, failed }),
|
|
78
|
+
});
|
|
79
|
+
} else {
|
|
80
|
+
toggleNotification({
|
|
81
|
+
type: "success",
|
|
82
|
+
message: t("import.success", "Imported transactions.", { count: imported }),
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
} catch (err) {
|
|
86
|
+
console.error("Import failed:", err);
|
|
87
|
+
toggleNotification({ type: "danger", message: t("import.error", "Import failed") });
|
|
88
|
+
} finally {
|
|
89
|
+
setImporting(false);
|
|
90
|
+
e.target.value = "";
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
return (
|
|
95
|
+
<Flex gap={2} width={"100%"}>
|
|
96
|
+
<Box>
|
|
97
|
+
<Button
|
|
98
|
+
variant="secondary"
|
|
99
|
+
size="S"
|
|
100
|
+
startIcon={<Download />}
|
|
101
|
+
loading={exporting}
|
|
102
|
+
onClick={() => handleExport("json")}
|
|
103
|
+
minWidth={"140px"}
|
|
104
|
+
>
|
|
105
|
+
{t("export.json", "Export JSON")}
|
|
106
|
+
</Button>
|
|
107
|
+
</Box>
|
|
108
|
+
{/* <Box>
|
|
109
|
+
<Button
|
|
110
|
+
variant="secondary"
|
|
111
|
+
size="S"
|
|
112
|
+
startIcon={<Download />}
|
|
113
|
+
loading={exporting}
|
|
114
|
+
onClick={() => handleExport("csv")}
|
|
115
|
+
minWidth={"140px"}
|
|
116
|
+
>
|
|
117
|
+
{t("export.csv", "Export CSV")}
|
|
118
|
+
</Button>
|
|
119
|
+
</Box> */}
|
|
120
|
+
<Box>
|
|
121
|
+
<input
|
|
122
|
+
ref={fileInputRef}
|
|
123
|
+
type="file"
|
|
124
|
+
accept=".json,.csv,application/json,text/csv"
|
|
125
|
+
style={{ display: "none" }}
|
|
126
|
+
onChange={handleImportFile}
|
|
127
|
+
/>
|
|
128
|
+
<Button
|
|
129
|
+
variant="secondary"
|
|
130
|
+
size="S"
|
|
131
|
+
startIcon={<Upload/>}
|
|
132
|
+
loading={importing}
|
|
133
|
+
minWidth={"140px"}
|
|
134
|
+
onClick={handleImportClick}
|
|
135
|
+
>
|
|
136
|
+
{t("import.button", "Import")}
|
|
137
|
+
</Button>
|
|
138
|
+
</Box>
|
|
139
|
+
|
|
140
|
+
<Button
|
|
141
|
+
variant="secondary"
|
|
142
|
+
onClick={handleReset}
|
|
143
|
+
startIcon={<ArrowsCounterClockwise />}
|
|
144
|
+
size="S"
|
|
145
|
+
maxWidth="100px"
|
|
146
|
+
>
|
|
147
|
+
{t("filters.reset", "Reset")}
|
|
148
|
+
</Button>
|
|
149
|
+
</Flex>
|
|
150
|
+
);
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
export default ImportExportBar;
|
|
@@ -11,8 +11,10 @@ import TransactionDetails from "./details/TransactionDetails";
|
|
|
11
11
|
import FiltersPanel from "./FiltersPanel";
|
|
12
12
|
import useTransactionHistory from "../../../hooks/useTransactionHistory";
|
|
13
13
|
import StatusBadge from "../StatusBadge";
|
|
14
|
+
import { usePluginTranslations } from "../../../hooks/usePluginTranslations";
|
|
14
15
|
|
|
15
16
|
const TransactionTable = () => {
|
|
17
|
+
const { t } = usePluginTranslations();
|
|
16
18
|
const {
|
|
17
19
|
transactions,
|
|
18
20
|
isLoadingHistory,
|
|
@@ -21,25 +23,30 @@ const TransactionTable = () => {
|
|
|
21
23
|
filters,
|
|
22
24
|
handleFiltersChange,
|
|
23
25
|
pagination,
|
|
26
|
+
loadTransactionHistory,
|
|
24
27
|
} = useTransactionHistory();
|
|
25
28
|
|
|
26
|
-
const headers =
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
29
|
+
const headers = React.useMemo(
|
|
30
|
+
() => [
|
|
31
|
+
{ name: "txid", label: t("table.txid", "TxId") },
|
|
32
|
+
{ name: "reference", label: t("table.reference", "Reference") },
|
|
33
|
+
{ name: "amount", label: t("table.amount", "Amount") },
|
|
34
|
+
{ name: "paymentMethod", label: t("table.paymentMethod", "Payment Method") },
|
|
35
|
+
{ name: "type", label: t("table.type", "Type") },
|
|
36
|
+
{ name: "status", label: t("table.status", "Status") },
|
|
37
|
+
{ name: "created_at", label: t("table.createdAt", "Created At") },
|
|
38
|
+
{ name: "updated_at", label: t("table.updatedAt", "Updated At") },
|
|
39
|
+
{ name: "details", label: t("table.details", "Details") },
|
|
40
|
+
],
|
|
41
|
+
[t]
|
|
42
|
+
);
|
|
37
43
|
|
|
38
44
|
return (
|
|
39
45
|
<Flex direction="column" alignItems="stretch" gap={4} minHeight={"800px"}>
|
|
40
46
|
<FiltersPanel
|
|
41
47
|
filters={filters}
|
|
42
48
|
handleFiltersChange={handleFiltersChange}
|
|
49
|
+
loadTransactionHistory={loadTransactionHistory}
|
|
43
50
|
/>
|
|
44
51
|
|
|
45
52
|
<Box>
|
|
@@ -69,12 +76,12 @@ const TransactionTable = () => {
|
|
|
69
76
|
<Table.Row>
|
|
70
77
|
<Table.Cell>
|
|
71
78
|
<Typography variant="pi" textColor="neutral600">
|
|
72
|
-
{transaction.txid || "N/A"}
|
|
79
|
+
{transaction.txid || t("table.na", "N/A")}
|
|
73
80
|
</Typography>
|
|
74
81
|
</Table.Cell>
|
|
75
82
|
<Table.Cell>
|
|
76
83
|
<Typography variant="pi" fontWeight="medium">
|
|
77
|
-
{transaction.reference || "N/A"}
|
|
84
|
+
{transaction.reference || t("table.na", "N/A")}
|
|
78
85
|
</Typography>
|
|
79
86
|
</Table.Cell>
|
|
80
87
|
<Table.Cell>
|
|
@@ -95,7 +102,7 @@ const TransactionTable = () => {
|
|
|
95
102
|
</Table.Cell>
|
|
96
103
|
<Table.Cell>
|
|
97
104
|
<Typography variant="pi" fontWeight="semiBold">
|
|
98
|
-
{transaction.request_type || "N/A"}
|
|
105
|
+
{transaction.request_type || t("table.na", "N/A")}
|
|
99
106
|
</Typography>
|
|
100
107
|
</Table.Cell>
|
|
101
108
|
<Table.Cell>
|
|
@@ -125,7 +132,7 @@ const TransactionTable = () => {
|
|
|
125
132
|
)
|
|
126
133
|
}
|
|
127
134
|
>
|
|
128
|
-
{isSelected ? "Hide" : "Details"}
|
|
135
|
+
{isSelected ? t("table.hide", "Hide") : t("table.details", "Details")}
|
|
129
136
|
</Button>
|
|
130
137
|
</Table.Cell>
|
|
131
138
|
</Table.Row>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin translations. Uses react-intl from Strapi admin (do NOT install react-intl).
|
|
3
|
+
*/
|
|
4
|
+
import { useIntl } from 'react-intl';
|
|
5
|
+
import pluginId from '../../pluginId';
|
|
6
|
+
|
|
7
|
+
export function usePluginTranslations() {
|
|
8
|
+
const { formatMessage } = useIntl();
|
|
9
|
+
const t = (id, defaultMessage = '') =>
|
|
10
|
+
formatMessage({ id: `${pluginId}.${id}`, defaultMessage });
|
|
11
|
+
return { t, formatMessage };
|
|
12
|
+
}
|
|
@@ -37,6 +37,31 @@ const usePayoneRequests = () => {
|
|
|
37
37
|
);
|
|
38
38
|
};
|
|
39
39
|
|
|
40
|
+
const exportTransactions = (params = {}) => {
|
|
41
|
+
const queryParams = new URLSearchParams();
|
|
42
|
+
const format = params.format === "csv" ? "csv" : "json";
|
|
43
|
+
queryParams.append("format", format);
|
|
44
|
+
if (params.sort_by) queryParams.append("sort_by", params.sort_by);
|
|
45
|
+
if (params.sort_order) queryParams.append("sort_order", params.sort_order);
|
|
46
|
+
if (params.filters && typeof params.filters === "object") {
|
|
47
|
+
Object.keys(params.filters).forEach((key) => {
|
|
48
|
+
const value = params.filters[key];
|
|
49
|
+
const v = value == null ? "" : String(value).trim();
|
|
50
|
+
if (v !== "" && v.toLowerCase() !== "all") {
|
|
51
|
+
queryParams.append(`filters[${key}]`, String(value));
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
const queryString = queryParams.toString();
|
|
56
|
+
return get(`/${pluginId}/transactions/export?${queryString}`);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const importTransactions = (payload) => {
|
|
60
|
+
return post(`/${pluginId}/transactions/import`, payload, {
|
|
61
|
+
headers: { "Content-Type": "application/json" },
|
|
62
|
+
});
|
|
63
|
+
};
|
|
64
|
+
|
|
40
65
|
const testConnection = () =>
|
|
41
66
|
post(`/${pluginId}/test-connection`);
|
|
42
67
|
|
|
@@ -59,6 +84,8 @@ const usePayoneRequests = () => {
|
|
|
59
84
|
getSettings,
|
|
60
85
|
updateSettings,
|
|
61
86
|
getTransactionHistory,
|
|
87
|
+
exportTransactions,
|
|
88
|
+
importTransactions,
|
|
62
89
|
testConnection,
|
|
63
90
|
preauthorization,
|
|
64
91
|
authorization,
|