payment-kit 1.18.2 → 1.18.4

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.
Files changed (44) hide show
  1. package/api/src/index.ts +4 -21
  2. package/api/src/libs/logger.ts +2 -1
  3. package/api/src/routes/checkout-sessions.ts +7 -7
  4. package/api/src/routes/customers.ts +6 -5
  5. package/api/src/routes/events.ts +3 -2
  6. package/api/src/routes/invoices.ts +4 -3
  7. package/api/src/routes/payment-currencies.ts +2 -2
  8. package/api/src/routes/payment-intents.ts +6 -6
  9. package/api/src/routes/payment-links.ts +1 -1
  10. package/api/src/routes/payment-stats.ts +3 -2
  11. package/api/src/routes/payouts.ts +6 -5
  12. package/api/src/routes/pricing-table.ts +2 -2
  13. package/api/src/routes/settings.ts +251 -2
  14. package/api/src/routes/subscription-items.ts +3 -3
  15. package/api/src/routes/subscriptions.ts +15 -15
  16. package/api/src/routes/usage-records.ts +2 -2
  17. package/api/src/routes/webhook-attempts.ts +2 -1
  18. package/api/src/routes/webhook-endpoints.ts +3 -2
  19. package/api/src/store/migrations/20250211-setting.ts +10 -0
  20. package/api/src/store/migrations/20250214-setting-component.ts +22 -0
  21. package/api/src/store/models/index.ts +6 -1
  22. package/api/src/store/models/setting.ts +84 -0
  23. package/api/src/store/models/types.ts +2 -0
  24. package/blocklet.yml +13 -1
  25. package/package.json +24 -24
  26. package/src/app.tsx +6 -1
  27. package/src/components/invoice/list.tsx +1 -3
  28. package/src/components/payment-intent/list.tsx +5 -6
  29. package/src/components/payouts/list.tsx +3 -3
  30. package/src/components/refund/list.tsx +3 -6
  31. package/src/components/subscription/list.tsx +1 -2
  32. package/src/locales/en.tsx +100 -1
  33. package/src/locales/zh.tsx +96 -0
  34. package/src/pages/admin/customers/customers/index.tsx +27 -16
  35. package/src/pages/admin/developers/webhooks/index.tsx +14 -12
  36. package/src/pages/admin/products/links/index.tsx +22 -15
  37. package/src/pages/admin/products/pricing-tables/index.tsx +16 -14
  38. package/src/pages/admin/products/products/index.tsx +19 -15
  39. package/src/pages/home.tsx +1 -1
  40. package/src/pages/integrations/donations/edit-form.tsx +349 -0
  41. package/src/pages/integrations/donations/index.tsx +360 -0
  42. package/src/pages/integrations/donations/preview.tsx +229 -0
  43. package/src/pages/integrations/index.tsx +80 -0
  44. package/src/pages/integrations/overview.tsx +121 -0
