stripe payment

master
alex 2024-02-17 15:19:49 +01:00
parent 91dce8da3d
commit c46ee6e5ea
16 changed files with 493 additions and 386 deletions

335
package-lock.json generated
View File

@ -16,7 +16,7 @@
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@yudiel/react-qr-scanner": "^1.1.10",
"antd": "^5.10.3",
"antd": "^5.14.1",
"buffer": "^6.0.3",
"i18next": "^23.2.3",
"i18next-browser-languagedetector": "^7.1.0",
@ -55,23 +55,23 @@
}
},
"node_modules/@ant-design/colors": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-7.0.0.tgz",
"integrity": "sha512-iVm/9PfGCbC0dSMBrz7oiEXZaaGH7ceU40OJEfKmyuzR9R5CRimJYPlRiFtMQGQcbNMea/ePcoIebi4ASGYXtg==",
"version": "7.0.2",
"resolved": "https://registry.npmjs.org/@ant-design/colors/-/colors-7.0.2.tgz",
"integrity": "sha512-7KJkhTiPiLHSu+LmMJnehfJ6242OCxSlR3xHVBecYxnMW8MS/878NXct1GqYARyL59fyeFdKRxXTfvR9SnDgJg==",
"dependencies": {
"@ctrl/tinycolor": "^3.4.0"
"@ctrl/tinycolor": "^3.6.1"
}
},
"node_modules/@ant-design/cssinjs": {
"version": "1.17.2",
"resolved": "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.17.2.tgz",
"integrity": "sha512-vu7lnfEx4Mf8MPzZxn506Zen3Nt4fRr2uutwvdCuTCN5IiU0lDdQ0tiJ24/rmB8+pefwjluYsbyzbQSbgfJy+A==",
"version": "1.18.4",
"resolved": "https://registry.npmjs.org/@ant-design/cssinjs/-/cssinjs-1.18.4.tgz",
"integrity": "sha512-IrUAOj5TYuMG556C9gdbFuOrigyhzhU5ZYpWb3gYTxAwymVqRbvLzFCZg6OsjLBR6GhzcxYF3AhxKmjB+rA2xA==",
"dependencies": {
"@babel/runtime": "^7.11.1",
"@emotion/hash": "^0.8.0",
"@emotion/unitless": "^0.7.5",
"classnames": "^2.3.1",
"csstype": "^3.0.10",
"csstype": "^3.1.3",
"rc-util": "^5.35.0",
"stylis": "^4.0.13"
},
@ -81,12 +81,12 @@
}
},
"node_modules/@ant-design/icons": {
"version": "5.2.6",
"resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.2.6.tgz",
"integrity": "sha512-4wn0WShF43TrggskBJPRqCD0fcHbzTYjnaoskdiJrVHg86yxoZ8ZUqsXvyn4WUqehRiFKnaclOhqk9w4Ui2KVw==",
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/@ant-design/icons/-/icons-5.3.0.tgz",
"integrity": "sha512-69FgBsIkeCjw72ZU3fJpqjhmLCPrzKGEllbrAZK7MUdt1BrKsyG6A8YDCBPKea27UQ0tRXi33PcjR4tp/tEXMg==",
"dependencies": {
"@ant-design/colors": "^7.0.0",
"@ant-design/icons-svg": "^4.3.0",
"@ant-design/icons-svg": "^4.4.0",
"@babel/runtime": "^7.11.2",
"classnames": "^2.2.6",
"rc-util": "^5.31.1"
@ -100,9 +100,9 @@
}
},
"node_modules/@ant-design/icons-svg": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.3.1.tgz",
"integrity": "sha512-4QBZg8ccyC6LPIRii7A0bZUk3+lEDCLnhB+FVsflGdcWPPmV+j3fire4AwwoqHV/BibgvBmR9ZIo4s867smv+g=="
"version": "4.4.2",
"resolved": "https://registry.npmjs.org/@ant-design/icons-svg/-/icons-svg-4.4.2.tgz",
"integrity": "sha512-vHbT+zJEVzllwP+CM+ul7reTEfBR0vgxFe7+lREAsAA7YGsYpboiq2sQNeQeRvh09GfQgs/GyFEvZpJ9cLXpXA=="
},
"node_modules/@ant-design/react-slick": {
"version": "1.0.2",
@ -1873,9 +1873,9 @@
"integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA=="
},
"node_modules/@babel/runtime": {
"version": "7.23.2",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz",
"integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==",
"version": "7.23.9",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz",
"integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==",
"dependencies": {
"regenerator-runtime": "^0.14.0"
},
@ -4724,14 +4724,14 @@
}
},
"node_modules/@rc-component/color-picker": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/@rc-component/color-picker/-/color-picker-1.4.1.tgz",
"integrity": "sha512-vh5EWqnsayZa/JwUznqDaPJz39jznx/YDbyBuVJntv735tKXKwEUZZb2jYEldOg+NKWZwtALjGMrNeGBmqFoEw==",
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/@rc-component/color-picker/-/color-picker-1.5.1.tgz",
"integrity": "sha512-onyAFhWKXuG4P162xE+7IgaJkPkwM94XlOYnQuu69XdXWMfxpeFi6tpJBsieIMV7EnyLV5J3lDzdLiFeK0iEBA==",
"dependencies": {
"@babel/runtime": "^7.10.1",
"@ctrl/tinycolor": "^3.6.0",
"@babel/runtime": "^7.23.6",
"@ctrl/tinycolor": "^3.6.1",
"classnames": "^2.2.6",
"rc-util": "^5.30.0"
"rc-util": "^5.38.1"
},
"peerDependencies": {
"react": ">=16.9.0",
@ -4797,9 +4797,9 @@
}
},
"node_modules/@rc-component/tour": {
"version": "1.10.0",
"resolved": "https://registry.npmjs.org/@rc-component/tour/-/tour-1.10.0.tgz",
"integrity": "sha512-voV0BKaTJbewB9LLgAHQ7tAGG7rgDkKQkZo82xw2gIk542hY+o7zwoqdN16oHhIKk7eG/xi+mdXrONT62Dt57A==",
"version": "1.12.3",
"resolved": "https://registry.npmjs.org/@rc-component/tour/-/tour-1.12.3.tgz",
"integrity": "sha512-U4mf1FiUxGCwrX4ed8op77Y8VKur+8Y/61ylxtqGbcSoh1EBC7bWd/DkLu0ClTUrKZInqEi1FL7YgFtnT90vHA==",
"dependencies": {
"@babel/runtime": "^7.18.0",
"@rc-component/portal": "^1.0.0-9",
@ -4816,9 +4816,9 @@
}
},
"node_modules/@rc-component/trigger": {
"version": "1.18.0",
"resolved": "https://registry.npmjs.org/@rc-component/trigger/-/trigger-1.18.0.tgz",
"integrity": "sha512-vloGnWpeTmt7DBw0OHnG9poQ8h1WFh0hebq6fpgVjGYSxm6JU8rLH+kNwVNNvhL6Rg5He4ESjOk6O7uF9dJhxA==",
"version": "1.18.3",
"resolved": "https://registry.npmjs.org/@rc-component/trigger/-/trigger-1.18.3.tgz",
"integrity": "sha512-Ksr25pXreYe1gX6ayZ1jLrOrl9OAUHUqnuhEx6MeHnNa1zVM5Y2Aj3Q35UrER0ns8D2cJYtmJtVli+i+4eKrvA==",
"dependencies": {
"@babel/runtime": "^7.23.2",
"@rc-component/portal": "^1.1.0",
@ -6751,57 +6751,56 @@
}
},
"node_modules/antd": {
"version": "5.10.3",
"resolved": "https://registry.npmjs.org/antd/-/antd-5.10.3.tgz",
"integrity": "sha512-IV+F4P9Fm0pXj4WFCLVLKIu7eCtVKZMLvU1a0HUIRBEy5YPsD5bDzjYkZ4F+RVPaFrAjAvChrWcX6NtQOVNuJw==",
"version": "5.14.1",
"resolved": "https://registry.npmjs.org/antd/-/antd-5.14.1.tgz",
"integrity": "sha512-P0Bwt9NKSZqnEJ0QAyAb13ay34FjOKsz+KEp/ts+feYsynhUxF7/Ay6d1jS6ZcNpcs+JWTlLKO59YFZ3tX07wQ==",
"dependencies": {
"@ant-design/colors": "^7.0.0",
"@ant-design/cssinjs": "^1.17.2",
"@ant-design/icons": "^5.2.6",
"@ant-design/colors": "^7.0.2",
"@ant-design/cssinjs": "^1.18.4",
"@ant-design/icons": "^5.3.0",
"@ant-design/react-slick": "~1.0.2",
"@babel/runtime": "^7.18.3",
"@ctrl/tinycolor": "^3.6.1",
"@rc-component/color-picker": "~1.4.1",
"@rc-component/color-picker": "~1.5.1",
"@rc-component/mutate-observer": "^1.1.0",
"@rc-component/tour": "~1.10.0",
"@rc-component/trigger": "^1.18.0",
"classnames": "^2.2.6",
"copy-to-clipboard": "^3.2.0",
"dayjs": "^1.11.1",
"@rc-component/tour": "~1.12.3",
"@rc-component/trigger": "^1.18.3",
"classnames": "^2.5.1",
"copy-to-clipboard": "^3.3.3",
"dayjs": "^1.11.10",
"qrcode.react": "^3.1.0",
"rc-cascader": "~3.18.1",
"rc-cascader": "~3.21.2",
"rc-checkbox": "~3.1.0",
"rc-collapse": "~3.7.1",
"rc-collapse": "~3.7.2",
"rc-dialog": "~9.3.4",
"rc-drawer": "~6.5.2",
"rc-drawer": "~7.0.0",
"rc-dropdown": "~4.1.0",
"rc-field-form": "~1.39.0",
"rc-image": "~7.3.1",
"rc-input": "~1.2.1",
"rc-input-number": "~8.1.0",
"rc-mentions": "~2.8.0",
"rc-menu": "~9.12.2",
"rc-field-form": "~1.41.0",
"rc-image": "~7.5.1",
"rc-input": "~1.4.3",
"rc-input-number": "~9.0.0",
"rc-mentions": "~2.10.1",
"rc-menu": "~9.12.4",
"rc-motion": "^2.9.0",
"rc-notification": "~5.3.0",
"rc-pagination": "~3.6.1",
"rc-picker": "~3.14.6",
"rc-pagination": "~4.0.4",
"rc-picker": "~4.1.1",
"rc-progress": "~3.5.1",
"rc-rate": "~2.12.0",
"rc-resize-observer": "^1.4.0",
"rc-segmented": "~2.2.2",
"rc-select": "~14.9.2",
"rc-slider": "~10.3.1",
"rc-segmented": "~2.3.0",
"rc-select": "~14.11.0",
"rc-slider": "~10.5.0",
"rc-steps": "~6.0.1",
"rc-switch": "~4.1.0",
"rc-table": "~7.34.4",
"rc-tabs": "~12.12.1",
"rc-textarea": "~1.4.0",
"rc-tooltip": "~6.1.2",
"rc-tree": "~5.7.12",
"rc-tree-select": "~5.13.0",
"rc-upload": "~4.3.5",
"rc-util": "^5.38.0",
"scroll-into-view-if-needed": "^3.0.3",
"rc-table": "~7.39.0",
"rc-tabs": "~14.0.0",
"rc-textarea": "~1.6.3",
"rc-tooltip": "~6.1.3",
"rc-tree": "~5.8.5",
"rc-tree-select": "~5.17.0",
"rc-upload": "~4.5.2",
"rc-util": "^5.38.1",
"scroll-into-view-if-needed": "^3.1.0",
"throttle-debounce": "^5.0.0"
},
"funding": {
@ -7823,9 +7822,9 @@
"integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA=="
},
"node_modules/classnames": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.2.tgz",
"integrity": "sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw=="
"version": "2.5.1",
"resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz",
"integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow=="
},
"node_modules/clean-css": {
"version": "5.3.2",
@ -8034,9 +8033,9 @@
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
},
"node_modules/compute-scroll-into-view": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.0.3.tgz",
"integrity": "sha512-nadqwNxghAGTamwIqQSG433W6OADZx2vCo3UXHNrzTRHK/htu+7+L0zhjEoaeaQVNAi3YgqWDv8+tzf0hRfR+A=="
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/compute-scroll-into-view/-/compute-scroll-into-view-3.1.0.tgz",
"integrity": "sha512-rj8l8pD4bJ1nx+dAkMhV1xB5RuZEyVysfxJqB1pRchh1KVvwOv9b7CGB8ZfjTImVv2oF+sYMUkMZq6Na5Ftmbg=="
},
"node_modules/concat-map": {
"version": "0.0.1",
@ -8577,9 +8576,9 @@
"integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg=="
},
"node_modules/csstype": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
"integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ=="
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
},
"node_modules/d": {
"version": "1.0.1",
@ -17932,16 +17931,16 @@
}
},
"node_modules/rc-cascader": {
"version": "3.18.1",
"resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.18.1.tgz",
"integrity": "sha512-M7Xr5Fs/E87ZGustfObtBYQjsvBCET0UX2JYXB2GmOP+2fsZgjaRGXK+CJBmmWXQ6o4OFinpBQBXG4wJOQ5MEg==",
"version": "3.21.2",
"resolved": "https://registry.npmjs.org/rc-cascader/-/rc-cascader-3.21.2.tgz",
"integrity": "sha512-J7GozpgsLaOtzfIHFJFuh4oFY0ePb1w10twqK6is3pAkqHkca/PsokbDr822KIRZ8/CK8CqevxohuPDVZ1RO/A==",
"dependencies": {
"@babel/runtime": "^7.12.5",
"array-tree-filter": "^2.1.0",
"classnames": "^2.3.1",
"rc-select": "~14.9.0",
"rc-tree": "~5.7.0",
"rc-util": "^5.35.0"
"rc-select": "~14.11.0",
"rc-tree": "~5.8.1",
"rc-util": "^5.37.0"
},
"peerDependencies": {
"react": ">=16.9.0",
@ -17963,9 +17962,9 @@
}
},
"node_modules/rc-collapse": {
"version": "3.7.1",
"resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.7.1.tgz",
"integrity": "sha512-N/7ejyiTf3XElNJBBpxqnZBUuMsQWEOPjB2QkfNvZ/Ca54eAvJXuOD1EGbCWCk2m7v/MSxku7mRpdeaLOCd4Gg==",
"version": "3.7.2",
"resolved": "https://registry.npmjs.org/rc-collapse/-/rc-collapse-3.7.2.tgz",
"integrity": "sha512-ZRw6ipDyOnfLFySxAiCMdbHtb5ePAsB9mT17PA6y1mRD/W6KHRaZeb5qK/X9xDV1CqgyxMpzw0VdS74PCcUk4A==",
"dependencies": {
"@babel/runtime": "^7.10.1",
"classnames": "2.x",
@ -17994,9 +17993,9 @@
}
},
"node_modules/rc-drawer": {
"version": "6.5.2",
"resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-6.5.2.tgz",
"integrity": "sha512-QckxAnQNdhh4vtmKN0ZwDf3iakO83W9eZcSKWYYTDv4qcD2fHhRAZJJ/OE6v2ZlQ2kSqCJX5gYssF4HJFvsEPQ==",
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/rc-drawer/-/rc-drawer-7.0.0.tgz",
"integrity": "sha512-ePcS4KtQnn57bCbVXazHN2iC8nTPCXlWEIA/Pft87Pd9U7ZeDkdRzG47jWG2/TAFXFlFltRAMcslqmUM8NPCGA==",
"dependencies": {
"@babel/runtime": "^7.10.1",
"@rc-component/portal": "^1.1.1",
@ -18025,9 +18024,9 @@
}
},
"node_modules/rc-field-form": {
"version": "1.39.0",
"resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.39.0.tgz",
"integrity": "sha512-V7Wk7uji1jBsUGGgP788H9rpFy55HLiD4lywTlktUGjK7EgW5dt+mq1MPbtCpPRMzs83vZBW4SOChOmCACz4WA==",
"version": "1.41.0",
"resolved": "https://registry.npmjs.org/rc-field-form/-/rc-field-form-1.41.0.tgz",
"integrity": "sha512-k9AS0wmxfJfusWDP/YXWTpteDNaQ4isJx9UKxx4/e8Dub4spFeZ54/EuN2sYrMRID/+hUznPgVZeg+Gf7XSYCw==",
"dependencies": {
"@babel/runtime": "^7.18.0",
"async-validator": "^4.1.0",
@ -18042,14 +18041,14 @@
}
},
"node_modules/rc-image": {
"version": "7.3.1",
"resolved": "https://registry.npmjs.org/rc-image/-/rc-image-7.3.1.tgz",
"integrity": "sha512-Tu3vcUyMHa6zxTiQRzHt1glbGwuNWzeQBG9O6qIdy/+1ue0Qb70it+jUct1YPVNkJa/QfaTfUhmsNsqrw7mgsg==",
"version": "7.5.1",
"resolved": "https://registry.npmjs.org/rc-image/-/rc-image-7.5.1.tgz",
"integrity": "sha512-Z9loECh92SQp0nSipc0MBuf5+yVC05H/pzC+Nf8xw1BKDFUJzUeehYBjaWlxly8VGBZJcTHYri61Fz9ng1G3Ag==",
"dependencies": {
"@babel/runtime": "^7.11.2",
"@rc-component/portal": "^1.0.2",
"classnames": "^2.2.6",
"rc-dialog": "~9.3.0",
"rc-dialog": "~9.3.4",
"rc-motion": "^2.6.2",
"rc-util": "^5.34.1"
},
@ -18059,9 +18058,9 @@
}
},
"node_modules/rc-input": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/rc-input/-/rc-input-1.2.1.tgz",
"integrity": "sha512-nQRmBvEFoGi+SNRDavccZ8ueyhFgmxkWqIt4aDyuNJgUZF12HJKIwDhAafUM7N+g7PyuW9FH3pf3zPHzdiCWbA==",
"version": "1.4.3",
"resolved": "https://registry.npmjs.org/rc-input/-/rc-input-1.4.3.tgz",
"integrity": "sha512-aHyQUAIRmTlOnvk5EcNqEpJ+XMtfMpYRAJayIlJfsvvH9cAKUWboh4egm23vgMA7E+c/qm4BZcnrDcA960GC1w==",
"dependencies": {
"@babel/runtime": "^7.11.1",
"classnames": "^2.2.1",
@ -18073,14 +18072,14 @@
}
},
"node_modules/rc-input-number": {
"version": "8.1.0",
"resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-8.1.0.tgz",
"integrity": "sha512-bdHgduOxuN0lrhzgPmoKbhRD4GLIzVcddVz972/JHPHr7oLwPX5xDb9w4bXhuMzyT2VzQy7nggRCfH3yAl09oA==",
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/rc-input-number/-/rc-input-number-9.0.0.tgz",
"integrity": "sha512-RfcDBDdWFFetouWFXBA+WPEC8LzBXyngr9b+yTLVIygfFu7HiLRGn/s/v9wwno94X7KFvnb28FNynMGj9XJlDQ==",
"dependencies": {
"@babel/runtime": "^7.10.1",
"@rc-component/mini-decimal": "^1.0.1",
"classnames": "^2.2.5",
"rc-input": "~1.2.1",
"rc-input": "~1.4.0",
"rc-util": "^5.28.0"
},
"peerDependencies": {
@ -18089,16 +18088,16 @@
}
},
"node_modules/rc-mentions": {
"version": "2.8.0",
"resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-2.8.0.tgz",
"integrity": "sha512-LBMkO6bSGhEvS1CvMK978qGN82tI+mzk7l/uTiQJH+UDiwpvq+pxK4DxU5b6Q1T5LW6bn2pSua9RaZKZrDoBOw==",
"version": "2.10.1",
"resolved": "https://registry.npmjs.org/rc-mentions/-/rc-mentions-2.10.1.tgz",
"integrity": "sha512-72qsEcr/7su+a07ndJ1j8rI9n0Ka/ngWOLYnWMMv0p2mi/5zPwPrEDTt6Uqpe8FWjWhueDJx/vzunL6IdKDYMg==",
"dependencies": {
"@babel/runtime": "^7.22.5",
"@rc-component/trigger": "^1.5.0",
"classnames": "^2.2.6",
"rc-input": "~1.2.1",
"rc-input": "~1.4.0",
"rc-menu": "~9.12.0",
"rc-textarea": "~1.4.0",
"rc-textarea": "~1.6.1",
"rc-util": "^5.34.1"
},
"peerDependencies": {
@ -18107,9 +18106,9 @@
}
},
"node_modules/rc-menu": {
"version": "9.12.2",
"resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.12.2.tgz",
"integrity": "sha512-NzloFH2pRUYmQ3S/YbJAvRkgCZaLvq0sRa5rgJtuIHLfPPprNHNyepeSlT64+dbVqI4qRWL44VN0lUCldCbbfg==",
"version": "9.12.4",
"resolved": "https://registry.npmjs.org/rc-menu/-/rc-menu-9.12.4.tgz",
"integrity": "sha512-t2NcvPLV1mFJzw4F21ojOoRVofK2rWhpKPx69q2raUsiHPDP6DDevsBILEYdsIegqBeSXoWs2bf6CueBKg3BFg==",
"dependencies": {
"@babel/runtime": "^7.10.1",
"@rc-component/trigger": "^1.17.0",
@ -18171,13 +18170,13 @@
}
},
"node_modules/rc-pagination": {
"version": "3.6.1",
"resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-3.6.1.tgz",
"integrity": "sha512-R/sUnKKXx1Nm4kZfUKS3YKa7yEPF1ZkVB/AynQaHt+nMER7h9wPTfliDJFdYo+RM/nk2JD4Yc5QpUq8fIQHeug==",
"version": "4.0.4",
"resolved": "https://registry.npmjs.org/rc-pagination/-/rc-pagination-4.0.4.tgz",
"integrity": "sha512-GGrLT4NgG6wgJpT/hHIpL9nELv27A1XbSZzECIuQBQTVSf4xGKxWr6I/jhpRPauYEWEbWVw22ObG6tJQqwJqWQ==",
"dependencies": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.1",
"rc-util": "^5.32.2"
"classnames": "^2.3.2",
"rc-util": "^5.38.0"
},
"peerDependencies": {
"react": ">=16.9.0",
@ -18185,14 +18184,16 @@
}
},
"node_modules/rc-picker": {
"version": "3.14.6",
"resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-3.14.6.tgz",
"integrity": "sha512-AdKKW0AqMwZsKvIpwUWDUnpuGKZVrbxVTZTNjcO+pViGkjC1EBcjMgxVe8tomOEaIHJL5Gd13vS8Rr3zzxWmag==",
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/rc-picker/-/rc-picker-4.1.1.tgz",
"integrity": "sha512-H99qaHUepHjHnAqMLiftJEATXRuHJZcUyFoRkyIqUvTHVGnx/uHxFFNm7QIu1valCpfwdsGWQxiWgn9CAxvlvA==",
"dependencies": {
"@babel/runtime": "^7.10.1",
"@rc-component/trigger": "^1.5.0",
"classnames": "^2.2.1",
"rc-util": "^5.30.0"
"rc-overflow": "^1.3.2",
"rc-resize-observer": "^1.4.0",
"rc-util": "^5.38.1"
},
"engines": {
"node": ">=8.x"
@ -18267,9 +18268,9 @@
}
},
"node_modules/rc-segmented": {
"version": "2.2.2",
"resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.2.2.tgz",
"integrity": "sha512-Mq52M96QdHMsNdE/042ibT5vkcGcD5jxKp7HgPC2SRofpia99P5fkfHy1pEaajLMF/kj0+2Lkq1UZRvqzo9mSA==",
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/rc-segmented/-/rc-segmented-2.3.0.tgz",
"integrity": "sha512-I3FtM5Smua/ESXutFfb8gJ8ZPcvFR+qUgeeGFQHBOvRiRKyAk4aBE5nfqrxXx+h8/vn60DQjOt6i4RNtrbOobg==",
"dependencies": {
"@babel/runtime": "^7.11.1",
"classnames": "^2.2.1",
@ -18282,9 +18283,9 @@
}
},
"node_modules/rc-select": {
"version": "14.9.2",
"resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.9.2.tgz",
"integrity": "sha512-VQ15sRFgPURHb8ZcZNSDtb2rAw3+C9xlL0nDziwNHTEW1KvEpZ8y+0v5w24X/Bpl9b3cW1BOyW1F5UqSAq+7Dg==",
"version": "14.11.0",
"resolved": "https://registry.npmjs.org/rc-select/-/rc-select-14.11.0.tgz",
"integrity": "sha512-8J8G/7duaGjFiTXCBLWfh5P+KDWyA3KTlZDfV3xj/asMPqB2cmxfM+lH50wRiPIRsCQ6EbkCFBccPuaje3DHIg==",
"dependencies": {
"@babel/runtime": "^7.10.1",
"@rc-component/trigger": "^1.5.0",
@ -18303,9 +18304,9 @@
}
},
"node_modules/rc-slider": {
"version": "10.3.1",
"resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-10.3.1.tgz",
"integrity": "sha512-XszsZLkbjcG9ogQy/zUC0n2kndoKUAnY/Vnk1Go5Gx+JJQBz0Tl15d5IfSiglwBUZPS9vsUJZkfCmkIZSqWbcA==",
"version": "10.5.0",
"resolved": "https://registry.npmjs.org/rc-slider/-/rc-slider-10.5.0.tgz",
"integrity": "sha512-xiYght50cvoODZYI43v3Ylsqiw14+D7ELsgzR40boDZaya1HFa1Etnv9MDkQE8X/UrXAffwv2AcNAhslgYuDTw==",
"dependencies": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.5",
@ -18351,15 +18352,15 @@
}
},
"node_modules/rc-table": {
"version": "7.34.4",
"resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.34.4.tgz",
"integrity": "sha512-os+i88Y2AO/6dNkOgJkKSHgXYaZZGnuOEEe+nyaq5IRgvAQNhLysUjXt2objtBeFDEZR8TqXrajwBNRUwunmdw==",
"version": "7.39.0",
"resolved": "https://registry.npmjs.org/rc-table/-/rc-table-7.39.0.tgz",
"integrity": "sha512-7fHLMNsm/2DlGwyIMkdH2xIeRzb5I69bLsFaEVtX+gqmGhByy0wtOAgHkiOew3PtXozSJyh+iXifjLgQzWdczw==",
"dependencies": {
"@babel/runtime": "^7.10.1",
"@rc-component/context": "^1.4.0",
"classnames": "^2.2.5",
"rc-resize-observer": "^1.1.0",
"rc-util": "^5.36.0",
"rc-util": "^5.37.0",
"rc-virtual-list": "^3.11.1"
},
"engines": {
@ -18371,9 +18372,9 @@
}
},
"node_modules/rc-tabs": {
"version": "12.12.1",
"resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-12.12.1.tgz",
"integrity": "sha512-e10VBjEkECdPl4XZSs9to81SE+mgclBTM7J8/LMsFqmJoi05Tci91bRnmeeDtrcOCx2PuZdJv57XUlC4d8PEIw==",
"version": "14.0.0",
"resolved": "https://registry.npmjs.org/rc-tabs/-/rc-tabs-14.0.0.tgz",
"integrity": "sha512-lp1YWkaPnjlyhOZCPrAWxK6/P6nMGX/BAZcAC3nuVwKz0Byfp+vNnQKK8BRCP2g/fzu+SeB5dm9aUigRu3tRkQ==",
"dependencies": {
"@babel/runtime": "^7.11.2",
"classnames": "2.x",
@ -18392,13 +18393,13 @@
}
},
"node_modules/rc-textarea": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-1.4.0.tgz",
"integrity": "sha512-CiqK+uyoJlnfufbC0kwfHJpfElhQacuDSNyNQ/xGnA/QMaJLDbgmqRT8QmX0T0KD/ws/hy6qqRaGJSsrRR5uiQ==",
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/rc-textarea/-/rc-textarea-1.6.3.tgz",
"integrity": "sha512-8k7+8Y2GJ/cQLiClFMg8kUXOOdvcFQrnGeSchOvI2ZMIVvX5a3zQpLxoODL0HTrvU63fPkRmMuqaEcOF9dQemA==",
"dependencies": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.1",
"rc-input": "~1.2.1",
"rc-input": "~1.4.0",
"rc-resize-observer": "^1.0.0",
"rc-util": "^5.27.0"
},
@ -18408,9 +18409,9 @@
}
},
"node_modules/rc-tooltip": {
"version": "6.1.2",
"resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-6.1.2.tgz",
"integrity": "sha512-89zwvybvCxGJu3+gGF8w5AXd4HHk6hIN7K0vZbkzjilVaEAIWPqc1fcyeUeP71n3VCcw7pTL9LyFupFbrx8gHw==",
"version": "6.1.3",
"resolved": "https://registry.npmjs.org/rc-tooltip/-/rc-tooltip-6.1.3.tgz",
"integrity": "sha512-HMSbSs5oieZ7XddtINUddBLSVgsnlaSb3bZrzzGWjXa7/B7nNedmsuz72s7EWFEro9mNa7RyF3gOXKYqvJiTcQ==",
"dependencies": {
"@babel/runtime": "^7.11.2",
"@rc-component/trigger": "^1.18.0",
@ -18422,9 +18423,9 @@
}
},
"node_modules/rc-tree": {
"version": "5.7.12",
"resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.7.12.tgz",
"integrity": "sha512-LXA5nY2hG5koIAlHW5sgXgLpOMz+bFRbnZZ+cCg0tQs4Wv1AmY7EDi1SK7iFXhslYockbqUerQan82jljoaItg==",
"version": "5.8.5",
"resolved": "https://registry.npmjs.org/rc-tree/-/rc-tree-5.8.5.tgz",
"integrity": "sha512-PRfcZtVDNkR7oh26RuNe1hpw11c1wfgzwmPFL0lnxGnYefe9lDAO6cg5wJKIAwyXFVt5zHgpjYmaz0CPy1ZtKg==",
"dependencies": {
"@babel/runtime": "^7.10.1",
"classnames": "2.x",
@ -18441,14 +18442,14 @@
}
},
"node_modules/rc-tree-select": {
"version": "5.13.0",
"resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.13.0.tgz",
"integrity": "sha512-g01JU9EdE7j/9KfDKtmvFqJ7ZDNIYDzkpmAXllbTBFoRNhWJBjW1x/dCZLVG+IdZeIz8SKJkgZzCf1CUZrzV/Q==",
"version": "5.17.0",
"resolved": "https://registry.npmjs.org/rc-tree-select/-/rc-tree-select-5.17.0.tgz",
"integrity": "sha512-7sRGafswBhf7n6IuHyCEFCildwQIgyKiV8zfYyUoWfZEFdhuk7lCH+DN0aHt+oJrdiY9+6Io/LDXloGe01O8XQ==",
"dependencies": {
"@babel/runtime": "^7.10.1",
"classnames": "2.x",
"rc-select": "~14.9.0",
"rc-tree": "~5.7.0",
"rc-select": "~14.11.0-0",
"rc-tree": "~5.8.1",
"rc-util": "^5.16.1"
},
"peerDependencies": {
@ -18457,9 +18458,9 @@
}
},
"node_modules/rc-upload": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.3.5.tgz",
"integrity": "sha512-EHlKJbhkgFSQHliTj9v/2K5aEuFwfUQgZARzD7AmAPOneZEPiCNF3n6PEWIuqz9h7oq6FuXgdR67sC5BWFxJbA==",
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/rc-upload/-/rc-upload-4.5.2.tgz",
"integrity": "sha512-QO3ne77DwnAPKFn0bA5qJM81QBjQi0e0NHdkvpFyY73Bea2NfITiotqJqVjHgeYPOJu5lLVR32TNGP084aSoXA==",
"dependencies": {
"@babel/runtime": "^7.18.3",
"classnames": "^2.2.5",
@ -18471,9 +18472,9 @@
}
},
"node_modules/rc-util": {
"version": "5.38.0",
"resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.38.0.tgz",
"integrity": "sha512-yV/YBNdFn+edyBpBdCqkPE29Su0jWcHNgwx2dJbRqMrMfrUcMJUjCRV+ZPhcvWyKFJ63GzEerPrz9JIVo0zXmA==",
"version": "5.38.1",
"resolved": "https://registry.npmjs.org/rc-util/-/rc-util-5.38.1.tgz",
"integrity": "sha512-e4ZMs7q9XqwTuhIK7zBIVFltUtMSjphuPPQXHoHlzRzNdOwUxDejo0Zls5HYaJfRKNURcsS/ceKVULlhjBrxng==",
"dependencies": {
"@babel/runtime": "^7.18.3",
"react-is": "^18.2.0"
@ -18489,9 +18490,9 @@
"integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w=="
},
"node_modules/rc-virtual-list": {
"version": "3.11.2",
"resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.11.2.tgz",
"integrity": "sha512-MTFLL2LOHr3+/+r+WjTIs6j8XmJE6EqdOsJvCH8SWig7qyik3aljCEImUtw5tdWR0tQhXUfbv7P7nZaLY91XPg==",
"version": "3.11.4",
"resolved": "https://registry.npmjs.org/rc-virtual-list/-/rc-virtual-list-3.11.4.tgz",
"integrity": "sha512-NbBi0fvyIu26gP69nQBiWgUMTPX3mr4FcuBQiVqagU0BnuX8WQkiivnMs105JROeuUIFczLrlgUhLQwTWV1XDA==",
"dependencies": {
"@babel/runtime": "^7.20.0",
"classnames": "^2.2.6",
@ -18502,8 +18503,8 @@
"node": ">=8.x"
},
"peerDependencies": {
"react": "*",
"react-dom": "*"
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/react": {
@ -19624,9 +19625,9 @@
}
},
"node_modules/scroll-into-view-if-needed": {
"version": "3.0.10",
"resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.0.10.tgz",
"integrity": "sha512-t44QCeDKAPf1mtQH3fYpWz8IM/DyvHLjs8wUvvwMYxk5moOqCzrMSxK6HQVD0QVmVjXFavoFIPRVrMuJPKAvtg==",
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/scroll-into-view-if-needed/-/scroll-into-view-if-needed-3.1.0.tgz",
"integrity": "sha512-49oNpRjWRvnU8NyGVmUaYG4jtTkNonFZI86MmGRDqBphEK2EXT9gdEUoQPZhuBM8yWHxCWbobltqYO5M4XrUvQ==",
"dependencies": {
"compute-scroll-into-view": "^3.0.2"
}
@ -20305,9 +20306,9 @@
}
},
"node_modules/stylis": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.0.tgz",
"integrity": "sha512-E87pIogpwUsUwXw7dNyU4QDjdgVMy52m+XEOPEKUn161cCzWjjhPSQhByfd1CcNvrOLnXQ6OnnZDwnJrz/Z4YQ=="
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/stylis/-/stylis-4.3.1.tgz",
"integrity": "sha512-EQepAV+wMsIaGVGX1RECzgrcqRRU/0sYOHkeLsZ3fzHaHXZy4DaOOX0vOlGQdlsjkh3mFHAIlVimpwAs4dslyQ=="
},
"node_modules/sucrase": {
"version": "3.32.0",

View File

@ -11,7 +11,7 @@
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"@yudiel/react-qr-scanner": "^1.1.10",
"antd": "^5.10.3",
"antd": "^5.14.1",
"buffer": "^6.0.3",
"i18next": "^23.2.3",
"i18next-browser-languagedetector": "^7.1.0",

View File

@ -221,6 +221,10 @@
},
"costSummary": {
"title": "Kostenzusammenfassung",
"options": {
"yearly": "Jährlich",
"monthly": "Monatlich"
},
"totalNet": "SUMME NETTO",
"vat": "MWST.",
"totalAmount": "GESAMTBETRAG"
@ -490,6 +494,7 @@
},
"paymentPlan": {
"title": "Zahlungsplan",
"buttonUpdateBillingDetails": "Zahlungsdetails aktualisieren",
"plan": "Plan",
"contentsOfSubscription": {
"title": "Inhalt des Abonnements",

View File

@ -221,10 +221,19 @@
},
"costSummary": {
"title": "Cost summary",
"options": {
"yearly": "Yearly",
"monthly": "Monthly"
},
"totalNet": "TOTAL NET",
"vat": "VAT",
"totalAmount": "TOTAL AMOUNT"
},
"checkoutCanceled": {
"title": "Order canceled",
"subTitle": "The order has been canceled. Please try again.",
"buttonBackToPriceOverview": "Back to price overview"
},
"request": {
"400": {
"title": "Sign up failed",
@ -494,6 +503,7 @@
},
"paymentPlan": {
"title": "Payment plan",
"buttonUpdateBillingDetails": "Update billing details",
"plan": "Plan",
"contentsOfSubscription": {
"title": "Contents of subscription",

View File

@ -8,6 +8,12 @@ import Verification from "../../Pages/Verification";
// Lazy-loaded components
const Authentication = lazy(() => import("../../Pages/Authentication"));
const SignUp = lazy(() => import("../../Pages/Authentication/SignUp"));
const CheckoutSuccess = lazy(() =>
import("../../Pages/Authentication/CheckoutSuccess")
);
const CheckoutCanceled = lazy(() =>
import("../../Pages/Authentication/CheckoutCanceled")
);
const Dashboard = lazy(() => import("../../Pages/Dashboard"));
const PaymentPlan = lazy(() => import("../../Pages/PaymentPlan"));
const PageNotFound = lazy(() => import("../../Pages/PageNotFound"));
@ -51,6 +57,24 @@ export function AuthenticationRoutes() {
}
/>
<Route
path={`${Constants.ROUTE_PATHS.AUTHENTICATION.CHECKOUT_SUCCESS}/:sessionId`}
element={
<MySupsenseFallback>
<CheckoutSuccess />
</MySupsenseFallback>
}
/>
<Route
path={`${Constants.ROUTE_PATHS.AUTHENTICATION.CHECKOUT_CANCELED}/:sessionId`}
element={
<MySupsenseFallback>
<CheckoutCanceled />
</MySupsenseFallback>
}
/>
<Route
path={Constants.ROUTE_PATHS.AUTHENTICATION.FORGOT_PASSWORD}
element={

View File

@ -0,0 +1,10 @@
import { Spin } from "antd";
import MyCenteredContainer from "../MyContainer";
export default function MyCenteredSpin({ fullHeight = false }) {
return (
<MyCenteredContainer fullHeight>
<Spin size="large" />
</MyCenteredContainer>
);
}

View File

@ -1,4 +1,4 @@
export default function MyCenteredContainer({ children }) {
export default function MyCenteredContainer({ children, fullHeight = false }) {
return (
<div
style={{
@ -7,7 +7,7 @@ export default function MyCenteredContainer({ children }) {
justifyContent: "center",
alignContent: "center",
alignItems: "center",
height: "85.3vh",
height: fullHeight ? "100vh" : "85.3vh",
}}
>
{children}

View File

@ -1,15 +1,13 @@
import { Spin } from "antd";
import { Suspense } from "react";
import MyCenteredContainer from "../MyContainer";
import MyCenteredSpin from "../MyCenteredSpin";
export function MySupsenseFallback({ children, spinnerCentered = true }) {
return (
<Suspense
fallback={
spinnerCentered ? (
<MyCenteredContainer>
<Spin size="large" />
</MyCenteredContainer>
<MyCenteredSpin fullHeight />
) : (
<div
style={{

View File

@ -0,0 +1,68 @@
import { Button, Modal, Result } from "antd";
import { useParams } from "react-router-dom";
import { useEffect, useState } from "react";
import MyCenteredSpin from "../../Components/MyCenteredSpin";
import { RequestState } from "../../Components/MyRequestStateItem";
import { myFetch } from "../../utils";
import PageNotFound from "../PageNotFound";
import { BackToZeitAdlerPricingOverview } from ".";
import { useTranslation } from "react-i18next";
export default function CheckoutCanceled() {
const { t } = useTranslation();
const [isRequesting, setIsRequesting] = useState(RequestState.INIT);
const { sessionId } = useParams();
useEffect(() => {
// was set in sign up page
localStorage.removeItem("tmp_session");
myFetch({
url: "/payment/checkout/canceled",
method: "POST",
body: {
sessionId: sessionId,
},
})
.then(() => setIsRequesting(RequestState.SUCCESS))
.catch(() => setIsRequesting(RequestState.FAILED));
}, []);
if (isRequesting === RequestState.INIT) {
return <MyCenteredSpin fullHeight />;
}
return (
<Modal
open={true}
mask={false}
closable={false}
centered
keyboard={false}
footer={null}
>
{isRequesting === RequestState.FAILED ? (
<PageNotFound />
) : (
<Result
status="error"
title={t("authentication.signUp.checkoutCanceled.title")}
subTitle={t("authentication.signUp.checkoutCanceled.subTitle")}
extra={[
<Button
type="primary"
key="back"
onClick={() => BackToZeitAdlerPricingOverview()}
>
{t(
"authentication.signUp.checkoutCanceled.buttonBackToPriceOverview"
)}
</Button>,
]}
/>
)}
</Modal>
);
}

View File

@ -0,0 +1,37 @@
import { useParams } from "react-router-dom";
import { useEffect } from "react";
import { myFetch, showUnkownErrorNotification } from "../../utils";
import MyCenteredSpin from "../../Components/MyCenteredSpin";
export default function CheckoutSuccess() {
const { sessionId } = useParams();
useEffect(() => {
setInterval(() => {
myFetch({
method: "POST",
url: "/payment/checkout/success",
body: {
sessionId: sessionId,
},
})
.then((response) => {
// payment success
if (response.status === 1) {
const session = localStorage.getItem("tmp_session");
if (session) {
localStorage.setItem("session", session);
}
localStorage.removeItem("tmp_session");
window.location.href = "/";
}
})
.catch(() => showUnkownErrorNotification());
}, 2000);
}, []);
return <MyCenteredSpin fullHeight />;
}

View File

@ -11,6 +11,7 @@ import {
showUnkownErrorNotification,
} from "../../utils";
import {
BackToZeitAdlerPricingOverview,
MyRecaptcha,
PendingEmailVerification,
PrivacyPolicyCheckbox,
@ -274,9 +275,7 @@ export function Login({ notificationApi }) {
<Button
type="link"
style={{ padding: 0 }}
onClick={() =>
navigate(Constants.ROUTE_PATHS.AUTHENTICATION.SIGN_UP)
}
onClick={() => BackToZeitAdlerPricingOverview()}
>
{t("authentication.signUpLink")}
</Button>

View File

@ -1,4 +1,3 @@
import { loadStripe } from "@stripe/stripe-js";
import {
Affix,
Button,
@ -8,6 +7,8 @@ import {
Flex,
Form,
Row,
Segmented,
Skeleton,
Typography,
notification,
} from "antd";
@ -28,12 +29,6 @@ import {
MyPasswordFormInput,
MyUsernameFormInput,
} from "../../Components/MyFormInputs";
import {
Elements,
PaymentElement,
useElements,
useStripe,
} from "@stripe/react-stripe-js";
import {
MyRecaptcha,
PendingEmailVerification,
@ -41,6 +36,7 @@ import {
} from ".";
import MyAppLogo from "../../Components/MyAppLogo";
import { CheckOutlined } from "@ant-design/icons";
import { RequestState } from "../../Components/MyRequestStateItem";
const SignUpStep = {
SIGN_UP: 1,
@ -87,8 +83,6 @@ export default function SignUp({ paymentPlan }) {
navigate={navigate}
form={form}
/>
<PaymentDetails notificationApi={notificationApi} t={t} />
</Col>
<Col
@ -137,23 +131,6 @@ function AccountDetails({ t, form }) {
);
}
/*
<Flex justify="center" style={{ paddingTop: 12 }}>
<Typography.Text>
{t("authentication.signUp.alreadyHaveAccount")}{" "}
<Button
type="link"
style={{ padding: 0 }}
onClick={() =>
navigate(Constants.ROUTE_PATHS.AUTHENTICATION.LOGIN)
}
>
{t("authentication.loginLink")}
</Button>
</Typography.Text>
</Flex>
*/
function ChoosenProduct({ t, paymentPlan }) {
return (
<Card
@ -194,140 +171,14 @@ function ChoosenProduct({ t, paymentPlan }) {
);
}
const stripePromise = loadStripe(process.env.REACT_APP_STRIPE_PUBLISHABLE_KEY);
function PaymentDetails({ notificationApi, t }) {
const [clientSecret, setClientSecret] = useState(null);
useEffect(() => {
myFetch({
method: "POST",
url: "/payment/create-payment-intent",
})
.then((data) => setClientSecret(data.clientSecret))
.catch((err) => {
console.error(err);
showUnkownErrorNotification(notificationApi, t);
});
}, []);
return (
<Card
title={t("authentication.signUp.paymentDetails.title")}
style={{ marginBottom: 40 }}
>
{clientSecret && (
<Elements
options={{
clientSecret: clientSecret,
appearance: {
theme: "stripe",
},
}}
stripe={stripePromise}
>
<CheckoutForm />
</Elements>
)}
</Card>
);
}
function CheckoutForm() {
const stripe = useStripe();
const elements = useElements();
const [message, setMessage] = useState(null);
const [isLoading, setIsLoading] = useState(false);
useEffect(() => {
if (!stripe) {
return;
}
const clientSecret = new URLSearchParams(window.location.search).get(
"payment_intent_client_secret"
);
if (!clientSecret) {
return;
}
stripe.retrievePaymentIntent(clientSecret).then(({ paymentIntent }) => {
switch (paymentIntent.status) {
case "succeeded":
setMessage("Payment succeeded!");
break;
case "processing":
setMessage("Your payment is processing.");
break;
case "requires_payment_method":
setMessage("Your payment was not successful, please try again.");
break;
default:
setMessage("Something went wrong.");
break;
}
});
}, [stripe]);
const handleSubmit = async (e) => {
e.preventDefault();
if (!stripe || !elements) {
// Stripe.js hasn't yet loaded.
// Make sure to disable form submission until Stripe.js has loaded.
return;
}
setIsLoading(true);
const { error } = await stripe.confirmPayment({
elements,
confirmParams: {
receipt_email: "test@roese.dev",
// Make sure to change this to your payment completion page
return_url: `${Constants.DASHBOARD_ADDRESS}/buy/premium`,
},
});
// This point will only be reached if there is an immediate error when
// confirming the payment. Otherwise, your customer will be redirected to
// your `return_url`. For some payment methods like iDEAL, your customer will
// be redirected to an intermediate site first to authorize the payment, then
// redirected to the `return_url`.
if (error.type === "card_error" || error.type === "validation_error") {
setMessage(error.message);
} else {
setMessage("An unexpected error occurred.");
}
setIsLoading(false);
};
const paymentElementOptions = {
layout: "tabs",
};
return (
<form id="payment-form" onSubmit={handleSubmit}>
<PaymentElement id="payment-element" options={paymentElementOptions} />
<button disabled={isLoading || !stripe || !elements} id="submit">
<span id="button-text">
{isLoading ? <div className="spinner" id="spinner"></div> : "Pay now"}
</span>
</button>
{/* Show any error or success messages */}
{message && <div id="payment-message">{message}</div>}
</form>
);
}
function CostSummary({ notificationApi, paymentPlan, form }) {
const { t, i18n } = useTranslation();
const [isRequesting, setIsRequesting] = useState(false);
const [isRequesting, setIsRequesting] = useState(RequestState.INIT);
const recaptchaRef = useRef(null);
const recaptchaValueRef = useRef(null);
const [prices, setPrices] = useState(null);
const [segmentedValue, setSegmentedValue] = useState(1);
const showErrorNotification = (errStatus) => {
if (errStatus === 400) {
@ -342,7 +193,7 @@ function CostSummary({ notificationApi, paymentPlan, form }) {
form
.validateFields()
.then((values) => {
setIsRequesting(true);
setIsRequesting(RequestState.REQUESTING);
myFetch({
url: `/user/auth/signup`,
@ -355,30 +206,76 @@ function CostSummary({ notificationApi, paymentPlan, form }) {
language: i18n.language,
rememberMe: true,
recaptcha: recaptchaValueRef.current,
paymentPlan: paymentPlan,
paymentInterval: segmentedValue,
},
notificationApi: notificationApi,
t: t,
})
.then(() => {
/*
setStep(SignUpStep.PENDING_EMAIL_VERIFICATION)
*/
.then((data) => {
setIsRequesting(RequestState.NOTHING);
localStorage.setItem("tmp_session", data.XAuthorization);
window.location.href = data.redirectUrl;
})
.catch((errStatus) => {
recaptchaRef.current.reset();
showErrorNotification(errStatus);
setIsRequesting(false);
});
})
.catch(() => {
recaptchaRef.current.reset();
showInputsInvalidNotification(notificationApi, t);
setIsRequesting(false);
});
};
useEffect(() => {
myFetch({
url: `/payment/prices/${paymentPlan}`,
method: "GET",
})
.then((data) => {
setIsRequesting(RequestState.NOTHING);
setPrices(data.prices);
})
.catch(() => showUnkownErrorNotification(notificationApi, t));
}, []);
const formatPrice = (price) => {
return (price / 100).toLocaleString("de-DE", {
style: "currency",
currency: "EUR",
});
};
const price = prices ? prices[segmentedValue].unit_amount : 0;
const totalNet = formatPrice(price);
const vat = formatPrice((price / 100) * 19);
const totalAmount = formatPrice(price + (price / 100) * 19);
return (
<Affix offsetTop={16}>
<Card title={t("authentication.signUp.costSummary.title")}>
<Form form={form}>
<Segmented
block
options={[
{
label: t("authentication.signUp.costSummary.options.yearly"),
value: 1,
},
{
label: t("authentication.signUp.costSummary.options.monthly"),
value: 0,
},
]}
value={segmentedValue}
onChange={(v) => setSegmentedValue(v)}
/>
<div
style={{
backgroundColor: "#393a56",
@ -388,42 +285,51 @@ function CostSummary({ notificationApi, paymentPlan, form }) {
textAlign: "center",
fontWeight: "bold",
padding: 8,
marginTop: 12,
marginBottom: 12,
}}
>
{Constants.APP_NAME} - {Constants.PAYMENT_PLAN[paymentPlan].name}
</div>
<Flex justify="space-between">
<Typography.Text style={{ fontSize: 16 }}>
{t("authentication.signUp.costSummary.totalNet")}
</Typography.Text>
{isRequesting === RequestState.INIT ? (
<Skeleton.Button active size="small" />
) : (
<Typography.Text style={{ fontSize: 16 }}>
{
Constants.PAYMENT_PLAN[paymentPlan].price[i18n.language]
.totalNet
}
{totalNet}
</Typography.Text>
)}
</Flex>
<Divider style={{ margin: 8 }} />
<Flex justify="space-between">
<Typography.Text style={{ fontSize: 16 }}>
{" "}
{t("authentication.signUp.costSummary.vat")}
</Typography.Text>
<Typography.Text style={{ fontSize: 16 }}>
{Constants.PAYMENT_PLAN[paymentPlan].price[i18n.language].vat}
</Typography.Text>
{isRequesting === RequestState.INIT ? (
<Skeleton.Button active size="small" />
) : (
<Typography.Text style={{ fontSize: 16 }}>{vat}</Typography.Text>
)}
</Flex>
<Divider style={{ margin: 8 }} />
<Flex justify="space-between" style={{ marginBottom: 20 }}>
<Flex
justify="space-between"
align="center"
style={{ marginBottom: 20 }}
>
<Typography.Text style={{ fontSize: 16, fontWeight: "600" }}>
{t("authentication.signUp.costSummary.totalAmount")}
</Typography.Text>
{isRequesting === RequestState.INIT ? (
<Skeleton.Button active size="large" />
) : (
<Typography.Text
style={{
fontSize: 16,
@ -436,23 +342,24 @@ function CostSummary({ notificationApi, paymentPlan, form }) {
fontWeight: "bold",
}}
>
{
Constants.PAYMENT_PLAN[paymentPlan].price[i18n.language]
.totalAmount
}
{totalAmount}
</Typography.Text>
)}
</Flex>
<PrivacyPolicyCheckbox />
<MyRecaptcha recaptchaValueRef={recaptchaValueRef} />
<MyRecaptcha
recaptchaRef={recaptchaRef}
recaptchaValueRef={recaptchaValueRef}
/>
<Button
type="primary"
size="large"
block
onClick={handleSubmit}
loading={isRequesting}
loading={isRequesting === RequestState.REQUESTING}
>
{t("authentication.signUp.button")}
</Button>

View File

@ -117,3 +117,7 @@ export function PendingEmailVerification() {
/>
);
}
export function BackToZeitAdlerPricingOverview() {
window.location.href = process.env.REACT_APP_ZEITADLER_HOMEPAGE_PRICING;
}

View File

@ -1,14 +1,47 @@
import { Card, Descriptions } from "antd";
import { Button, Card, Descriptions } from "antd";
import { useAppContext } from "../../Contexts/AppContext";
import { Constants } from "../../utils";
import { Constants, myFetch } from "../../utils";
import { useTranslation } from "react-i18next";
import { CreditCardOutlined } from "@ant-design/icons";
import { useState } from "react";
export default function PaymentPlan() {
const { t } = useTranslation();
const appContext = useAppContext();
const [isRequestingBillingDetails, setIsRequestingBillingDetails] =
useState(false);
return (
<Card title={t("paymentPlan.title")}>
<Card
title={t("paymentPlan.title")}
extra={
<Button
type="link"
icon={<CreditCardOutlined />}
loading={isRequestingBillingDetails}
onClick={() => {
setIsRequestingBillingDetails(true);
myFetch({
method: "GET",
url: "/payment/portal",
})
.then((response) => {
console.log("response", response);
window.location.href = response.url;
})
.catch((error) => {
console.error("error", error);
setIsRequestingBillingDetails(false);
});
}}
>
{t("paymentPlan.buttonUpdateBillingDetails")}
</Button>
}
>
<Descriptions>
<Descriptions.Item label={t("paymentPlan.plan")}>
{Constants.PAYMENT_PLAN[appContext.paymentPlan].name}

View File

@ -18,6 +18,13 @@ root.render(
colorPrimary: "#6878d6",
colorInfo: "#6878d6",
},
components: {
Segmented: {
// used in sign up
itemSelectedBg: "#6878d6",
itemSelectedColor: "#fff",
},
},
}}
>
<App />

View File

@ -48,6 +48,8 @@ export const Constants = {
LOGIN: "/login",
SIGN_UP: "/buy",
FORGOT_PASSWORD: "/forgot-password",
CHECKOUT_SUCCESS: "/checkout/success",
CHECKOUT_CANCELED: "/checkout/canceled",
},
VERIFY: "/verify",
OVERVIEW: "/",
@ -348,6 +350,8 @@ export function showUnkownErrorNotification(notificationApi, t) {
}
export function handleLogout({ setUserSession }) {
console.log("handleLogout");
if (setUserSession !== undefined) setUserSession();
window.location.href = Constants.ROUTE_PATHS.AUTHENTICATION.LOGIN;