From 70abd2520805615d30dc1e2bcad840b5744264f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20K=C3=BCndig?= Date: Fri, 1 Sep 2023 10:56:52 +0200 Subject: [PATCH] website(refactor): cleanups and add analytics (#557) --- admin/package.json | 30 +- functions/package.json | 20 +- package-lock.json | 432 +++++++++++++----- package.json | 2 +- shared/locales/de/website-home.json | 3 +- shared/locales/en/website-home.json | 3 +- shared/package.json | 8 +- shared/src/stripe/StripeEventHandler.ts | 9 +- .../src/stripe/StripeWebhookHandler.test.ts | 2 - shared/src/stripe/index.ts | 2 +- .../components/containers/base-container.tsx | 2 +- website/package.json | 32 +- .../(website)/(home)/section-1-input.tsx | 49 +- .../[country]/(website)/(home)/section-1.tsx | 4 +- .../[country]/(website)/(home)/section-2.tsx | 2 +- .../[lang]/[country]/(website)/faq/page.tsx | 5 + .../me/contributions/contributions-table.tsx | 21 +- .../(website)/me/contributions/page.tsx | 12 +- .../transparency/[currency]/charts/page.tsx | 2 +- .../transparency/[currency]/page.tsx | 2 +- .../app/api/stripe/billing-portal/route.ts | 15 +- .../app/api/stripe/checkout/success/route.ts | 2 +- .../app/api/user/create-auth-user/route.ts | 2 +- website/src/app/providers.tsx | 42 +- .../components/navbar/language-switcher.tsx | 69 +++ .../src/components/navbar/navbar-client.tsx | 60 +-- website/src/components/navbar/navbar.tsx | 2 +- .../{firebase/admin.ts => firebase-admin.ts} | 0 website/src/firebase/client.ts | 32 -- 29 files changed, 556 insertions(+), 310 deletions(-) create mode 100644 website/src/app/[lang]/[country]/(website)/faq/page.tsx create mode 100644 website/src/components/navbar/language-switcher.tsx rename website/src/{firebase/admin.ts => firebase-admin.ts} (100%) delete mode 100644 website/src/firebase/client.ts diff --git a/admin/package.json b/admin/package.json index 5bbc097c4..47f00f151 100644 --- a/admin/package.json +++ b/admin/package.json @@ -16,38 +16,38 @@ }, "devDependencies": { "@firebase/rules-unit-testing": "^3.0.0", - "@jest/globals": "^29.6.2", - "@playwright/test": "^1.37.0", - "@types/jest": "^29.5.3", - "@types/luxon": "^3.3.1", - "@types/node": "^20.5.0", - "@types/react": "^18.2.20", + "@jest/globals": "^29.6.4", + "@playwright/test": "^1.37.1", + "@types/jest": "^29.5.4", + "@types/luxon": "^3.3.2", + "@types/node": "^20.5.7", + "@types/react": "^18.2.21", "@types/react-dom": "^18.2.7", "@vitejs/plugin-react": "^4.0.4", "css-loader": "^6.8.1", - "jest": "^29.6.2", + "jest": "^29.6.4", "process": "^0.11.10", "style-loader": "^3.3.3", "ts-jest": "^29.1.1", "ts-loader": "^9.4.4", "ts-node": "^10.9.1", - "typescript": "^5.1.6", + "typescript": "^5.2.2", "vite": "^4.4.9" }, "dependencies": { "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", - "@mui/icons-material": "^5.14.3", - "@mui/lab": "^5.0.0-alpha.140", - "@mui/material": "^5.14.5", - "@mui/x-data-grid": "^6.11.1", - "@mui/x-date-pickers": "^6.11.1", + "@mui/icons-material": "^5.14.7", + "@mui/lab": "^5.0.0-alpha.142", + "@mui/material": "^5.14.7", + "@mui/x-data-grid": "^6.12.1", + "@mui/x-date-pickers": "^6.12.1", "@socialincome/shared": "^1.0.0", "algoliasearch": "^4.19.1", - "firebase": "^9.23.0", + "firebase": "^10.3.1", "firecms": "2.0.5", "lodash": "^4.17.21", - "luxon": "^3.4.0", + "luxon": "^3.4.2", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router": "^6.15.0", diff --git a/functions/package.json b/functions/package.json index 8bef626c7..bd79b9c3d 100644 --- a/functions/package.json +++ b/functions/package.json @@ -16,22 +16,22 @@ "test:playwright:update": "firebase emulators:exec --project social-income-staging --only firestore --config ../firebase.json --import ../seed 'npx playwright install --with-deps && playwright test --update-snapshots'" }, "devDependencies": { - "@jest/globals": "^29.6.2", - "@playwright/test": "^1.37.0", + "@jest/globals": "^29.6.4", + "@playwright/test": "^1.37.1", "@types/imap-simple": "^4.2.6", - "@types/jest": "^29.5.3", - "@types/luxon": "^3.3.1", + "@types/jest": "^29.5.4", + "@types/luxon": "^3.3.2", "@types/mailparser": "^3.4.0", "@types/pdfkit": "^0.12.10", "firebase-functions-test": "^3.1.0", - "jest": "^29.6.2", + "jest": "^29.6.4", "request": "^2.88.2", "ts-jest": "^29.1.1", "ts-loader": "^9.4.4", - "typescript": "^5.1.6" + "typescript": "^5.2.2" }, "dependencies": { - "axios": "^1.4.0", + "axios": "^1.5.0", "dotenv": "^16.3.1", "firebase-admin": "^11.10.1", "firebase-functions": "^4.4.1", @@ -40,13 +40,13 @@ "i18next-resources-to-backend": "^1.1.4", "imap-simple": "^5.1.0", "lodash": "^4.17.21", - "luxon": "^3.4.0", + "luxon": "^3.4.2", "mailparser": "^3.6.5", "mjml": "^4.14.1", "nodemailer": "^6.9.4", "pdfkit": "^0.13.0", - "stripe": "^12.18.0", + "stripe": "^13.4.0", "tmp-promise": "^3.0.3", - "twilio": "^4.15.0" + "twilio": "^4.16.0" } } diff --git a/package-lock.json b/package-lock.json index 47733009f..6cc31ba15 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "prettier": "3.0.0", "prettier-plugin-organize-imports": "3.2.3", "prettier-plugin-tailwindcss": "0.4.1", - "typescript": "^5.1.6" + "typescript": "^5.2.2" } }, "admin": { @@ -29,17 +29,17 @@ "dependencies": { "@emotion/react": "^11.11.1", "@emotion/styled": "^11.11.0", - "@mui/icons-material": "^5.14.3", - "@mui/lab": "^5.0.0-alpha.140", - "@mui/material": "^5.14.5", - "@mui/x-data-grid": "^6.11.1", - "@mui/x-date-pickers": "^6.11.1", + "@mui/icons-material": "^5.14.7", + "@mui/lab": "^5.0.0-alpha.142", + "@mui/material": "^5.14.7", + "@mui/x-data-grid": "^6.12.1", + "@mui/x-date-pickers": "^6.12.1", "@socialincome/shared": "^1.0.0", "algoliasearch": "^4.19.1", - "firebase": "^9.23.0", + "firebase": "^10.3.1", "firecms": "2.0.5", "lodash": "^4.17.21", - "luxon": "^3.4.0", + "luxon": "^3.4.2", "react": "^18.2.0", "react-dom": "^18.2.0", "react-router": "^6.15.0", @@ -48,30 +48,228 @@ }, "devDependencies": { "@firebase/rules-unit-testing": "^3.0.0", - "@jest/globals": "^29.6.2", - "@playwright/test": "^1.37.0", - "@types/jest": "^29.5.3", - "@types/luxon": "^3.3.1", - "@types/node": "^20.5.0", - "@types/react": "^18.2.20", + "@jest/globals": "^29.6.4", + "@playwright/test": "^1.37.1", + "@types/jest": "^29.5.4", + "@types/luxon": "^3.3.2", + "@types/node": "^20.5.7", + "@types/react": "^18.2.21", "@types/react-dom": "^18.2.7", "@vitejs/plugin-react": "^4.0.4", "css-loader": "^6.8.1", - "jest": "^29.6.2", + "jest": "^29.6.4", "process": "^0.11.10", "style-loader": "^3.3.3", "ts-jest": "^29.1.1", "ts-loader": "^9.4.4", "ts-node": "^10.9.1", - "typescript": "^5.1.6", + "typescript": "^5.2.2", "vite": "^4.4.9" } }, + "admin/node_modules/@firebase/app": { + "version": "0.9.18", + "resolved": "https://registry.npmjs.org/@firebase/app/-/app-0.9.18.tgz", + "integrity": "sha512-SIJi3B/LzNezaEgbFCFIem12+51khkA3iewYljPQPUArWGSAr1cO9NK8TvtJWax5GMKSmQbJPqgi6a+gxHrWGQ==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "idb": "7.1.1", + "tslib": "^2.1.0" + } + }, + "admin/node_modules/@firebase/app-compat": { + "version": "0.2.18", + "resolved": "https://registry.npmjs.org/@firebase/app-compat/-/app-compat-0.2.18.tgz", + "integrity": "sha512-zUbAAZHhwmMUyaNFiFr+1Z/sfcxSQBFrRhpjzzpQMTfiV2C/+P0mC3BQA0HsysdGSYOlwrCs5rEGOyarhRU9Kw==", + "dependencies": { + "@firebase/app": "0.9.18", + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + } + }, + "admin/node_modules/@firebase/auth": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@firebase/auth/-/auth-1.3.0.tgz", + "integrity": "sha512-vjK4CHbY9aWdiVOrKi6mpa8z6uxeaf7LB/MZTHuZOiGHMcUoTGB6TeMbRShyqk1uaMrxhhZ5Ar/dR0965E1qyA==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "node-fetch": "2.6.7", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app": "0.x", + "@react-native-async-storage/async-storage": "^1.18.1" + }, + "peerDependenciesMeta": { + "@react-native-async-storage/async-storage": { + "optional": true + } + } + }, + "admin/node_modules/@firebase/auth-compat": { + "version": "0.4.6", + "resolved": "https://registry.npmjs.org/@firebase/auth-compat/-/auth-compat-0.4.6.tgz", + "integrity": "sha512-pKp1d4fSf+yoy1EBjTx9ISxlunqhW0vTICk0ByZ3e+Lp6ZIXThfUy4F1hAJlEafD/arM0oepRiAh7LXS1xn/BA==", + "dependencies": { + "@firebase/auth": "1.3.0", + "@firebase/auth-types": "0.12.0", + "@firebase/component": "0.6.4", + "@firebase/util": "1.9.3", + "node-fetch": "2.6.7", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "admin/node_modules/@firebase/database": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@firebase/database/-/database-1.0.1.tgz", + "integrity": "sha512-VAhF7gYwunW4Lw/+RQZvW8dlsf2r0YYqV9W0Gi2Mz8+0TGg1mBJWoUtsHfOr8kPJXhcLsC4eP/z3x6L/Fvjk/A==", + "dependencies": { + "@firebase/auth-interop-types": "0.2.1", + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "faye-websocket": "0.11.4", + "tslib": "^2.1.0" + } + }, + "admin/node_modules/@firebase/database-compat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@firebase/database-compat/-/database-compat-1.0.1.tgz", + "integrity": "sha512-ky82yLIboLxtAIWyW/52a6HLMVTzD2kpZlEilVDok73pNPLjkJYowj8iaIWK5nTy7+6Gxt7d00zfjL6zckGdXQ==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/database": "1.0.1", + "@firebase/database-types": "1.0.0", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + } + }, + "admin/node_modules/@firebase/database-types": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@firebase/database-types/-/database-types-1.0.0.tgz", + "integrity": "sha512-SjnXStoE0Q56HcFgNQ+9SsmJc0c8TqGARdI/T44KXy+Ets3r6x/ivhQozT66bMnCEjJRywYoxNurRTMlZF8VNg==", + "dependencies": { + "@firebase/app-types": "0.9.0", + "@firebase/util": "1.9.3" + } + }, + "admin/node_modules/@firebase/firestore": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@firebase/firestore/-/firestore-4.1.3.tgz", + "integrity": "sha512-3kw/oZrLAIHuSDTAlKguZ1e0hAgWgiBl4QQm2mIPBvBAs++iEkuv9DH2tr6rbYpT6dWtdn6jj0RN0XeqOouJRg==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/logger": "0.4.0", + "@firebase/util": "1.9.3", + "@firebase/webchannel-wrapper": "0.10.2", + "@grpc/grpc-js": "~1.8.17", + "@grpc/proto-loader": "^0.7.8", + "node-fetch": "2.6.7", + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=10.10.0" + }, + "peerDependencies": { + "@firebase/app": "0.x" + } + }, + "admin/node_modules/@firebase/firestore-compat": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@firebase/firestore-compat/-/firestore-compat-0.3.17.tgz", + "integrity": "sha512-Qh3tbE4vkn9XvyWnRaJM/v4vhCZ+btk2RZcq037o6oECHohaCFortevd/SKA4vA5yOx0/DwARIEv6XwgHkVucg==", + "dependencies": { + "@firebase/component": "0.6.4", + "@firebase/firestore": "4.1.3", + "@firebase/firestore-types": "3.0.0", + "@firebase/util": "1.9.3", + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@firebase/app-compat": "0.x" + } + }, + "admin/node_modules/@firebase/firestore-types": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@firebase/firestore-types/-/firestore-types-3.0.0.tgz", + "integrity": "sha512-Meg4cIezHo9zLamw0ymFYBD4SMjLb+ZXIbuN7T7ddXN6MGoICmOTq3/ltdCGoDCS2u+H1XJs2u/cYp75jsX9Qw==", + "peerDependencies": { + "@firebase/app-types": "0.x", + "@firebase/util": "1.x" + } + }, + "admin/node_modules/@firebase/webchannel-wrapper": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@firebase/webchannel-wrapper/-/webchannel-wrapper-0.10.2.tgz", + "integrity": "sha512-xDxhD9++451HuCv3xKBEdSYaArX9NcokODXZYH/MxGw1XFFOz7OKkTRItZ5wf6npBN/inwp8dUZCP7SpAg46yQ==" + }, + "admin/node_modules/firebase": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/firebase/-/firebase-10.3.1.tgz", + "integrity": "sha512-lUk1X0SQocShyIwz5x9mj829Yn1y4Y9KWriGLZ0/Pbwqt4ZxElx8rI1p/YAi4MZTtT1qi0wazo7dAlmuF6J0Aw==", + "dependencies": { + "@firebase/analytics": "0.10.0", + "@firebase/analytics-compat": "0.2.6", + "@firebase/app": "0.9.18", + "@firebase/app-check": "0.8.0", + "@firebase/app-check-compat": "0.3.7", + "@firebase/app-compat": "0.2.18", + "@firebase/app-types": "0.9.0", + "@firebase/auth": "1.3.0", + "@firebase/auth-compat": "0.4.6", + "@firebase/database": "1.0.1", + "@firebase/database-compat": "1.0.1", + "@firebase/firestore": "4.1.3", + "@firebase/firestore-compat": "0.3.17", + "@firebase/functions": "0.10.0", + "@firebase/functions-compat": "0.3.5", + "@firebase/installations": "0.6.4", + "@firebase/installations-compat": "0.2.4", + "@firebase/messaging": "0.12.4", + "@firebase/messaging-compat": "0.2.4", + "@firebase/performance": "0.6.4", + "@firebase/performance-compat": "0.2.4", + "@firebase/remote-config": "0.4.4", + "@firebase/remote-config-compat": "0.2.4", + "@firebase/storage": "0.11.2", + "@firebase/storage-compat": "0.3.2", + "@firebase/util": "1.9.3" + } + }, + "admin/node_modules/node-fetch": { + "version": "2.6.7", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz", + "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "functions": { "name": "@socialincome/functions", "version": "1.0.0", "dependencies": { - "axios": "^1.4.0", + "axios": "^1.5.0", "dotenv": "^16.3.1", "firebase-admin": "^11.10.1", "firebase-functions": "^4.4.1", @@ -80,29 +278,29 @@ "i18next-resources-to-backend": "^1.1.4", "imap-simple": "^5.1.0", "lodash": "^4.17.21", - "luxon": "^3.4.0", + "luxon": "^3.4.2", "mailparser": "^3.6.5", "mjml": "^4.14.1", "nodemailer": "^6.9.4", "pdfkit": "^0.13.0", - "stripe": "^12.18.0", + "stripe": "^13.4.0", "tmp-promise": "^3.0.3", - "twilio": "^4.15.0" + "twilio": "^4.16.0" }, "devDependencies": { - "@jest/globals": "^29.6.2", - "@playwright/test": "^1.37.0", + "@jest/globals": "^29.6.4", + "@playwright/test": "^1.37.1", "@types/imap-simple": "^4.2.6", - "@types/jest": "^29.5.3", - "@types/luxon": "^3.3.1", + "@types/jest": "^29.5.4", + "@types/luxon": "^3.3.2", "@types/mailparser": "^3.4.0", "@types/pdfkit": "^0.12.10", "firebase-functions-test": "^3.1.0", - "jest": "^29.6.2", + "jest": "^29.6.4", "request": "^2.88.2", "ts-jest": "^29.1.1", "ts-loader": "^9.4.4", - "typescript": "^5.1.6" + "typescript": "^5.2.2" }, "engines": { "node": "18" @@ -4707,7 +4905,6 @@ "version": "1.8.21", "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.8.21.tgz", "integrity": "sha512-KeyQeZpxeEBSqFVTi3q2K7PiPXmgBfECc4updA1ejCLjYmoAlvvM3ZMp5ztTDUCUQmoY3CpDxvchjO1+rFkoHg==", - "devOptional": true, "dependencies": { "@grpc/proto-loader": "^0.7.0", "@types/node": ">=12.12.47" @@ -4720,7 +4917,6 @@ "version": "0.7.9", "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.9.tgz", "integrity": "sha512-YJsOehVXzgurc+lLAxYnlSMc1p/Gu6VAvnfx0ATi2nzvr0YZcjhmZDeY8SeAKv1M7zE3aEJH0Xo9mK1iZ8GYoQ==", - "devOptional": true, "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", @@ -4827,9 +5023,9 @@ "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" }, "node_modules/@icons-pack/react-simple-icons": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/@icons-pack/react-simple-icons/-/react-simple-icons-8.0.1.tgz", - "integrity": "sha512-lCdPSp+EFJKDabwQ16pQsTJKViwGa8naoYAnL0IpxQvl7E1CeQ7Z84BbJWhIustrrdNIZwcyuKg+ClPi7BXFWw==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@icons-pack/react-simple-icons/-/react-simple-icons-9.0.0.tgz", + "integrity": "sha512-2ZLcJKCmz0VESaKbuiJ8ks4Qd8fldTdK63JkO3bLgD0GVXQi994jy7/1Kd+mIrMmrSMGPe23+DGGx5g9aAsc2w==", "peerDependencies": { "react": "^16.13 || ^17 || ^18" } @@ -5810,12 +6006,12 @@ } }, "node_modules/@mui/x-data-grid": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-6.12.0.tgz", - "integrity": "sha512-ZuQ8Uq/dF6gjrE/qU6VvP3tgy9n78DdCMD6hbXy/uDIoddJ4J8hSn9S6flnFnFQbRZzF/Q/pPWXZTR4oeg8NQg==", + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/@mui/x-data-grid/-/x-data-grid-6.12.1.tgz", + "integrity": "sha512-lSY1dFBv6yh2ffkkWeMM9c0ajpwIWn/da/ec0kY8OfLa79Hboh53mN09nopylZO8MHJGfDlPvduwuWcgWs+zFw==", "dependencies": { "@babel/runtime": "^7.22.11", - "@mui/utils": "^5.14.5", + "@mui/utils": "^5.14.7", "clsx": "^2.0.0", "prop-types": "^15.8.1", "reselect": "^4.1.8" @@ -5843,12 +6039,12 @@ } }, "node_modules/@mui/x-date-pickers": { - "version": "6.12.0", - "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-6.12.0.tgz", - "integrity": "sha512-lEfdPKdr2o2jUvEviYB/xaYaHJ3Gf9u/AvU3eCX6R0mzIpi1h1SsmrFOTcBIFkwz1iekUNIdZjfrkKmLX+n6dA==", + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/@mui/x-date-pickers/-/x-date-pickers-6.12.1.tgz", + "integrity": "sha512-euMM7KNbqoOgIdf5P8T8KG74qqbpDvLp5k8yEVMx1zHeSiSZGofKpQrDFAMxjJRnJ0x1aJLIhFEc46O70fSAlA==", "dependencies": { "@babel/runtime": "^7.22.11", - "@mui/utils": "^5.14.5", + "@mui/utils": "^5.14.7", "@types/react-transition-group": "^4.4.6", "clsx": "^2.0.0", "prop-types": "^15.8.1", @@ -5927,9 +6123,9 @@ } }, "node_modules/@next/env": { - "version": "13.4.16", - "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.16.tgz", - "integrity": "sha512-pCU0sJBqdfKP9mwDadxvZd+eLz3fZrTlmmDHY12Hdpl3DD0vy8ou5HWKVfG0zZS6tqhL4wnQqRbspdY5nqa7MA==" + "version": "13.4.19", + "resolved": "https://registry.npmjs.org/@next/env/-/env-13.4.19.tgz", + "integrity": "sha512-FsAT5x0jF2kkhNkKkukhsyYOrRqtSxrEhfliniIq0bwWbuXLgyt3Gv0Ml+b91XwjwArmuP7NxCiGd++GGKdNMQ==" }, "node_modules/@next/eslint-plugin-next": { "version": "13.4.19", @@ -5961,9 +6157,9 @@ } }, "node_modules/@next/swc-darwin-arm64": { - "version": "13.4.16", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.16.tgz", - "integrity": "sha512-Rl6i1uUq0ciRa3VfEpw6GnWAJTSKo9oM2OrkGXPsm7rMxdd2FR5NkKc0C9xzFCI4+QtmBviWBdF2m3ur3Nqstw==", + "version": "13.4.19", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-13.4.19.tgz", + "integrity": "sha512-vv1qrjXeGbuF2mOkhkdxMDtv9np7W4mcBtaDnHU+yJG+bBwa6rYsYSCI/9Xm5+TuF5SbZbrWO6G1NfTh1TMjvQ==", "cpu": [ "arm64" ], @@ -5976,9 +6172,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "13.4.16", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.16.tgz", - "integrity": "sha512-o1vIKYbZORyDmTrPV1hApt9NLyWrS5vr2p5hhLGpOnkBY1cz6DAXjv8Lgan8t6X87+83F0EUDlu7klN8ieZ06A==", + "version": "13.4.19", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-13.4.19.tgz", + "integrity": "sha512-jyzO6wwYhx6F+7gD8ddZfuqO4TtpJdw3wyOduR4fxTUCm3aLw7YmHGYNjS0xRSYGAkLpBkH1E0RcelyId6lNsw==", "cpu": [ "x64" ], @@ -5991,9 +6187,9 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "13.4.16", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.16.tgz", - "integrity": "sha512-JRyAl8lCfyTng4zoOmE6hNI2f1MFUr7JyTYCHl1RxX42H4a5LMwJhDVQ7a9tmDZ/yj+0hpBn+Aan+d6lA3v0UQ==", + "version": "13.4.19", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-13.4.19.tgz", + "integrity": "sha512-vdlnIlaAEh6H+G6HrKZB9c2zJKnpPVKnA6LBwjwT2BTjxI7e0Hx30+FoWCgi50e+YO49p6oPOtesP9mXDRiiUg==", "cpu": [ "arm64" ], @@ -6006,9 +6202,9 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "13.4.16", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.16.tgz", - "integrity": "sha512-9gqVqNzUMWbUDgDiND18xoUqhwSm2gmksqXgCU0qaOKt6oAjWz8cWYjgpPVD0WICKFylEY/gvPEP1fMZDVFZ/g==", + "version": "13.4.19", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-13.4.19.tgz", + "integrity": "sha512-aU0HkH2XPgxqrbNRBFb3si9Ahu/CpaR5RPmN2s9GiM9qJCiBBlZtRTiEca+DC+xRPyCThTtWYgxjWHgU7ZkyvA==", "cpu": [ "arm64" ], @@ -6021,9 +6217,9 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "13.4.16", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.16.tgz", - "integrity": "sha512-KcQGwchAKmZVPa8i5PLTxvTs1/rcFnSltfpTm803Tr/BtBV3AxCkHLfhtoyVtVzx/kl/oue8oS+DSmbepQKwhw==", + "version": "13.4.19", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-13.4.19.tgz", + "integrity": "sha512-htwOEagMa/CXNykFFeAHHvMJeqZfNQEoQvHfsA4wgg5QqGNqD5soeCer4oGlCol6NGUxknrQO6VEustcv+Md+g==", "cpu": [ "x64" ], @@ -6036,9 +6232,9 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "13.4.16", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.16.tgz", - "integrity": "sha512-2RbMZNxYnJmW8EPHVBsGZPq5zqWAyBOc/YFxq/jIQ/Yn3RMFZ1dZVCjtIcsiaKmgh7mjA/W0ApbumutHNxRqqQ==", + "version": "13.4.19", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-13.4.19.tgz", + "integrity": "sha512-4Gj4vvtbK1JH8ApWTT214b3GwUh9EKKQjY41hH/t+u55Knxi/0wesMzwQRhppK6Ddalhu0TEttbiJ+wRcoEj5Q==", "cpu": [ "x64" ], @@ -6051,9 +6247,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "13.4.16", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.16.tgz", - "integrity": "sha512-thDcGonELN7edUKzjzlHrdoKkm7y8IAdItQpRvvMxNUXa4d9r0ElofhTZj5emR7AiXft17hpen+QAkcWpqG7Jg==", + "version": "13.4.19", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-13.4.19.tgz", + "integrity": "sha512-bUfDevQK4NsIAHXs3/JNgnvEY+LRyneDN788W2NYiRIIzmILjba7LaQTfihuFawZDhRtkYCv3JDC3B4TwnmRJw==", "cpu": [ "arm64" ], @@ -6066,9 +6262,9 @@ } }, "node_modules/@next/swc-win32-ia32-msvc": { - "version": "13.4.16", - "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.16.tgz", - "integrity": "sha512-f7SE1Mo4JAchUWl0LQsbtySR9xCa+x55C0taetjUApKtcLR3AgAjASrrP+oE1inmLmw573qRnE1eZN8YJfEBQw==", + "version": "13.4.19", + "resolved": "https://registry.npmjs.org/@next/swc-win32-ia32-msvc/-/swc-win32-ia32-msvc-13.4.19.tgz", + "integrity": "sha512-Y5kikILFAr81LYIFaw6j/NrOtmiM4Sf3GtOc0pn50ez2GCkr+oejYuKGcwAwq3jiTKuzF6OF4iT2INPoxRycEA==", "cpu": [ "ia32" ], @@ -6081,9 +6277,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "13.4.16", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.16.tgz", - "integrity": "sha512-WamDZm1M/OEM4QLce3lOmD1XdLEl37zYZwlmOLhmF7qYJ2G6oYm9+ejZVv+LakQIsIuXhSpVlOvrxIAHqwRkPQ==", + "version": "13.4.19", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-13.4.19.tgz", + "integrity": "sha512-YzA78jBDXMYiINdPdJJwGgPNT3YqBNNGhsthsDoWHL9p24tEJn9ViQf/ZqTbwSpX/RrkPupLfuuTH2sf73JBAw==", "cpu": [ "x64" ], @@ -9941,9 +10137,9 @@ "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" }, "node_modules/@types/luxon": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.3.1.tgz", - "integrity": "sha512-XOS5nBcgEeP2PpcqJHjCWhUCAzGfXIU8ILOSLpx2FhxqMW9KdxgCGXNOEKGVBfveKtIpztHzKK5vSRVLyW/NqA==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/@types/luxon/-/luxon-3.3.2.tgz", + "integrity": "sha512-l5cpE57br4BIjK+9BSkFBOsWtwv6J9bJpC7gdXIzZyI0vuKvNTk0wZZrkQxMGsUAuGW9+WMNWF2IJMD7br2yeQ==", "dev": true }, "node_modules/@types/mailparser": { @@ -25150,11 +25346,11 @@ } }, "node_modules/next": { - "version": "13.4.16", - "resolved": "https://registry.npmjs.org/next/-/next-13.4.16.tgz", - "integrity": "sha512-1xaA/5DrfpPu0eV31Iro7JfPeqO8uxQWb1zYNTe+KDKdzqkAGapLcDYHMLNKXKB7lHjZ7LfKUOf9dyuzcibrhA==", + "version": "13.4.19", + "resolved": "https://registry.npmjs.org/next/-/next-13.4.19.tgz", + "integrity": "sha512-HuPSzzAbJ1T4BD8e0bs6B9C1kWQ6gv8ykZoRWs5AQoiIuqbGHHdQO7Ljuvg05Q0Z24E2ABozHe6FxDvI6HfyAw==", "dependencies": { - "@next/env": "13.4.16", + "@next/env": "13.4.19", "@swc/helpers": "0.5.1", "busboy": "1.6.0", "caniuse-lite": "^1.0.30001406", @@ -25170,15 +25366,15 @@ "node": ">=16.8.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "13.4.16", - "@next/swc-darwin-x64": "13.4.16", - "@next/swc-linux-arm64-gnu": "13.4.16", - "@next/swc-linux-arm64-musl": "13.4.16", - "@next/swc-linux-x64-gnu": "13.4.16", - "@next/swc-linux-x64-musl": "13.4.16", - "@next/swc-win32-arm64-msvc": "13.4.16", - "@next/swc-win32-ia32-msvc": "13.4.16", - "@next/swc-win32-x64-msvc": "13.4.16" + "@next/swc-darwin-arm64": "13.4.19", + "@next/swc-darwin-x64": "13.4.19", + "@next/swc-linux-arm64-gnu": "13.4.19", + "@next/swc-linux-arm64-musl": "13.4.19", + "@next/swc-linux-x64-gnu": "13.4.19", + "@next/swc-linux-x64-musl": "13.4.19", + "@next/swc-win32-arm64-msvc": "13.4.19", + "@next/swc-win32-ia32-msvc": "13.4.19", + "@next/swc-win32-x64-msvc": "13.4.19" }, "peerDependencies": { "@opentelemetry/api": "^1.1.0", @@ -26334,9 +26530,9 @@ "dev": true }, "node_modules/postcss": { - "version": "8.4.28", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.28.tgz", - "integrity": "sha512-Z7V5j0cq8oEKyejIKfpD8b4eBy9cwW2JWPk0+fB1HOAMsfHbnAXLLS+PfVWlzMSLQaWttKDt607I0XHmpE67Vw==", + "version": "8.4.29", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.29.tgz", + "integrity": "sha512-cbI+jaqIeu/VGqXEarWkRCCffhjgXc0qjBtXpqJhTBohMUjUQnbBr0xqX3vEKudc4iviTewcJo5ajcec5+wdJw==", "funding": [ { "type": "opencollective", @@ -32145,9 +32341,9 @@ } }, "node_modules/stripe": { - "version": "12.18.0", - "resolved": "https://registry.npmjs.org/stripe/-/stripe-12.18.0.tgz", - "integrity": "sha512-cYjgBM2SY/dTm8Lr6eMyyONaHTZHA/QjHxFUIW5WH8FevSRIGAVtXEmBkUXF1fsqe7QvvRgQSGSJZmjDacegGg==", + "version": "13.4.0", + "resolved": "https://registry.npmjs.org/stripe/-/stripe-13.4.0.tgz", + "integrity": "sha512-UxvRzu46AJALIueMH3/jn++qJlOoM5s+uoHXagr36xTFOj7Knrh28WFiI73dMDkngBElK68cG3WI+LgRulHw6g==", "dependencies": { "@types/node": ">=8.1.0", "qs": "^6.11.0" @@ -32384,18 +32580,18 @@ } }, "node_modules/survey-core": { - "version": "1.9.104", - "resolved": "https://registry.npmjs.org/survey-core/-/survey-core-1.9.104.tgz", - "integrity": "sha512-tMXD8kPi8IFgdMeFUnZAlxUPypSy3zf3+hxNBzRI4W1MI6FuVceT0AuHrdHjcBhaJu7YN6lCgO6c3s0ioaZ1oQ==" + "version": "1.9.105", + "resolved": "https://registry.npmjs.org/survey-core/-/survey-core-1.9.105.tgz", + "integrity": "sha512-n3H+lfU+xtDPeEcGkPA6QvOexBmgRSDMzjidOHTg41mxurY1sQilZl3MmAblDcComtSg41CaRxfUpLXmzuYhXA==" }, "node_modules/survey-react-ui": { - "version": "1.9.104", - "resolved": "https://registry.npmjs.org/survey-react-ui/-/survey-react-ui-1.9.104.tgz", - "integrity": "sha512-lXLilhbt+38Rz2QC47BSm4SOmsrx5sPMcnwAbF1hSzArKDykZ6FNqbpv50AOAFUM3Bs8Itm/b8wwl/gkb1kaXQ==", + "version": "1.9.105", + "resolved": "https://registry.npmjs.org/survey-react-ui/-/survey-react-ui-1.9.105.tgz", + "integrity": "sha512-1jybup6eptCyGyeRbtALjrAwS2RYO/k9TPgbVsCkVJ5kYRuwXFH+S5azCpRi7j7UIqfQTdW02p5sS4uhu4cHJw==", "dependencies": { "react": "^16.5.0 || ^17.0.1 || ^18.1.0", "react-dom": "^16.5.0 || ^17.0.1 || ^18.1.0", - "survey-core": "1.9.104" + "survey-core": "1.9.105" } }, "node_modules/svg-parser": { @@ -35415,16 +35611,16 @@ "name": "@socialincome/shared", "version": "1.0.0", "dependencies": { - "axios": "^1.4.0", + "axios": "^1.5.0", "firebase-admin": "^11.10.1", "handlebars": "^4.7.8", "handlebars-i18next": "^1.0.3", - "i18next": "^23.4.4", + "i18next": "^23.4.6", "i18next-resources-to-backend": "^1.1.4", - "luxon": "^3.4.0", + "luxon": "^3.4.2", "mjml": "^4.14.1", "nodemailer": "^6.9.4", - "stripe": "^12.18.0", + "stripe": "^13.4.0", "twilio": "^4.15.0" }, "devDependencies": { @@ -35550,43 +35746,43 @@ "name": "@socialincome/website", "version": "1.0.0", "dependencies": { - "@headlessui/react": "^1.7.16", + "@headlessui/react": "^1.7.17", "@heroicons/react": "^2.0.18", - "@icons-pack/react-simple-icons": "^8.0.1", + "@icons-pack/react-simple-icons": "^9.0.0", "@socialincome/shared": "^1.0.0", "@socialincome/ui": "^1.0.0", - "@tanstack/react-query": "^4.32.6", + "@tanstack/react-query": "^4.33.0", "@vimeo/player": "^2.20.1", "accept-language-parser": "^1.5.0", "classnames": "^2.3.2", "firebase": "^9.23.0", - "flag-icons": "^6.10.0", + "flag-icons": "^6.11.0", "formik": "^2.4.3", - "i18next": "^23.4.4", + "i18next": "^23.4.6", "lodash": "^4.17.21", - "next": "13.4.16", + "next": "13.4.19", "react": "18.2.0", "react-dom": "18.2.0", "react-hot-toast": "^2.4.1", "reactfire": "^4.2.3", - "recharts": "^2.7.3", + "recharts": "^2.8.0", "server-only": "^0.0.1", - "stripe": "^12.18.0", - "survey-core": "^1.9.103", - "survey-react-ui": "^1.9.103" + "stripe": "^13.4.0", + "survey-core": "^1.9.105", + "survey-react-ui": "^1.9.105" }, "devDependencies": { "@types/accept-language-parser": "^1.5.3", - "@types/node": "^20.5.0", - "@types/react": "^18.2.20", + "@types/node": "^20.5.7", + "@types/react": "^18.2.21", "@types/react-dom": "^18.2.7", "@types/vimeo__player": "^2.18.0", "autoprefixer": "^10.4.15", - "eslint": "^8.47.0", - "eslint-config-next": "^13.4.16", - "postcss": "^8.4.28", + "eslint": "^8.48.0", + "eslint-config-next": "^13.4.19", + "postcss": "^8.4.29", "tailwindcss": "^3.3.3", - "typescript": "^5.1.6" + "typescript": "^5.2.2" } } } diff --git a/package.json b/package.json index fa35e4b69..822aa6d15 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,6 @@ "prettier": "3.0.0", "prettier-plugin-organize-imports": "3.2.3", "prettier-plugin-tailwindcss": "0.4.1", - "typescript": "^5.1.6" + "typescript": "^5.2.2" } } diff --git a/shared/locales/de/website-home.json b/shared/locales/de/website-home.json index e056d972f..91dcc1586 100644 --- a/shared/locales/de/website-home.json +++ b/shared/locales/de/website-home.json @@ -3,7 +3,8 @@ "title-1": "Wie vielen Menschen kannst Du mit 1 % deines Schweizer Einkommens ", "title-2": "aus der Armut helfen?", "title-3": "", - "income-text": "Gib dein monatliches Einkommen ein und schau, was du bewirken kannst." + "income-text": "Gib dein monatliches Einkommen ein und schau, was du bewirken kannst.", + "button-text": "Beitrag berechnen" }, "section-2": { "title-1": "Was würde sich in deinem Alltag ändern, ", diff --git a/shared/locales/en/website-home.json b/shared/locales/en/website-home.json index 3524afb3a..9653b5a7d 100644 --- a/shared/locales/en/website-home.json +++ b/shared/locales/en/website-home.json @@ -3,7 +3,8 @@ "title-1": "How many people can you ", "title-2": "lift out of poverty ", "title-3": "with 1% of your income?", - "income-text": "Gib dein monatliches Einkommen ein und schau, was du bewirken kannst." + "income-text": "Enter your monthly income and calculate your impact.", + "button-text": "Show my Impact" }, "section-2": { "title-1": "What would change ", diff --git a/shared/package.json b/shared/package.json index 3b9e01bc1..728acbc8d 100644 --- a/shared/package.json +++ b/shared/package.json @@ -17,16 +17,16 @@ "ts-jest": "^29.1.1" }, "dependencies": { - "axios": "^1.4.0", + "axios": "^1.5.0", "firebase-admin": "^11.10.1", "handlebars": "^4.7.8", "handlebars-i18next": "^1.0.3", - "i18next": "^23.4.4", + "i18next": "^23.4.6", "i18next-resources-to-backend": "^1.1.4", - "luxon": "^3.4.0", + "luxon": "^3.4.2", "mjml": "^4.14.1", "nodemailer": "^6.9.4", - "stripe": "^12.18.0", + "stripe": "^13.4.0", "twilio": "^4.15.0" } } diff --git a/shared/src/stripe/StripeEventHandler.ts b/shared/src/stripe/StripeEventHandler.ts index 011788aae..31f47d089 100644 --- a/shared/src/stripe/StripeEventHandler.ts +++ b/shared/src/stripe/StripeEventHandler.ts @@ -23,7 +23,7 @@ export class StripeEventHandler { this.firestoreAdmin = firestoreAdmin; this.stripe = new Stripe(apiKey, { typescript: true, - apiVersion: '2022-11-15', + apiVersion: '2023-08-16', }); } @@ -57,15 +57,16 @@ export class StripeEventHandler { * Try to find an existing user using create a new on. */ getOrCreateUser = async (customer: Stripe.Customer): Promise> => { - const userRef = await this.findUser(customer); - if (!userRef) { + const userDoc = await this.findUser(customer); + if (!userDoc) { console.info(`User not found for stripe customer: ${customer.id}`); const userToCreate = this.constructUser(customer); const newUserRef = await this.firestoreAdmin.collection(USER_FIRESTORE_PATH).add(userToCreate); console.info(`New user created for Stripe user: ${customer.id}, user id: ${newUserRef.id}`); return newUserRef; } else { - return userRef.ref; + await userDoc.ref.update({ stripe_customer_id: customer.id }); + return userDoc.ref; } }; diff --git a/shared/src/stripe/StripeWebhookHandler.test.ts b/shared/src/stripe/StripeWebhookHandler.test.ts index 91f39cc9c..42d970375 100644 --- a/shared/src/stripe/StripeWebhookHandler.test.ts +++ b/shared/src/stripe/StripeWebhookHandler.test.ts @@ -146,8 +146,6 @@ describe('stripeWebhook', () => { currency: 'usd', customer: 'cus_123', description: 'Subscription update', - destination: null, - dispute: null, disputed: false, failure_balance_transaction: null, failure_code: null, diff --git a/shared/src/stripe/index.ts b/shared/src/stripe/index.ts index 5515c36f9..8a388cc92 100644 --- a/shared/src/stripe/index.ts +++ b/shared/src/stripe/index.ts @@ -3,6 +3,6 @@ import Stripe from 'stripe'; export const initializeStripe = (apiKey: string) => { return new Stripe(apiKey, { typescript: true, - apiVersion: '2022-11-15', + apiVersion: '2023-08-16', }); }; diff --git a/ui/src/components/containers/base-container.tsx b/ui/src/components/containers/base-container.tsx index 386cd9f07..22a6021e2 100644 --- a/ui/src/components/containers/base-container.tsx +++ b/ui/src/components/containers/base-container.tsx @@ -8,7 +8,7 @@ interface BaseContainerProps { export function BaseContainer({ children, className }: PropsWithChildren) { return (
-
{children}
+
{children}
); } diff --git a/website/package.json b/website/package.json index 45f689da7..771dd283d 100644 --- a/website/package.json +++ b/website/package.json @@ -18,42 +18,42 @@ "lint": "next lint" }, "dependencies": { - "@headlessui/react": "^1.7.16", + "@headlessui/react": "^1.7.17", "@heroicons/react": "^2.0.18", - "@icons-pack/react-simple-icons": "^8.0.1", + "@icons-pack/react-simple-icons": "^9.0.0", "@socialincome/shared": "^1.0.0", "@socialincome/ui": "^1.0.0", - "@tanstack/react-query": "^4.32.6", + "@tanstack/react-query": "^4.33.0", "@vimeo/player": "^2.20.1", "accept-language-parser": "^1.5.0", "classnames": "^2.3.2", "firebase": "^9.23.0", - "flag-icons": "^6.10.0", + "flag-icons": "^6.11.0", "formik": "^2.4.3", - "i18next": "^23.4.4", + "i18next": "^23.4.6", "lodash": "^4.17.21", - "next": "13.4.16", + "next": "13.4.19", "react": "18.2.0", "react-dom": "18.2.0", "react-hot-toast": "^2.4.1", "reactfire": "^4.2.3", - "recharts": "^2.7.3", + "recharts": "^2.8.0", "server-only": "^0.0.1", - "stripe": "^12.18.0", - "survey-core": "^1.9.103", - "survey-react-ui": "^1.9.103" + "stripe": "^13.4.0", + "survey-core": "^1.9.105", + "survey-react-ui": "^1.9.105" }, "devDependencies": { "@types/accept-language-parser": "^1.5.3", - "@types/node": "^20.5.0", - "@types/react": "^18.2.20", + "@types/node": "^20.5.7", + "@types/react": "^18.2.21", "@types/react-dom": "^18.2.7", "@types/vimeo__player": "^2.18.0", "autoprefixer": "^10.4.15", - "eslint": "^8.47.0", - "eslint-config-next": "^13.4.16", - "postcss": "^8.4.28", + "eslint": "^8.48.0", + "eslint-config-next": "^13.4.19", + "postcss": "^8.4.29", "tailwindcss": "^3.3.3", - "typescript": "^5.1.6" + "typescript": "^5.2.2" } } diff --git a/website/src/app/[lang]/[country]/(website)/(home)/section-1-input.tsx b/website/src/app/[lang]/[country]/(website)/(home)/section-1-input.tsx index 30322ecb3..69a2d13f4 100644 --- a/website/src/app/[lang]/[country]/(website)/(home)/section-1-input.tsx +++ b/website/src/app/[lang]/[country]/(website)/(home)/section-1-input.tsx @@ -1,38 +1,39 @@ 'use client'; import { Button, Input } from '@socialincome/ui'; +import { Field, Form, Formik } from 'formik'; import { useRouter } from 'next/navigation'; -import { useState } from 'react'; interface Section1InputProps { text: string; } + +// TODO: i18n export default function Section1Input({ text }: Section1InputProps) { - const [amount, setAmount] = useState(0); const router = useRouter(); + const onSubmit = (values: { amount: number | string }) => { + router.push(`/donate?amount=${(Number(values.amount) / 100).toFixed(2)}`); + }; + return ( - <> - setAmount(Number(e.target.value))} - value={amount} - /> - - + + {({ values, handleChange, handleBlur, handleSubmit }) => ( +
+ + + + )} +
); } diff --git a/website/src/app/[lang]/[country]/(website)/(home)/section-1.tsx b/website/src/app/[lang]/[country]/(website)/(home)/section-1.tsx index 4ecbaa12d..063ee5233 100644 --- a/website/src/app/[lang]/[country]/(website)/(home)/section-1.tsx +++ b/website/src/app/[lang]/[country]/(website)/(home)/section-1.tsx @@ -21,9 +21,9 @@ export default async function Section1({ params }: DefaultPageProps) { {translator.t('section-1.title-3')} -
+
{translator.t('section-1.income-text')} - +
diff --git a/website/src/app/[lang]/[country]/(website)/(home)/section-2.tsx b/website/src/app/[lang]/[country]/(website)/(home)/section-2.tsx index ebec1f3d2..c817b5f95 100644 --- a/website/src/app/[lang]/[country]/(website)/(home)/section-2.tsx +++ b/website/src/app/[lang]/[country]/(website)/(home)/section-2.tsx @@ -61,7 +61,7 @@ export default function Section2({ vimeoVideoId, translations }: Section2Props) {translations.videoButton} - + diff --git a/website/src/app/[lang]/[country]/(website)/faq/page.tsx b/website/src/app/[lang]/[country]/(website)/faq/page.tsx new file mode 100644 index 000000000..c1dff9f7a --- /dev/null +++ b/website/src/app/[lang]/[country]/(website)/faq/page.tsx @@ -0,0 +1,5 @@ +import { Typography } from '@socialincome/ui'; + +export default async function Page() { + return Coming soon; +} diff --git a/website/src/app/[lang]/[country]/(website)/me/contributions/contributions-table.tsx b/website/src/app/[lang]/[country]/(website)/me/contributions/contributions-table.tsx index 8a16a8a0f..ab5eb51df 100644 --- a/website/src/app/[lang]/[country]/(website)/me/contributions/contributions-table.tsx +++ b/website/src/app/[lang]/[country]/(website)/me/contributions/contributions-table.tsx @@ -3,11 +3,11 @@ import { DefaultParams } from '@/app/[lang]/[country]'; import { UserContext } from '@/app/[lang]/[country]/(website)/me/user-context-provider'; import { useTranslator } from '@/hooks/useTranslator'; -import { CONTRIBUTION_FIRESTORE_PATH, USER_FIRESTORE_PATH } from '@socialincome/shared/src/types'; +import { CONTRIBUTION_FIRESTORE_PATH, StatusKey, USER_FIRESTORE_PATH } from '@socialincome/shared/src/types'; import { toDateTime } from '@socialincome/shared/src/utils/date'; import { Table, Typography } from '@socialincome/ui'; import { useQuery } from '@tanstack/react-query'; -import { collection, getDocs, query } from 'firebase/firestore'; +import { collection, getDocs, query, where } from 'firebase/firestore'; import { useContext } from 'react'; import { useFirestore } from 'reactfire'; @@ -27,7 +27,12 @@ export function ContributionsTable({ lang, translations }: ContributionsTablePro [user], async () => { if (user && firestore) { - return await getDocs(query(collection(firestore, USER_FIRESTORE_PATH, user.id, CONTRIBUTION_FIRESTORE_PATH))); + return await getDocs( + query( + collection(firestore, USER_FIRESTORE_PATH, user.id, CONTRIBUTION_FIRESTORE_PATH), + where('status', '==', StatusKey.SUCCEEDED), + ), + ); } else return null; }, { @@ -36,10 +41,14 @@ export function ContributionsTable({ lang, translations }: ContributionsTablePro ); return ( - +
- {translations.date} - {translations.amount} + + {translations.date} + + + {translations.amount} + {contributions?.docs.map((contribution, index) => { diff --git a/website/src/app/[lang]/[country]/(website)/me/contributions/page.tsx b/website/src/app/[lang]/[country]/(website)/me/contributions/page.tsx index d3a1bf272..77ad35c88 100644 --- a/website/src/app/[lang]/[country]/(website)/me/contributions/page.tsx +++ b/website/src/app/[lang]/[country]/(website)/me/contributions/page.tsx @@ -7,11 +7,13 @@ export default async function Page({ params }: DefaultPageProps) { const translator = await Translator.getInstance({ language: params.lang, namespaces: ['website-me'] }); return ( -
- +
+
+ +
); diff --git a/website/src/app/[lang]/[country]/(website)/transparency/[currency]/charts/page.tsx b/website/src/app/[lang]/[country]/(website)/transparency/[currency]/charts/page.tsx index 5ca02ab79..47ffacb3d 100644 --- a/website/src/app/[lang]/[country]/(website)/transparency/[currency]/charts/page.tsx +++ b/website/src/app/[lang]/[country]/(website)/transparency/[currency]/charts/page.tsx @@ -1,5 +1,5 @@ import { DefaultPageProps } from '@/app/[lang]/[country]'; -import { firestoreAdmin } from '@/firebase/admin'; +import { firestoreAdmin } from '@/firebase-admin'; import { ValidCountry, WebsiteLanguage } from '@/i18n'; import { ContributionStatsCalculator } from '@socialincome/shared/src/utils/stats/ContributionStatsCalculator'; import { PaymentStatsCalculator } from '@socialincome/shared/src/utils/stats/PaymentStatsCalculator'; diff --git a/website/src/app/[lang]/[country]/(website)/transparency/[currency]/page.tsx b/website/src/app/[lang]/[country]/(website)/transparency/[currency]/page.tsx index 407881db9..b1e9778b4 100644 --- a/website/src/app/[lang]/[country]/(website)/transparency/[currency]/page.tsx +++ b/website/src/app/[lang]/[country]/(website)/transparency/[currency]/page.tsx @@ -1,7 +1,7 @@ import { DefaultPageProps } from '@/app/[lang]/[country]'; import { contributionStats } from '@/app/[lang]/[country]/(website)/transparency/[currency]/contribution-stats'; import { paymentStats } from '@/app/[lang]/[country]/(website)/transparency/[currency]/payment-stats'; -import { firestoreAdmin } from '@/firebase/admin'; +import { firestoreAdmin } from '@/firebase-admin'; import { ValidCountry, WebsiteLanguage } from '@/i18n'; import { ContributionStatsCalculator } from '@socialincome/shared/src/utils/stats/ContributionStatsCalculator'; import { PaymentStatsCalculator } from '@socialincome/shared/src/utils/stats/PaymentStatsCalculator'; diff --git a/website/src/app/api/stripe/billing-portal/route.ts b/website/src/app/api/stripe/billing-portal/route.ts index 267f4a58f..815c0fbac 100644 --- a/website/src/app/api/stripe/billing-portal/route.ts +++ b/website/src/app/api/stripe/billing-portal/route.ts @@ -1,5 +1,5 @@ -import { authAdmin, firestoreAdmin } from '@/firebase/admin'; -import { StripeEventHandler } from '@socialincome/shared/src/stripe/StripeEventHandler'; +import { authAdmin, firestoreAdmin } from '@/firebase-admin'; +import { initializeStripe } from '@socialincome/shared/src/stripe'; import { USER_FIRESTORE_PATH, User } from '@socialincome/shared/src/types'; import { NextResponse } from 'next/server'; @@ -11,22 +11,15 @@ export async function GET(request: Request) { return new Response(null, { status: 400, statusText: 'Missing accessToken or returnUrl' }); } + const stripe = initializeStripe(process.env.STRIPE_SECRET_KEY!); const decodedToken = await authAdmin.auth.verifyIdToken(accessToken, true); - const userDoc = await firestoreAdmin.findFirst(USER_FIRESTORE_PATH, (q) => q.where('authUserId', '==', decodedToken.uid), ); - - const stripeEventHandler = new StripeEventHandler(process.env.STRIPE_SECRET_KEY!, firestoreAdmin); - // const stripeCustomer = await stripeEventHandler.stripe.customers.retrieve(userDoc?.get('stripe_customer_id'), { - // expand: ['subscriptions'], - // }); - - const session = await stripeEventHandler.stripe.billingPortal.sessions.create({ + const session = await stripe.billingPortal.sessions.create({ customer: userDoc?.get('stripe_customer_id'), return_url: returnUrl, locale: userDoc?.get('language'), }); - return NextResponse.json(session); } diff --git a/website/src/app/api/stripe/checkout/success/route.ts b/website/src/app/api/stripe/checkout/success/route.ts index c7143e799..7e1cc22fb 100644 --- a/website/src/app/api/stripe/checkout/success/route.ts +++ b/website/src/app/api/stripe/checkout/success/route.ts @@ -1,4 +1,4 @@ -import { firestoreAdmin } from '@/firebase/admin'; +import { firestoreAdmin } from '@/firebase-admin'; import { StripeEventHandler } from '@socialincome/shared/src/stripe/StripeEventHandler'; export async function GET(request: Request) { diff --git a/website/src/app/api/user/create-auth-user/route.ts b/website/src/app/api/user/create-auth-user/route.ts index 106f3bc45..7920ef3fa 100644 --- a/website/src/app/api/user/create-auth-user/route.ts +++ b/website/src/app/api/user/create-auth-user/route.ts @@ -1,4 +1,4 @@ -import { authAdmin, firestoreAdmin } from '@/firebase/admin'; +import { authAdmin, firestoreAdmin } from '@/firebase-admin'; import { USER_FIRESTORE_PATH, User } from '@socialincome/shared/src/types'; import { NextResponse } from 'next/server'; diff --git a/website/src/app/providers.tsx b/website/src/app/providers.tsx index c4c0756ea..20da04354 100644 --- a/website/src/app/providers.tsx +++ b/website/src/app/providers.tsx @@ -1,13 +1,21 @@ 'use client'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; +import { Analytics, getAnalytics, isSupported as isAnalyticsSupported } from 'firebase/analytics'; import { connectAuthEmulator, getAuth } from 'firebase/auth'; import { connectFirestoreEmulator, getFirestore } from 'firebase/firestore'; import { connectFunctionsEmulator, getFunctions } from 'firebase/functions'; import { connectStorageEmulator, getStorage } from 'firebase/storage'; -import { PropsWithChildren } from 'react'; +import { PropsWithChildren, useEffect, useState } from 'react'; import { Toaster } from 'react-hot-toast'; -import { AuthProvider, FirebaseAppProvider, FirestoreProvider, StorageProvider, useFirebaseApp } from 'reactfire'; +import { + AnalyticsProvider, + AuthProvider, + FirebaseAppProvider, + FirestoreProvider, + StorageProvider, + useFirebaseApp, +} from 'reactfire'; // These variables are needed so that the emulators are only initialized once. Probably due to the React Strict mode, it // happens that the emulators get initialized multiple times in the development environment. @@ -16,6 +24,28 @@ let connectFirestoreEmulatorCalled = false; let connectStorageEmulatorCalled = false; let connectFunctionsEmulatorCalled = false; +function AnalyticsProviderWrapper({ children }: PropsWithChildren) { + const app = useFirebaseApp(); + const [analytics, setAnalytics] = useState(null); + + useEffect(() => { + if (process.env.NEXT_PUBLIC_FIREBASE_APP_ID) { + isAnalyticsSupported().then((isSupported) => { + if (isSupported) { + console.log('Using analytics'); + setAnalytics(getAnalytics(app)); + } + }); + } + }, [app]); + + if (analytics) { + return {children}; + } else { + return children; + } +} + function FirebaseSDKProviders({ children }: PropsWithChildren) { const app = useFirebaseApp(); const auth = getAuth(app); @@ -55,7 +85,9 @@ function FirebaseSDKProviders({ children }: PropsWithChildren) { return ( - {children} + + {children} + ); @@ -64,8 +96,12 @@ function FirebaseSDKProviders({ children }: PropsWithChildren) { export function Providers({ children }: PropsWithChildren) { const firebaseConfig = { apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY, + appId: process.env.NEXT_PUBLIC_FIREBASE_APP_ID, authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, + measurementId: process.env.NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID, + messagingSenderId: process.env.NEXT_PUBLIC_FIREBASE_MESSAGING_SENDER_ID, projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID, + storageBucket: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_BUCKET, }; const queryClient = new QueryClient(); diff --git a/website/src/components/navbar/language-switcher.tsx b/website/src/components/navbar/language-switcher.tsx new file mode 100644 index 000000000..45074cc0e --- /dev/null +++ b/website/src/components/navbar/language-switcher.tsx @@ -0,0 +1,69 @@ +'use client'; + +import { LanguageIcon } from '@heroicons/react/24/solid'; +import { Language } from '@socialincome/shared/src/types'; +import { Dropdown, Menu, Typography } from '@socialincome/ui'; +import { useRouter, useSearchParams } from 'next/navigation'; +import { Suspense } from 'react'; + +type LanguageSwitcherProps = { + mobile?: boolean; + currentLanguage: string; + languages: { + code: Language; + translation: string; + }[]; +}; + +function LanguageSwitcherComponent({ languages, mobile, currentLanguage }: LanguageSwitcherProps) { + const router = useRouter(); + const searchParams = useSearchParams(); + + const onLanguageChange = (lang: Language) => { + const pathSegments = window.location.pathname.split('/'); + pathSegments[1] = lang; + const current = new URLSearchParams(Array.from(searchParams.entries())); + router.push(pathSegments.join('/') + '?' + current.toString()); + }; + if (mobile) { + return ( + + + {currentLanguage} +
+ } + > + {languages.map((lang, index) => ( + + onLanguageChange(lang.code)}>{lang.translation} + + ))} + + ); + } else { + return ( + + + + + + {languages.map((lang, index) => ( + onLanguageChange(lang.code)}> + {lang.translation} + + ))} + + + ); + } +} + +export function LanguageSwitcher(props: LanguageSwitcherProps) { + return ( + + + + ); +} diff --git a/website/src/components/navbar/navbar-client.tsx b/website/src/components/navbar/navbar-client.tsx index 5adbe54ac..67e70b3e7 100644 --- a/website/src/components/navbar/navbar-client.tsx +++ b/website/src/components/navbar/navbar-client.tsx @@ -2,16 +2,16 @@ import { DefaultParams } from '@/app/[lang]/[country]'; import { SILogo } from '@/components/logos/si-logo'; +import { LanguageSwitcher } from '@/components/navbar/language-switcher'; import { Disclosure } from '@headlessui/react'; import { Bars3Icon, UserCircleIcon, XMarkIcon } from '@heroicons/react/24/outline'; -import { LanguageIcon } from '@heroicons/react/24/solid'; import { Language } from '@socialincome/shared/src/types'; import { Button, Dropdown, Menu, Typography } from '@socialincome/ui'; import classNames from 'classnames'; import { signOut } from 'firebase/auth'; import _ from 'lodash'; import Link from 'next/link'; -import { usePathname, useRouter, useSearchParams } from 'next/navigation'; +import { usePathname } from 'next/navigation'; import { useAuth, useUser } from 'reactfire'; type NavbarSection = { @@ -40,10 +40,8 @@ type NavbarProps = { } & DefaultParams; export default function NavbarClient({ lang, country, translations, languages, sections = [] }: NavbarProps) { - const router = useRouter(); const auth = useAuth(); const { status: authUserReady, data: authUser } = useUser(); - const searchParams = useSearchParams(); const pathname = usePathname(); const baseSegment = pathname?.split('/')[3]; let backgroundColor; @@ -56,18 +54,11 @@ export default function NavbarClient({ lang, country, translations, languages, s backgroundColor = 'bg-base-blue'; } - const onLanguageChange = (lang: Language) => { - const pathSegments = window.location.pathname.split('/'); - pathSegments[1] = lang; - const current = new URLSearchParams(Array.from(searchParams.entries())); - router.push(pathSegments.join('/') + '?' + current.toString()); - }; - return ( {({ open }) => ( <> -
+
@@ -120,18 +111,7 @@ export default function NavbarClient({ lang, country, translations, languages, s
- - - - - - {languages.map((lang, index) => ( - onLanguageChange(lang.code)}> - {lang.translation} - - ))} - - + @@ -145,11 +125,8 @@ export default function NavbarClient({ lang, country, translations, languages, s {translations.contactDetails} - signOut(auth).then(() => router.push(`/${lang}/${country}`))} - > - {translations.signOut} + + signOut(auth)}>{translations.signOut} ) : ( @@ -206,20 +183,11 @@ export default function NavbarClient({ lang, country, translations, languages, s
- - - {translations.currentLanguage} -
- } - > - {languages.map((lang, index) => ( - - onLanguageChange(lang.code)}>{lang.translation} - - ))} - + {translations.contactDetails} - {translations.payments} + {translations.payments} - signOut(auth).then(() => router.push(`/${lang}/${country}`))}> - {translations.signOut} - + signOut(auth)}>{translations.signOut} ) : ( diff --git a/website/src/components/navbar/navbar.tsx b/website/src/components/navbar/navbar.tsx index c8e871595..94ca5408e 100644 --- a/website/src/components/navbar/navbar.tsx +++ b/website/src/components/navbar/navbar.tsx @@ -8,8 +8,8 @@ export default async function Navbar({ lang, country }: DefaultParams) { language: lang, namespaces: ['common', 'website-common', 'website-me'], }); - const languages: Language[] = ['en', 'de']; + const languages: Language[] = ['en', 'de']; const aboutUs = translator.t('navigation.about-us'); const aboutUsHref = `/${lang}/${country}/about-us`; const ourWork = translator.t('navigation.our-work'); diff --git a/website/src/firebase/admin.ts b/website/src/firebase-admin.ts similarity index 100% rename from website/src/firebase/admin.ts rename to website/src/firebase-admin.ts diff --git a/website/src/firebase/client.ts b/website/src/firebase/client.ts deleted file mode 100644 index 14bdf2338..000000000 --- a/website/src/firebase/client.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { initializeFirebaseClient } from '@socialincome/shared/src/firebase/client/init'; - -/** - * Initializes public clients. In contrast to the admin clients, this can be used directly from the client - * since the security rules are applied. - */ -export const { app, auth, firestore, functions, storage } = initializeFirebaseClient({ - firebaseConfig: { - apiKey: process.env.NEXT_PUBLIC_FIREBASE_API_KEY, - authDomain: process.env.NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN, - projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID, - }, - authEmulatorUrl: process.env.NEXT_PUBLIC_FIREBASE_AUTH_EMULATOR_URL, - firestoreEmulatorHost: process.env.NEXT_PUBLIC_FIREBASE_FIRESTORE_EMULATOR_HOST, - firestoreEmulatorPort: Number(process.env.NEXT_PUBLIC_FIREBASE_FIRESTORE_EMULATOR_PORT), - storageEmulatorHost: process.env.NEXT_PUBLIC_FIREBASE_STORAGE_EMULATOR_HOST, - storageEmulatorPort: Number(process.env.NEXT_PUBLIC_FIREBASE_STORAGE_EMULATOR_PORT), - functionsEmulatorHost: process.env.NEXT_PUBLIC_FIREBASE_FUNCTIONS_EMULATOR_HOST, - functionsEmulatorPort: Number(process.env.NEXT_PUBLIC_FIREBASE_FUNCTIONS_EMULATOR_PORT), -}); - -export let asdf: string | undefined = undefined; - -export function initAsdf() { - console.log('initAsdf called'); - new Promise(async () => { - setTimeout(() => { - console.log('setting asdf'); - asdf = 'asdf'; - }, 3000); - }); -}