@@ -10,7 +10,7 @@ export default flat({
10
10
  add: 'Add more metadata',
11
11
  edit: 'Edit metadata',
12
12
  empty: 'No metadata',
13
- emptyTip: 'You havent added any metadata you can add it',
13
+ emptyTip: "You haven't added any metadata you can add it",
14
14
  },
15
15
  price: 'Price',
16
16
  add: 'Add',
@@ -27,6 +27,16 @@ export default flat({
27
27
  custom: 'Custom',
28
28
  estimatedDuration: '{duration} est.',
29
29
  detail: 'Detail',
30
+ setting: 'Setting',
31
+ welcome: 'Welcome to Payment Kit',
32
+ welcomeDesc: 'Start accepting payments in minutes with Payment Kit. Choose a feature to get started.',
33
+ quickStart: 'Quick Start Guides',
34
+ advancedFeatures: 'Advanced Features',
35
+ quickStarts: 'Quick Starts',
36
+ copy: 'Copy',
37
+ copySuccess: 'Copy Success',
38
+ copyFailed: 'Copy Failed',
39
+ copyTip: 'Please copy manually',
30
40
  },
31
41
  admin: {
32
42
  balances: 'Balances',
@@ -645,6 +655,64 @@ export default flat({
645
655
  quantity: 'Quantity',
646
656
  },
647
657
  },
658
+ donate: {
659
+ title: 'Donation Settings',
660
+ mountLocation: 'Mount Location',
661
+ component: 'Component',
662
+ description: 'Description',
663
+ status: {
664
+ title: 'Status',
665
+ active: 'Enable',
666
+ inactive: 'Disable',
667
+ inactiveTip:
668
+ 'After disabling donations, the donation button will no longer be displayed and users cannot use the donation feature. Are you sure you want to disable it?',
669
+ inactiveTitle: 'Disable Donation',
670
+ activeSuccess: 'Donation feature has been enabled',
671
+ inactiveSuccess: 'Donation feature has been disabled',
672
+ },
673
+ editTitle: 'Edit Donation Settings',
674
+ updateSuccess: 'Donation settings have been updated',
675
+ amountSettings: 'Amount Settings',
676
+ presets: 'Preset Amounts',
677
+ presetsHelper: 'Enter preset amounts, separated by commas (e.g., 1,5,10)',
678
+ preset: 'Default Amount',
679
+ presetHelper: 'Default selected amount (must be one of the presets)',
680
+ custom: 'Allow Custom Amount',
681
+ minimum: 'Minimum Amount',
682
+ maximum: 'Maximum Amount',
683
+ amountRange: 'Amount Range: {min} - {max}',
684
+ customAmount: 'Custom Amount',
685
+ buttonSettings: 'Donation Button Settings',
686
+ btn: {
687
+ text: 'Button Text',
688
+ helper: 'Set the text displayed on the donation button',
689
+ preview: 'Button Preview',
690
+ },
691
+ dialog: {
692
+ preview: 'Donation Dialog Preview',
693
+ confirmButton: 'Confirm Donation {amount}',
694
+ },
695
+ previewTitle: 'Live Preview',
696
+ validation: {
697
+ invalidPreset: 'Default amount must be one of the presets',
698
+ invalidRange: 'Minimum amount must be less than maximum amount',
699
+ invalidAmount: 'Amount must be within allowed range',
700
+ },
701
+ historyType: {
702
+ title: 'Donation History Display',
703
+ avatar: 'Avatar Wall',
704
+ list: 'List',
705
+ },
706
+ intro:
707
+ 'Configure the display effect of the donation button and donation dialog, and the donation feature will take effect after completion.',
708
+ usage: {
709
+ viewExample: 'View Usage Example',
710
+ title: 'Donation Component Usage Example',
711
+ description:
712
+ 'To use the donation feature, you need to correctly configure PaymentProvider and DonateProvider in the component. Here is a basic example:',
713
+ note: 'Note: mountLocation must be unique, used to identify the donation instance. After configuration, the instance will appear in the list, and you can make further settings.',
714
+ },
715
+ },
648
716
  },
649
717
  empty: {
650
718
  image: 'No Image',
@@ -746,4 +814,35 @@ export default flat({
746
814
  title: 'Revenue',
747
815
  },
748
816
  },
817
+ integrations: {
818
+ basicFeatures: 'Basic Features',
819
+ advancedFeatures: 'Advanced Features',
820
+ features: {
821
+ products: {
822
+ title: 'Create Products',
823
+ intro: 'Create and manage your products or services',
824
+ },
825
+ paymentLinks: {
826
+ title: 'Payment Links',
827
+ intro: 'Create shareable payment links for quick checkout',
828
+ },
829
+ pricingTables: {
830
+ title: 'Pricing Tables',
831
+ intro: 'Create beautiful pricing tables for your products',
832
+ },
833
+ donate: {
834
+ title: 'Donation',
835
+ intro: 'Add donation button to your application with <CheckoutDonate />',
836
+ },
837
+ paymentMethods: {
838
+ title: 'Payment Methods',
839
+ intro: 'Configure multiple payment methods and currencies',
840
+ },
841
+ api: {
842
+ title: 'API Integration',
843
+ intro: 'Integrate with our JavaScript SDK for custom solutions',
844
+ link: 'https://www.npmjs.com/package/@blocklet/payment-js',
845
+ },
846
+ },
847
+ },
749
848
  });
@@ -26,6 +26,16 @@ export default flat({
26
26
  custom: '自定义',
27
27
  estimatedDuration: '预计可用 {duration}',
28
28
  detail: '详情',
29
+ setting: '配置',
30
+ welcome: '欢迎使用 Payment Kit',
31
+ welcomeDesc: '从基础功能开始,轻松接入支付功能。选择下方任意功能,立即开始使用。',
32
+ quickStart: '快速入门指南',
33
+ advancedFeatures: '高级功能',
34
+ quickStarts: '快速入门',
35
+ copy: '复制',
36
+ copySuccess: '复制成功',
37
+ copyFailed: '复制失败',
38
+ copyTip: '请手动复制',
29
39
  },
30
40
  admin: {
31
41
  balances: '余额',
@@ -631,6 +641,61 @@ export default flat({
631
641
  quantity: '数量',
632
642
  },
633
643
  },
644
+ donate: {
645
+ title: '打赏配置',
646
+ mountLocation: '名称',
647
+ component: '组件',
648
+ description: '描述',
649
+ status: {
650
+ title: '启用状态',
651
+ active: '启用',
652
+ inactive: '关闭',
653
+ inactiveTip: '关闭打赏后,打赏按钮将不再显示,用户无法使用打赏功能,请确认是否关闭?',
654
+ inactiveTitle: '关闭打赏',
655
+ activeSuccess: '打赏功能已启用',
656
+ inactiveSuccess: '打赏功能已关闭',
657
+ },
658
+ editTitle: '编辑打赏配置',
659
+ updateSuccess: '打赏配置已更新',
660
+ amountSettings: '金额设置',
661
+ presets: '预设金额',
662
+ presetsHelper: '请输入预设金额,用英文逗号分隔(例如:1,5,10)',
663
+ preset: '默认金额',
664
+ presetHelper: '默认选中的金额(必须是预设金额之一)',
665
+ custom: '允许自定义金额',
666
+ minimum: '最小金额',
667
+ maximum: '最大金额',
668
+ amountRange: '金额范围:{min} - {max}',
669
+ customAmount: '自定义金额',
670
+ buttonSettings: '打赏按钮设置',
671
+ btn: {
672
+ text: '按钮文本',
673
+ helper: '设置打赏按钮显示的文字',
674
+ preview: '按钮预览',
675
+ },
676
+ dialog: {
677
+ preview: '打赏弹窗预览',
678
+ confirmButton: '确认打赏 {amount}',
679
+ },
680
+ previewTitle: '实时预览',
681
+ validation: {
682
+ invalidPreset: '默认金额必须是预设金额之一',
683
+ invalidRange: '最小金额必须小于最大金额',
684
+ invalidAmount: '金额必须在允许范围内',
685
+ },
686
+ historyType: {
687
+ title: '打赏记录显示方式',
688
+ avatar: '头像墙',
689
+ list: '列表',
690
+ },
691
+ intro: '配置打赏按钮和打赏弹窗的展示效果,完成配置后打赏功能将自动生效。',
692
+ usage: {
693
+ viewExample: '查看使用示例',
694
+ title: '打赏组件使用示例',
695
+ description: '要使用打赏功能,您需要先在组件中正确配置 PaymentProvider 和 DonateProvider。以下是一个基本示例:',
696
+ note: '注意:mountLocation 必须是唯一的,用于标识打赏实例。配置完成后,该实例将出现在列表中,您可以进行进一步的设置。',
697
+ },
698
+ },
634
699
  },
635
700
  empty: {
636
701
  image: '无图片',
@@ -727,4 +792,35 @@ export default flat({
727
792
  title: '收款记录',
728
793
  },
729
794
  },
795
+ integrations: {
796
+ basicFeatures: '基础功能',
797
+ advancedFeatures: '高级功能',
798
+ features: {
799
+ products: {
800
+ title: '创建产品',
801
+ intro: '创建和管理您的产品或服务',
802
+ },
803
+ paymentLinks: {
804
+ title: '支付链接',
805
+ intro: '创建可分享的支付链接,快速完成收款',
806
+ },
807
+ pricingTables: {
808
+ title: '定价表',
809
+ intro: '为您的产品创建美观的定价表',
810
+ },
811
+ donate: {
812
+ title: '打赏功能',
813
+ intro: '使用 <CheckoutDonate /> 组件为应用添加打赏按钮',
814
+ },
815
+ paymentMethods: {
816
+ title: '支付方式',
817
+ intro: '配置多种支付方式和货币支持',
818
+ },
819
+ api: {
820
+ title: 'API 集成',
821
+ intro: '使用我们的 JavaScript SDK 实现自定义解决方案',
822
+ link: 'https://www.npmjs.com/package/@blocklet/payment-js',
823
+ },
824
+ },
825
+ },
730
826
  });
@@ -5,6 +5,7 @@ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
5
5
  import { api, formatTime, getCustomerAvatar, Table } from '@blocklet/payment-react';
6
6
  import type { TCustomer } from '@blocklet/payment-types';
7
7
  import { Avatar, CircularProgress, Stack, Typography } from '@mui/material';
8
+ import { useLocalStorageState } from 'ahooks';
8
9
  import { useEffect, useState } from 'react';
9
10
  import { Link } from 'react-router-dom';
10
11
 
@@ -22,16 +23,25 @@ const fetchData = (params: Record<string, any> = {}): Promise<{ list: TCustomer[
22
23
  return api.get(`/api/customers?${search.toString()}`).then((res: any) => res.data);
23
24
  };
24
25
 
26
+ type SearchProps = {
27
+ active?: string;
28
+ pageSize: number;
29
+ page: number;
30
+ q?: any;
31
+ o?: string;
32
+ };
25
33
  export default function CustomersList() {
26
34
  const listKey = 'customers';
27
35
  const persisted = getDurableData(listKey);
28
36
 
29
37
  const { t } = useLocaleContext();
30
- const [search, setSearch] = useState<{ active?: string; pageSize: number; page: number; q?: any; o?: string }>({
31
- active: '',
32
- o: 'desc',
33
- pageSize: persisted.rowsPerPage || 20,
34
- page: persisted.page ? persisted.page + 1 : 1,
38
+ const [search, setSearch] = useLocalStorageState<SearchProps>(listKey, {
39
+ defaultValue: {
40
+ active: '',
41
+ o: 'desc',
42
+ pageSize: persisted.rowsPerPage || 20,
43
+ page: persisted.page ? persisted.page + 1 : 1,
44
+ },
35
45
  });
36
46
 
37
47
  const [data, setData] = useState({}) as any;
@@ -123,11 +133,11 @@ export default function CustomersList() {
123
133
  },
124
134
  ];
125
135
 
126
- const onTableChange = ({ page, rowsPerPage }: any) => {
127
- if (search.pageSize !== rowsPerPage) {
128
- setSearch((x) => ({ ...x, pageSize: rowsPerPage, page: 1 }));
129
- } else if (search.page !== page + 1) {
130
- setSearch((x) => ({ ...x, page: page + 1 }));
136
+ const onTableChange = ({ page, rowsPerPage }: { page: number; rowsPerPage: number }) => {
137
+ if (search!.pageSize !== rowsPerPage) {
138
+ setSearch((x: any) => ({ ...x, pageSize: rowsPerPage, page: 1 }));
139
+ } else if (search!.page !== page + 1) {
140
+ setSearch((x: any) => ({ ...x, page: page + 1 }));
131
141
  }
132
142
  };
133
143
 
@@ -140,18 +150,19 @@ export default function CustomersList() {
140
150
  columns={columns}
141
151
  options={{
142
152
  count: data.count,
143
- page: search.page - 1,
144
- rowsPerPage: search.pageSize,
153
+ page: search!.page - 1,
154
+ rowsPerPage: search!.pageSize,
145
155
  onColumnSortChange(_: any, order: any) {
146
156
  setSearch({
147
- ...search,
148
- q: search.q || {},
157
+ ...search!,
158
+ q: search!.q || {},
149
159
  o: order,
150
160
  });
151
161
  },
152
162
  onSearchChange: (text: string) => {
153
163
  if (text) {
154
164
  setSearch({
165
+ ...search!,
155
166
  q: {
156
167
  'like-name': text,
157
168
  'like-email': text,
@@ -161,13 +172,13 @@ export default function CustomersList() {
161
172
  },
162
173
  pageSize: 100,
163
174
  page: 1,
164
- active: '',
165
175
  });
166
176
  } else {
167
177
  setSearch({
168
- active: '',
178
+ ...search!,
169
179
  pageSize: 100,
170
180
  page: 1,
181
+ q: {},
171
182
  });
172
183
  }
173
184
  },
@@ -4,8 +4,8 @@ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
4
4
  import { Status, api, formatTime, Table } from '@blocklet/payment-react';
5
5
  import type { TWebhookEndpoint } from '@blocklet/payment-types';
6
6
  import { Alert, CircularProgress, Typography } from '@mui/material';
7
- import { useRequest } from 'ahooks';
8
- import { useEffect, useState } from 'react';
7
+ import { useLocalStorageState, useRequest } from 'ahooks';
8
+ import { useEffect } from 'react';
9
9
  import { useNavigate } from 'react-router-dom';
10
10
 
11
11
  import { useTransitionContext } from '../../../../components/progress-bar';
@@ -26,10 +26,12 @@ export default function WebhooksList() {
26
26
  const { t } = useLocaleContext();
27
27
  const navigate = useNavigate();
28
28
  const { startTransition } = useTransitionContext();
29
- const [search, setSearch] = useState<{ active: string; pageSize: number; page: number }>({
30
- active: '',
31
- pageSize: persisted.rowsPerPage || 20,
32
- page: persisted.page ? persisted.page + 1 : 1,
29
+ const [search, setSearch] = useLocalStorageState<{ active: string; pageSize: number; page: number }>(listKey, {
30
+ defaultValue: {
31
+ active: '',
32
+ pageSize: persisted.rowsPerPage || 20,
33
+ page: persisted.page ? persisted.page + 1 : 1,
34
+ },
33
35
  });
34
36
 
35
37
  const { loading, error, data, refresh } = useRequest(() => fetchData(search));
@@ -72,10 +74,10 @@ export default function WebhooksList() {
72
74
  ];
73
75
 
74
76
  const onTableChange = ({ page, rowsPerPage }: any) => {
75
- if (search.pageSize !== rowsPerPage) {
76
- setSearch((x) => ({ ...x, pageSize: rowsPerPage, page: 1 }));
77
- } else if (search.page !== page + 1) {
78
- setSearch((x) => ({ ...x, page: page + 1 }));
77
+ if (search!.pageSize !== rowsPerPage) {
78
+ setSearch((x: any) => ({ ...x, pageSize: rowsPerPage, page: 1 }));
79
+ } else if (search!.page !== page + 1) {
80
+ setSearch((x: any) => ({ ...x, page: page + 1 }));
79
81
  }
80
82
  };
81
83
 
@@ -87,8 +89,8 @@ export default function WebhooksList() {
87
89
  columns={columns}
88
90
  options={{
89
91
  count: data.count,
90
- page: search.page - 1,
91
- rowsPerPage: search.pageSize,
92
+ page: search!.page - 1,
93
+ rowsPerPage: search!.pageSize,
92
94
  onRowClick: (_: any, { dataIndex }: any) => {
93
95
  const item = data.list[dataIndex] as TWebhookEndpoint;
94
96
  startTransition(() => {
@@ -4,8 +4,8 @@ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
4
4
  import { Status, api, formatTime, usePaymentContext, Table, findCurrency } from '@blocklet/payment-react';
5
5
  import type { TPaymentLinkExpanded } from '@blocklet/payment-types';
6
6
  import { Alert, CircularProgress, ToggleButton, ToggleButtonGroup, Typography } from '@mui/material';
7
- import { useRequest } from 'ahooks';
8
- import { useEffect, useState } from 'react';
7
+ import { useLocalStorageState, useRequest } from 'ahooks';
8
+ import { useEffect } from 'react';
9
9
  import { Link } from 'react-router-dom';
10
10
  import { joinURL } from 'ufo';
11
11
  import useBus from 'use-bus';
@@ -29,11 +29,18 @@ function PaymentLinks() {
29
29
  const { settings } = usePaymentContext();
30
30
 
31
31
  const persisted = getDurableData(listKey);
32
- const [search, setSearch] = useState<{ active: string; pageSize: number; page: number; donation?: string }>({
33
- active: '',
34
- pageSize: persisted.rowsPerPage || 20,
35
- page: persisted.page ? persisted.page + 1 : 1,
36
- donation: 'hide',
32
+ const [search, setSearch] = useLocalStorageState<{
33
+ active: string;
34
+ pageSize: number;
35
+ page: number;
36
+ donation?: string;
37
+ }>(listKey, {
38
+ defaultValue: {
39
+ active: '',
40
+ pageSize: persisted.rowsPerPage || 20,
41
+ page: persisted.page ? persisted.page + 1 : 1,
42
+ donation: 'hide',
43
+ },
37
44
  });
38
45
 
39
46
  const { loading, error, data, refresh } = useRequest(() => fetchData(search));
@@ -128,10 +135,10 @@ function PaymentLinks() {
128
135
  ];
129
136
 
130
137
  const onTableChange = ({ page, rowsPerPage }: any) => {
131
- if (search.pageSize !== rowsPerPage) {
132
- setSearch((x) => ({ ...x, pageSize: rowsPerPage, page: 1 }));
133
- } else if (search.page !== page + 1) {
134
- setSearch((x) => ({ ...x, page: page + 1 }));
138
+ if (search!.pageSize !== rowsPerPage) {
139
+ setSearch((x: any) => ({ ...x, pageSize: rowsPerPage, page: 1 }));
140
+ } else if (search!.page !== page + 1) {
141
+ setSearch((x: any) => ({ ...x, page: page + 1 }));
135
142
  }
136
143
  };
137
144
 
@@ -143,10 +150,10 @@ function PaymentLinks() {
143
150
  title={
144
151
  <div className="table-toolbar-left">
145
152
  <ToggleButtonGroup
146
- value={search.active}
153
+ value={search!.active}
147
154
  onChange={(_, value) => {
148
155
  if (value !== null) {
149
- setSearch((x) => ({ ...x, active: value }));
156
+ setSearch((x: any) => ({ ...x, active: value }));
150
157
  }
151
158
  }}
152
159
  exclusive>
@@ -160,8 +167,8 @@ function PaymentLinks() {
160
167
  columns={columns}
161
168
  options={{
162
169
  count: data.count,
163
- page: search.page - 1,
164
- rowsPerPage: search.pageSize,
170
+ page: search!.page - 1,
171
+ rowsPerPage: search!.pageSize,
165
172
  }}
166
173
  loading={loading}
167
174
  onChange={onTableChange}
@@ -4,8 +4,8 @@ import { useLocaleContext } from '@arcblock/ux/lib/Locale/context';
4
4
  import { Status, api, formatTime, Table } from '@blocklet/payment-react';
5
5
  import type { TPricingTableExpanded } from '@blocklet/payment-types';
6
6
  import { Alert, CircularProgress, ToggleButton, ToggleButtonGroup, Typography } from '@mui/material';
7
- import { useRequest } from 'ahooks';
8
- import { useEffect, useState } from 'react';
7
+ import { useLocalStorageState, useRequest } from 'ahooks';
8
+ import { useEffect } from 'react';
9
9
  import { Link } from 'react-router-dom';
10
10
  import { joinURL } from 'ufo';
11
11
  import useBus from 'use-bus';
@@ -27,10 +27,12 @@ function PricingTables() {
27
27
  const { t } = useLocaleContext();
28
28
 
29
29
  const persisted = getDurableData(listKey);
30
- const [search, setSearch] = useState<{ active: string; pageSize: number; page: number }>({
31
- active: '',
32
- pageSize: persisted.rowsPerPage || 20,
33
- page: persisted.page ? persisted.page + 1 : 1,
30
+ const [search, setSearch] = useLocalStorageState<{ active: string; pageSize: number; page: number }>(listKey, {
31
+ defaultValue: {
32
+ active: '',
33
+ pageSize: persisted.rowsPerPage || 20,
34
+ page: persisted.page ? persisted.page + 1 : 1,
35
+ },
34
36
  });
35
37
 
36
38
  const { loading, error, data, refresh } = useRequest(() => fetchData(search));
@@ -113,10 +115,10 @@ function PricingTables() {
113
115
  ];
114
116
 
115
117
  const onTableChange = ({ page, rowsPerPage }: any) => {
116
- if (search.pageSize !== rowsPerPage) {
117
- setSearch((x) => ({ ...x, pageSize: rowsPerPage, page: 1 }));
118
- } else if (search.page !== page + 1) {
119
- setSearch((x) => ({ ...x, page: page + 1 }));
118
+ if (search!.pageSize !== rowsPerPage) {
119
+ setSearch((x: any) => ({ ...x, pageSize: rowsPerPage, page: 1 }));
120
+ } else if (search!.page !== page + 1) {
121
+ setSearch((x: any) => ({ ...x, page: page + 1 }));
120
122
  }
121
123
  };
122
124
 
@@ -128,10 +130,10 @@ function PricingTables() {
128
130
  title={
129
131
  <div className="table-toolbar-left">
130
132
  <ToggleButtonGroup
131
- value={search.active}
133
+ value={search!.active}
132
134
  onChange={(_, value) => {
133
135
  if (value !== null) {
134
- setSearch((x) => ({ ...x, active: value }));
136
+ setSearch((x: any) => ({ ...x, active: value }));
135
137
  }
136
138
  }}
137
139
  exclusive>
@@ -145,8 +147,8 @@ function PricingTables() {
145
147
  columns={columns}
146
148
  options={{
147
149
  count: data.count,
148
- page: search.page - 1,
149
- rowsPerPage: search.pageSize,
150
+ page: search!.page - 1,
151
+ rowsPerPage: search!.pageSize,
150
152
  }}
151
153
  loading={loading}
152
154
  onChange={onTableChange}
@@ -8,6 +8,7 @@ import { useEffect, useState } from 'react';
8
8
  import { Link } from 'react-router-dom';
9
9
  import useBus from 'use-bus';
10
10
 
11
+ import { useLocalStorageState } from 'ahooks';
11
12
  import FilterToolbar from '../../../../components/filter-toolbar';
12
13
  import InfoCard from '../../../../components/info-card';
13
14
  import ProductActions from '../../../../components/product/actions';
@@ -43,11 +44,13 @@ export default function ProductsList() {
43
44
 
44
45
  const { t, locale } = useLocaleContext();
45
46
  const { settings } = usePaymentContext();
46
- const [search, setSearch] = useState<SearchProps>({
47
- active: '',
48
- pageSize: persisted.rowsPerPage || 20,
49
- page: persisted.page ? persisted.page + 1 : 1,
50
- donation: 'hide',
47
+ const [search, setSearch] = useLocalStorageState<SearchProps>(listKey, {
48
+ defaultValue: {
49
+ active: '',
50
+ pageSize: persisted.rowsPerPage || 20,
51
+ page: persisted.page ? persisted.page + 1 : 1,
52
+ donation: 'hide',
53
+ },
51
54
  });
52
55
 
53
56
  const [data, setData] = useState({}) as any;
@@ -142,10 +145,10 @@ export default function ProductsList() {
142
145
  ];
143
146
 
144
147
  const onTableChange = ({ page, rowsPerPage }: any) => {
145
- if (search.pageSize !== rowsPerPage) {
146
- setSearch((x) => ({ ...x, pageSize: rowsPerPage, page: 1 }));
147
- } else if (search.page !== page + 1) {
148
- setSearch((x) => ({ ...x, page: page + 1 }));
148
+ if (search!.pageSize !== rowsPerPage) {
149
+ setSearch((x: any) => ({ ...x, pageSize: rowsPerPage, page: 1 }));
150
+ } else if (search!.page !== page + 1) {
151
+ setSearch((x: any) => ({ ...x, page: page + 1 }));
149
152
  }
150
153
  };
151
154
  return (
@@ -165,31 +168,32 @@ export default function ProductsList() {
165
168
  columns={columns}
166
169
  options={{
167
170
  count: data.count,
168
- page: search.page - 1,
169
- rowsPerPage: search.pageSize,
171
+ page: search!.page - 1,
172
+ rowsPerPage: search!.pageSize,
170
173
  onColumnSortChange(_: any, order: any) {
171
174
  setSearch({
172
- ...search,
173
- q: search.q || {},
175
+ ...search!,
176
+ q: search!.q || {},
174
177
  o: order,
175
178
  });
176
179
  },
177
180
  onSearchChange: (text: string) => {
178
181
  if (text) {
179
182
  setSearch({
183
+ ...search!,
180
184
  q: {
181
185
  'like-description': text,
182
186
  'like-name': text,
183
187
  },
184
- active: '',
185
188
  pageSize: 100,
186
189
  page: 1,
187
190
  });
188
191
  } else {
189
192
  setSearch({
190
- active: '',
193
+ ...search!,
191
194
  pageSize: 100,
192
195
  page: 1,
196
+ q: {},
193
197
  });
194
198
  }
195
199
  },
@@ -36,7 +36,7 @@ function Home() {
36
36
  </Typography>
37
37
  </Stack>
38
38
  <Stack direction="row" spacing={3}>
39
- <Button variant="outlined" color="secondary" size="large" component={Link} to="/admin/overview">
39
+ <Button variant="outlined" color="secondary" size="large" component={Link} to="/integrations">
40
40
  Admin Dashboard
41
41
  </Button>
42
42
  <Button