mirror of
https://github.com/ente-io/ente.git
synced 2025-08-07 23:18:10 +00:00
[web] Make the imported payments code feel at home in the new monorepo
- Use the shared yarn monorepo configuration - styled-components => emotion (since that's what the rest of the code uses) - Remove Sentry (since it's gone elsewhere)
This commit is contained in:
parent
ad3503053d
commit
8f0ef055c5
1
web/.gitignore
vendored
1
web/.gitignore
vendored
@ -9,6 +9,7 @@ node_modules/
|
|||||||
|
|
||||||
# Local env files
|
# Local env files
|
||||||
.env
|
.env
|
||||||
|
.env.local
|
||||||
.env.*.local
|
.env.*.local
|
||||||
|
|
||||||
# Next.js
|
# Next.js
|
||||||
|
@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"presets": ["next/babel"],
|
|
||||||
"plugins": [
|
|
||||||
[
|
|
||||||
"styled-components",
|
|
||||||
{
|
|
||||||
"ssr": true,
|
|
||||||
"displayName": true,
|
|
||||||
"preprocess": false
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": ["next", "next/core-web-vitals"]
|
|
||||||
}
|
|
8
web/apps/payments/.eslintrc.js
Normal file
8
web/apps/payments/.eslintrc.js
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: ["@/build-config/eslintrc-typescript-react"],
|
||||||
|
parserOptions: {
|
||||||
|
tsconfigRootDir: __dirname,
|
||||||
|
},
|
||||||
|
// TODO (MR): Figure out a way to not have to ignored the next config .js
|
||||||
|
ignorePatterns: [".eslintrc.js", "next.config.js"],
|
||||||
|
};
|
@ -1,3 +0,0 @@
|
|||||||
## Description
|
|
||||||
|
|
||||||
## Test Plan
|
|
34
web/apps/payments/.gitignore
vendored
34
web/apps/payments/.gitignore
vendored
@ -1,34 +0,0 @@
|
|||||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
||||||
|
|
||||||
# dependencies
|
|
||||||
/node_modules
|
|
||||||
/.pnp
|
|
||||||
.pnp.js
|
|
||||||
|
|
||||||
# testing
|
|
||||||
/coverage
|
|
||||||
|
|
||||||
# next.js
|
|
||||||
/.next/
|
|
||||||
/out/
|
|
||||||
|
|
||||||
# production
|
|
||||||
/build
|
|
||||||
|
|
||||||
# misc
|
|
||||||
.DS_Store
|
|
||||||
*.pem
|
|
||||||
|
|
||||||
# debug
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
|
|
||||||
# local env files
|
|
||||||
.env.local
|
|
||||||
.env.development.local
|
|
||||||
.env.test.local
|
|
||||||
.env.production.local
|
|
||||||
|
|
||||||
# vercel
|
|
||||||
.vercel
|
|
@ -1,6 +0,0 @@
|
|||||||
{
|
|
||||||
"tabWidth": 4,
|
|
||||||
"trailingComma": "es5",
|
|
||||||
"singleQuote": true,
|
|
||||||
"jsxBracketSameLine": true
|
|
||||||
}
|
|
@ -1,17 +1,7 @@
|
|||||||
This is a [Next.js](https://nextjs.org/) project bootstrapped with
|
Code that runs on `payments.ente.io`, handling and web facing interaction with
|
||||||
[`create-next-app`](https://github.com/vercel/next.js/tree/canary/packages/create-next-app).
|
Stripe's API for payments.
|
||||||
|
|
||||||
## Getting Started
|
## Development
|
||||||
|
|
||||||
First, run the development server:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm run dev
|
|
||||||
# or
|
|
||||||
yarn dev
|
|
||||||
```
|
|
||||||
|
|
||||||
## Notes
|
|
||||||
|
|
||||||
If you're running this to test out the payment flows end-to-end, please do a
|
If you're running this to test out the payment flows end-to-end, please do a
|
||||||
`yarn build`, that will place the output within the `out` folder.
|
`yarn build`, that will place the output within the `out` folder.
|
||||||
@ -23,12 +13,12 @@ Aside that, these are the necessary configuration changes.
|
|||||||
|
|
||||||
### Local configuration
|
### Local configuration
|
||||||
|
|
||||||
Update the `.env.local` to point to the local museum instance, and to define the
|
Create an `.env` in this directory to point to the local museum instance, and to
|
||||||
necessary Stripe keys that can be fetched from [Stripe's developer
|
define the necessary Stripe keys that can be fetched from [Stripe's developer
|
||||||
dashboard](https://dashboard.stripe.com).
|
dashboard](https://dashboard.stripe.com).
|
||||||
|
|
||||||
Assuming that your local museum instance is running on `192.168.1.2:8080`, your
|
Assuming that your local museum instance is running on `192.168.1.2:8080`, your
|
||||||
`.env.local` should look as follows.
|
`.env` should look as follows.
|
||||||
|
|
||||||
```
|
```
|
||||||
NEXT_PUBLIC_ENTE_ENDPOINT = http://192.168.1.2:8080
|
NEXT_PUBLIC_ENTE_ENDPOINT = http://192.168.1.2:8080
|
||||||
@ -44,15 +34,15 @@ NEXT_PUBLIC_STRIPE_US_PUBLISHABLE_KEY = stripe_publishable_key
|
|||||||
|
|
||||||
3. Update the `whitelisted-redirect-urls` so that it supports redirecting to this locally running project
|
3. Update the `whitelisted-redirect-urls` so that it supports redirecting to this locally running project
|
||||||
|
|
||||||
Assuming that your local payments app is running on `192.168.1.2:3001`, your
|
Assuming that your local payments app is running on `192.168.1.2:3004`, your
|
||||||
`museum.yaml` should look as follows.
|
`museum.yaml` should look as follows.
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
stripe:
|
stripe:
|
||||||
us:
|
us:
|
||||||
key: stripe_dev_key
|
key: stripe_dev_key
|
||||||
webhook-secret: stripe_dev_webhook_secret
|
webhook-secret: stripe_dev_webhook_secret
|
||||||
whitelisted-redirect-urls: ["http://192.168.1.2:3001/frameRedirect"]
|
whitelisted-redirect-urls: ["http://192.168.1.2:3004/frameRedirect"]
|
||||||
path:
|
path:
|
||||||
success: ?status=success&session_id={CHECKOUT_SESSION_ID}
|
success: ?status=success&session_id={CHECKOUT_SESSION_ID}
|
||||||
cancel: ?status=fail&reason=canceled
|
cancel: ?status=fail&reason=canceled
|
||||||
|
@ -1,44 +0,0 @@
|
|||||||
ente believes that working with security researchers across the globe is crucial to keeping our
|
|
||||||
users safe. If you believe you've found a security issue in our product or service, we encourage you to
|
|
||||||
notify us (security@ente.io). We welcome working with you to resolve the issue promptly. Thanks in advance!
|
|
||||||
|
|
||||||
# Disclosure Policy
|
|
||||||
|
|
||||||
- Let us know as soon as possible upon discovery of a potential security issue, and we'll make every
|
|
||||||
effort to quickly resolve the issue.
|
|
||||||
- Provide us a reasonable amount of time to resolve the issue before any disclosure to the public or a
|
|
||||||
third-party. We may publicly disclose the issue before resolving it, if appropriate.
|
|
||||||
- Make a good faith effort to avoid privacy violations, destruction of data, and interruption or
|
|
||||||
degradation of our service. Only interact with accounts you own or with explicit permission of the
|
|
||||||
account holder.
|
|
||||||
- If you would like to encrypt your report, please use the PGP key with long ID
|
|
||||||
`E273695C0403F34F74171932DF6DDDE98EBD2394` (available in the public keyserver pool).
|
|
||||||
|
|
||||||
# In-scope
|
|
||||||
|
|
||||||
- Security issues in any current release of ente. This includes the web app, desktop app,
|
|
||||||
and mobile apps (iOS and Android). Product downloads are available at https://ente.io. Source
|
|
||||||
code is available at https://github.com/ente-io.
|
|
||||||
|
|
||||||
# Exclusions
|
|
||||||
|
|
||||||
The following bug classes are out-of scope:
|
|
||||||
|
|
||||||
- Bugs that are already reported on any of ente's issue trackers (https://github.com/ente-io),
|
|
||||||
or that we already know of. Note that some of our issue tracking is private.
|
|
||||||
- Issues in an upstream software dependency (ex: Flutter, Next.js etc) which are already reported to the upstream maintainer.
|
|
||||||
- Attacks requiring physical access to a user's device.
|
|
||||||
- Self-XSS
|
|
||||||
- Issues related to software or protocols not under ente's control
|
|
||||||
- Vulnerabilities in outdated versions of ente
|
|
||||||
- Missing security best practices that do not directly lead to a vulnerability
|
|
||||||
- Issues that do not have any impact on the general public
|
|
||||||
|
|
||||||
While researching, we'd like to ask you to refrain from:
|
|
||||||
|
|
||||||
- Denial of service
|
|
||||||
- Spamming
|
|
||||||
- Social engineering (including phishing) of ente staff or contractors
|
|
||||||
- Any physical attempts against ente property or data centers
|
|
||||||
|
|
||||||
Thank you for helping keep ente and our users safe!
|
|
@ -1,44 +1,18 @@
|
|||||||
// This file sets a custom webpack configuration to use your Next.js app
|
// @ts-check
|
||||||
// with Sentry.
|
|
||||||
// https://nextjs.org/docs/api-reference/next.config.js/introduction
|
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
|
||||||
|
|
||||||
const { withSentryConfig } = require('@sentry/nextjs');
|
/**
|
||||||
|
* Configuration for the Next.js build
|
||||||
const cp = require('child_process');
|
*
|
||||||
const gitSha = cp.execSync('git rev-parse --short HEAD', {
|
* See also:
|
||||||
cwd: __dirname,
|
* - packages/next/next.config.base.js
|
||||||
encoding: 'utf8',
|
* - https://nextjs.org/docs/pages/api-reference/next-config-js
|
||||||
});
|
*
|
||||||
|
* @type {import("next").NextConfig}
|
||||||
const moduleExports = {
|
*/
|
||||||
// Your existing module.exports
|
const nextConfig = {
|
||||||
output: 'export',
|
/* generate a static export when we run `next build` */
|
||||||
|
output: "export",
|
||||||
reactStrictMode: true,
|
reactStrictMode: true,
|
||||||
env: {
|
|
||||||
SENTRY_RELEASE: gitSha,
|
|
||||||
},
|
|
||||||
sentry: {
|
|
||||||
hideSourceMaps: false,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const SentryWebpackPluginOptions = {
|
module.exports = nextConfig;
|
||||||
// Additional config options for the Sentry Webpack plugin. Keep in mind that
|
|
||||||
// the following options are set automatically, and overriding them is not
|
|
||||||
// recommended:
|
|
||||||
// release, url, org, project, authToken, configFile, stripPrefix,
|
|
||||||
// urlPrefix, include, ignore
|
|
||||||
release: gitSha,
|
|
||||||
silent: true, // Suppresses all logs
|
|
||||||
// Ignore sentry webpack errors
|
|
||||||
errorHandler: (err, invokeErr, compilation) => {
|
|
||||||
compilation.warnings.push('Sentry CLI Plugin: ' + err.message);
|
|
||||||
},
|
|
||||||
// For all available options, see:
|
|
||||||
// https://github.com/getsentry/sentry-webpack-plugin#options.
|
|
||||||
};
|
|
||||||
|
|
||||||
// Make sure adding Sentry options is the last code to run before exporting, to
|
|
||||||
// ensure that your source maps include changes from all other Webpack plugins
|
|
||||||
module.exports = withSentryConfig(moduleExports, SentryWebpackPluginOptions);
|
|
||||||
|
@ -1,31 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "payments",
|
"name": "payments",
|
||||||
"version": "0.1.0",
|
"version": "0.0.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"dependencies": {
|
||||||
"dev": "next dev -p 3001",
|
"@/next": "*",
|
||||||
"build": "next build",
|
"@stripe/stripe-js": "^1.17.0",
|
||||||
"start": "next start",
|
"axios": "^0.21.1",
|
||||||
"lint": "next lint"
|
"bootstrap": "4.6.0"
|
||||||
},
|
}
|
||||||
"dependencies": {
|
|
||||||
"@sentry/nextjs": "^7.54.0",
|
|
||||||
"@stripe/stripe-js": "^1.17.0",
|
|
||||||
"axios": "^0.21.1",
|
|
||||||
"bootstrap": "4.6.0",
|
|
||||||
"next": "^14.1.4",
|
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-bootstrap": "^1.6.1",
|
|
||||||
"react-dom": "^18.2.0",
|
|
||||||
"styled-components": "^5.3.0"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@types/node": "20.11.30",
|
|
||||||
"@types/react": "17.0.15",
|
|
||||||
"@types/styled-components": "^5.1.12",
|
|
||||||
"babel-plugin-styled-components": "^1.13.2",
|
|
||||||
"eslint": "^8.57.0",
|
|
||||||
"eslint-config-next": "^14.1.4",
|
|
||||||
"typescript": "^5.4.2"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
// This file configures the initialization of Sentry on the browser.
|
|
||||||
// The config you add here will be used whenever a page is visited.
|
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
|
||||||
|
|
||||||
import * as Sentry from '@sentry/nextjs';
|
|
||||||
|
|
||||||
const SENTRY_DSN =
|
|
||||||
(process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN) ??
|
|
||||||
'https://67447bc36684b1f7a18d79683b788f25@sentry.ente.io/6';
|
|
||||||
|
|
||||||
const TUNNEL_URL = 'https://sentry-reporter.ente.io';
|
|
||||||
const SENTRY_ENV = process.env.NEXT_PUBLIC_SENTRY_ENV ?? 'development';
|
|
||||||
|
|
||||||
Sentry.init({
|
|
||||||
dsn: SENTRY_DSN,
|
|
||||||
enabled: false,
|
|
||||||
environment: SENTRY_ENV,
|
|
||||||
// Adjust this value in production, or use tracesSampler for greater control
|
|
||||||
tracesSampleRate: 1.0,
|
|
||||||
attachStacktrace: true,
|
|
||||||
autoSessionTracking: false,
|
|
||||||
tunnel: TUNNEL_URL,
|
|
||||||
// ...
|
|
||||||
// Note: if you want to override the automatic release value, do not set a
|
|
||||||
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
|
||||||
// that it will also get attached to your source maps
|
|
||||||
});
|
|
@ -1,4 +0,0 @@
|
|||||||
defaults.url=https://sentry.ente.io/
|
|
||||||
defaults.org=ente
|
|
||||||
defaults.project=web-payments
|
|
||||||
|
|
@ -1,26 +0,0 @@
|
|||||||
// This file configures the initialization of Sentry on the server.
|
|
||||||
// The config you add here will be used whenever the server handles a request.
|
|
||||||
// https://docs.sentry.io/platforms/javascript/guides/nextjs/
|
|
||||||
|
|
||||||
import * as Sentry from '@sentry/nextjs';
|
|
||||||
|
|
||||||
const SENTRY_DSN =
|
|
||||||
(process.env.SENTRY_DSN || process.env.NEXT_PUBLIC_SENTRY_DSN) ??
|
|
||||||
'https://208e398c28cd4c069c83d7c6e63adef6@sentry.ente.io/6';
|
|
||||||
|
|
||||||
const SENTRY_ENV = process.env.NEXT_PUBLIC_SENTRY_ENV ?? 'development';
|
|
||||||
|
|
||||||
Sentry.init({
|
|
||||||
dsn: SENTRY_DSN,
|
|
||||||
enabled: SENTRY_ENV !== 'development',
|
|
||||||
environment: SENTRY_ENV,
|
|
||||||
// Adjust this value in production, or use tracesSampler for greater control
|
|
||||||
tracesSampleRate: 1.0,
|
|
||||||
release: process.env.SENTRY_RELEASE,
|
|
||||||
autoSessionTracking: false,
|
|
||||||
|
|
||||||
// ...
|
|
||||||
// Note: if you want to override the automatic release value, do not set a
|
|
||||||
// `release` value here - use the environment variable `SENTRY_RELEASE`, so
|
|
||||||
// that it will also get attached to your source maps
|
|
||||||
});
|
|
@ -1,4 +1,4 @@
|
|||||||
import styled from 'styled-components';
|
import styled from "@mui/styled-engine";
|
||||||
|
|
||||||
export const Container = styled.div`
|
export const Container = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import { Spinner } from "react-bootstrap";
|
||||||
import { Spinner } from 'react-bootstrap';
|
|
||||||
|
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||||
export default function EnteSpinner(props: any) {
|
export default function EnteSpinner(props: any) {
|
||||||
return (
|
return (
|
||||||
<Spinner {...props} animation="border" variant="success" role="status">
|
<Spinner {...props} animation="border" variant="success" role="status">
|
||||||
|
@ -1,2 +1,2 @@
|
|||||||
export const DESKTOP_REDIRECT_URL = 'ente://app/gallery';
|
export const DESKTOP_REDIRECT_URL = "ente://app/gallery";
|
||||||
export const ENTE_WEBSITE_URL = 'https://ente.io';
|
export const ENTE_WEBSITE_URL = "https://ente.io";
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { Container } from 'components/Container';
|
import { Container } from "components/Container";
|
||||||
import React from 'react';
|
import constants from "utils/strings/constants";
|
||||||
import constants from 'utils/strings/constants';
|
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
return <Container>{constants.NOT_FOUND}</Container>;
|
return <Container>{constants.NOT_FOUND}</Container>;
|
||||||
|
@ -1,9 +1,8 @@
|
|||||||
import '../styles/globals.css';
|
import "bootstrap/dist/css/bootstrap.min.css";
|
||||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
import type { AppProps } from "next/app";
|
||||||
import type { AppProps } from 'next/app';
|
import Head from "next/head";
|
||||||
import React from 'react';
|
import constants from "utils/strings/constants";
|
||||||
import constants from 'utils/strings/constants';
|
import "../styles/globals.css";
|
||||||
import Head from 'next/head';
|
|
||||||
|
|
||||||
function MyApp({ Component, pageProps }: AppProps) {
|
function MyApp({ Component, pageProps }: AppProps) {
|
||||||
return (
|
return (
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import { Container } from 'components/Container';
|
import { Container } from "components/Container";
|
||||||
import EnteSpinner from 'components/EnteSpinner';
|
import EnteSpinner from "components/EnteSpinner";
|
||||||
import { DESKTOP_REDIRECT_URL } from 'constants/common';
|
import { DESKTOP_REDIRECT_URL } from "constants/common";
|
||||||
import { useRouter } from 'next/dist/client/router';
|
import * as React from "react";
|
||||||
import React, { useEffect, useState } from 'react';
|
|
||||||
|
|
||||||
export default function DesktopRedirect() {
|
export default function DesktopRedirect() {
|
||||||
useEffect(() => {
|
React.useEffect(() => {
|
||||||
const currentURL = new URL(window.location.href);
|
const currentURL = new URL(window.location.href);
|
||||||
const desktopRedirectURL = new URL(DESKTOP_REDIRECT_URL);
|
const desktopRedirectURL = new URL(DESKTOP_REDIRECT_URL);
|
||||||
desktopRedirectURL.search = currentURL.search;
|
desktopRedirectURL.search = currentURL.search;
|
||||||
|
@ -1,21 +1,22 @@
|
|||||||
import { Container } from 'components/Container';
|
import { Container } from "components/Container";
|
||||||
import EnteSpinner from 'components/EnteSpinner';
|
import EnteSpinner from "components/EnteSpinner";
|
||||||
import { ENTE_WEBSITE_URL } from 'constants/common';
|
import { ENTE_WEBSITE_URL } from "constants/common";
|
||||||
import React, { useEffect, useState } from 'react';
|
import * as React from "react";
|
||||||
import { parseAndHandleRequest } from 'services/billingService';
|
import { parseAndHandleRequest } from "services/billingService";
|
||||||
import { CUSTOM_ERROR } from 'utils/error';
|
import { CUSTOM_ERROR } from "utils/error";
|
||||||
import constants from 'utils/strings/constants';
|
import constants from "utils/strings/constants";
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const [errorMessageView, setErrorMessageView] = useState(false);
|
const [errorMessageView, setErrorMessageView] = React.useState(false);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = React.useState(false);
|
||||||
useEffect(() => {
|
React.useEffect(() => {
|
||||||
async function main() {
|
async function main() {
|
||||||
try {
|
try {
|
||||||
setLoading(true);
|
setLoading(true);
|
||||||
await parseAndHandleRequest();
|
await parseAndHandleRequest();
|
||||||
} catch (e: any) {
|
} catch (e: unknown) {
|
||||||
if (
|
if (
|
||||||
|
e instanceof Error &&
|
||||||
e.message === CUSTOM_ERROR.DIRECT_OPEN_WITH_NO_QUERY_PARAMS
|
e.message === CUSTOM_ERROR.DIRECT_OPEN_WITH_NO_QUERY_PARAMS
|
||||||
) {
|
) {
|
||||||
window.location.href = ENTE_WEBSITE_URL;
|
window.location.href = ENTE_WEBSITE_URL;
|
||||||
@ -24,6 +25,8 @@ export default function Home() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO: audit
|
||||||
|
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||||
main();
|
main();
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
@ -1,4 +1,12 @@
|
|||||||
import axios, { AxiosRequestConfig } from 'axios';
|
// TODO: Audit
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
||||||
|
/* eslint-disable @typescript-eslint/prefer-promise-reject-errors */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
|
/* eslint-disable @typescript-eslint/consistent-indexed-object-style */
|
||||||
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
|
|
||||||
|
import axios, { AxiosRequestConfig } from "axios";
|
||||||
|
|
||||||
interface IHTTPHeaders {
|
interface IHTTPHeaders {
|
||||||
[headerKey: string]: any;
|
[headerKey: string]: any;
|
||||||
@ -29,7 +37,7 @@ class HTTPService {
|
|||||||
* header object to be append to all api calls.
|
* header object to be append to all api calls.
|
||||||
*/
|
*/
|
||||||
private headers: IHTTPHeaders = {
|
private headers: IHTTPHeaders = {
|
||||||
'content-type': 'application/json',
|
"content-type": "application/json",
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -77,7 +85,9 @@ class HTTPService {
|
|||||||
...config.headers,
|
...config.headers,
|
||||||
};
|
};
|
||||||
if (customConfig?.cancel) {
|
if (customConfig?.cancel) {
|
||||||
config.cancelToken=new axios.CancelToken((c)=> (customConfig.cancel.exec=c));
|
config.cancelToken = new axios.CancelToken(
|
||||||
|
(c) => (customConfig.cancel.exec = c),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return await axios({ ...config, ...customConfig });
|
return await axios({ ...config, ...customConfig });
|
||||||
}
|
}
|
||||||
@ -94,7 +104,7 @@ class HTTPService {
|
|||||||
return this.request(
|
return this.request(
|
||||||
{
|
{
|
||||||
headers,
|
headers,
|
||||||
method: 'GET',
|
method: "GET",
|
||||||
params,
|
params,
|
||||||
url,
|
url,
|
||||||
},
|
},
|
||||||
@ -116,7 +126,7 @@ class HTTPService {
|
|||||||
{
|
{
|
||||||
data,
|
data,
|
||||||
headers,
|
headers,
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
params,
|
params,
|
||||||
url,
|
url,
|
||||||
},
|
},
|
||||||
@ -138,7 +148,7 @@ class HTTPService {
|
|||||||
{
|
{
|
||||||
data,
|
data,
|
||||||
headers,
|
headers,
|
||||||
method: 'PUT',
|
method: "PUT",
|
||||||
params,
|
params,
|
||||||
url,
|
url,
|
||||||
},
|
},
|
||||||
@ -160,7 +170,7 @@ class HTTPService {
|
|||||||
{
|
{
|
||||||
data,
|
data,
|
||||||
headers,
|
headers,
|
||||||
method: 'DELETE',
|
method: "DELETE",
|
||||||
params,
|
params,
|
||||||
url,
|
url,
|
||||||
},
|
},
|
||||||
|
@ -1,68 +1,76 @@
|
|||||||
import { loadStripe, Stripe } from '@stripe/stripe-js';
|
// TODO: Audit this and other eslints
|
||||||
import { CUSTOM_ERROR } from 'utils/error';
|
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||||
import { logError } from 'utils/sentry';
|
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
|
||||||
import HTTPService from './HTTPService';
|
/* eslint-disable @typescript-eslint/no-confusing-void-expression */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-return */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unsafe-enum-comparison */
|
||||||
|
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
|
||||||
|
|
||||||
|
import { loadStripe } from "@stripe/stripe-js";
|
||||||
|
import { CUSTOM_ERROR } from "utils/error";
|
||||||
|
import { logError } from "utils/sentry";
|
||||||
|
import HTTPService from "./HTTPService";
|
||||||
|
|
||||||
const getStripePublishableKey = (stripeAccount: StripeAccountCountry) => {
|
const getStripePublishableKey = (stripeAccount: StripeAccountCountry) => {
|
||||||
if (stripeAccount === StripeAccountCountry.STRIPE_IN) {
|
if (stripeAccount === StripeAccountCountry.STRIPE_IN) {
|
||||||
return (
|
return (
|
||||||
process.env.NEXT_PUBLIC_STRIPE_IN_PUBLISHABLE_KEY ??
|
process.env.NEXT_PUBLIC_STRIPE_IN_PUBLISHABLE_KEY ??
|
||||||
'pk_live_51HAhqDK59oeucIMOiTI6MDDM2UWUbCAJXJCGsvjJhiO8nYJz38rQq5T4iyQLDMKxqEDUfU5Hopuj4U5U4dff23oT00fHvZeodC'
|
"pk_live_51HAhqDK59oeucIMOiTI6MDDM2UWUbCAJXJCGsvjJhiO8nYJz38rQq5T4iyQLDMKxqEDUfU5Hopuj4U5U4dff23oT00fHvZeodC"
|
||||||
);
|
);
|
||||||
} else if (stripeAccount === StripeAccountCountry.STRIPE_US) {
|
} else if (stripeAccount === StripeAccountCountry.STRIPE_US) {
|
||||||
return (
|
return (
|
||||||
process.env.NEXT_PUBLIC_STRIPE_US_PUBLISHABLE_KEY ??
|
process.env.NEXT_PUBLIC_STRIPE_US_PUBLISHABLE_KEY ??
|
||||||
'pk_live_51LZ9P4G1ITnQlpAnrP6pcS7NiuJo3SnJ7gibjJlMRatkrd2EY1zlMVTVQG5RkSpLPbsHQzFfnEtgHnk1PiylIFkk00tC0LWXwi'
|
"pk_live_51LZ9P4G1ITnQlpAnrP6pcS7NiuJo3SnJ7gibjJlMRatkrd2EY1zlMVTVQG5RkSpLPbsHQzFfnEtgHnk1PiylIFkk00tC0LWXwi"
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
throw Error('stripe account not found');
|
throw Error("stripe account not found");
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const getEndpoint = () => {
|
const getEndpoint = () => {
|
||||||
const endPoint =
|
const endPoint =
|
||||||
process.env.NEXT_PUBLIC_ENTE_ENDPOINT ?? 'https://api.ente.io';
|
process.env.NEXT_PUBLIC_ENTE_ENDPOINT ?? "https://api.ente.io";
|
||||||
return endPoint;
|
return endPoint;
|
||||||
};
|
};
|
||||||
enum PAYMENT_INTENT_STATUS {
|
enum PAYMENT_INTENT_STATUS {
|
||||||
SUCCESS = 'success',
|
SUCCESS = "success",
|
||||||
REQUIRE_ACTION = 'requires_action',
|
REQUIRE_ACTION = "requires_action",
|
||||||
REQUIRE_PAYMENT_METHOD = 'requires_payment_method',
|
REQUIRE_PAYMENT_METHOD = "requires_payment_method",
|
||||||
}
|
}
|
||||||
|
|
||||||
enum FAILURE_REASON {
|
enum FAILURE_REASON {
|
||||||
// Unable to authenticate card or 3DS
|
// Unable to authenticate card or 3DS
|
||||||
// User should be showing button for fixing card via customer portal
|
// User should be showing button for fixing card via customer portal
|
||||||
AUTHENTICATION_FAILED = 'authentication_failed',
|
AUTHENTICATION_FAILED = "authentication_failed",
|
||||||
// Card declined result in this error. Show button to the customer portal.
|
// Card declined result in this error. Show button to the customer portal.
|
||||||
REQUIRE_PAYMENT_METHOD = 'requires_payment_method',
|
REQUIRE_PAYMENT_METHOD = "requires_payment_method",
|
||||||
STRIPE_ERROR = 'stripe_error',
|
STRIPE_ERROR = "stripe_error",
|
||||||
CANCELED = 'canceled',
|
CANCELED = "canceled",
|
||||||
SERVER_ERROR = 'server_error',
|
SERVER_ERROR = "server_error",
|
||||||
}
|
}
|
||||||
|
|
||||||
enum STRIPE_ERROR_TYPE {
|
enum STRIPE_ERROR_TYPE {
|
||||||
CARD_ERROR = 'card_error',
|
CARD_ERROR = "card_error",
|
||||||
AUTHENTICATION_ERROR = 'authentication_error',
|
AUTHENTICATION_ERROR = "authentication_error",
|
||||||
}
|
}
|
||||||
|
|
||||||
enum STRIPE_ERROR_CODE {
|
enum STRIPE_ERROR_CODE {
|
||||||
AUTHENTICATION_ERROR = 'payment_intent_authentication_failure',
|
AUTHENTICATION_ERROR = "payment_intent_authentication_failure",
|
||||||
}
|
}
|
||||||
|
|
||||||
enum RESPONSE_STATUS {
|
enum RESPONSE_STATUS {
|
||||||
success = 'success',
|
success = "success",
|
||||||
fail = 'fail',
|
fail = "fail",
|
||||||
}
|
}
|
||||||
|
|
||||||
enum PaymentActionType {
|
enum PaymentActionType {
|
||||||
Buy = 'buy',
|
Buy = "buy",
|
||||||
Update = 'update',
|
Update = "update",
|
||||||
}
|
}
|
||||||
|
|
||||||
enum StripeAccountCountry {
|
enum StripeAccountCountry {
|
||||||
STRIPE_IN = 'IN',
|
STRIPE_IN = "IN",
|
||||||
STRIPE_US = 'US',
|
STRIPE_US = "US",
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SubscriptionUpdateResponse {
|
interface SubscriptionUpdateResponse {
|
||||||
@ -75,10 +83,10 @@ interface SubscriptionUpdateResponse {
|
|||||||
export async function parseAndHandleRequest() {
|
export async function parseAndHandleRequest() {
|
||||||
try {
|
try {
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
const productID = urlParams.get('productID');
|
const productID = urlParams.get("productID");
|
||||||
const paymentToken = urlParams.get('paymentToken');
|
const paymentToken = urlParams.get("paymentToken");
|
||||||
const action = urlParams.get('action');
|
const action = urlParams.get("action");
|
||||||
const redirectURL = urlParams.get('redirectURL');
|
const redirectURL = urlParams.get("redirectURL");
|
||||||
if (!action && !paymentToken && !productID && !redirectURL) {
|
if (!action && !paymentToken && !productID && !redirectURL) {
|
||||||
throw Error(CUSTOM_ERROR.DIRECT_OPEN_WITH_NO_QUERY_PARAMS);
|
throw Error(CUSTOM_ERROR.DIRECT_OPEN_WITH_NO_QUERY_PARAMS);
|
||||||
} else if (!action || !paymentToken || !productID || !redirectURL) {
|
} else if (!action || !paymentToken || !productID || !redirectURL) {
|
||||||
@ -95,7 +103,7 @@ export async function parseAndHandleRequest() {
|
|||||||
throw Error(CUSTOM_ERROR.INVALID_ACTION);
|
throw Error(CUSTOM_ERROR.INVALID_ACTION);
|
||||||
}
|
}
|
||||||
} catch (e: any) {
|
} catch (e: any) {
|
||||||
console.error("Error: ", JSON.stringify(e)) ;
|
console.error("Error: ", JSON.stringify(e));
|
||||||
if (e.message !== CUSTOM_ERROR.DIRECT_OPEN_WITH_NO_QUERY_PARAMS) {
|
if (e.message !== CUSTOM_ERROR.DIRECT_OPEN_WITH_NO_QUERY_PARAMS) {
|
||||||
logError(e);
|
logError(e);
|
||||||
}
|
}
|
||||||
@ -110,7 +118,7 @@ async function getUserStripeAccountCountry(
|
|||||||
`${getEndpoint()}/billing/stripe-account-country`,
|
`${getEndpoint()}/billing/stripe-account-country`,
|
||||||
undefined,
|
undefined,
|
||||||
{
|
{
|
||||||
'X-Auth-Token': paymentToken,
|
"X-Auth-Token": paymentToken,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response.data;
|
return response.data;
|
||||||
@ -125,11 +133,11 @@ async function getStripe(
|
|||||||
const stripe = await loadStripe(publishableKey);
|
const stripe = await loadStripe(publishableKey);
|
||||||
|
|
||||||
if (!stripe) {
|
if (!stripe) {
|
||||||
throw Error('stripe load failed');
|
throw Error("stripe load failed");
|
||||||
}
|
}
|
||||||
return stripe;
|
return stripe;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError(e, 'stripe load failed');
|
logError(e, "stripe load failed");
|
||||||
redirectToApp(
|
redirectToApp(
|
||||||
redirectURL,
|
redirectURL,
|
||||||
RESPONSE_STATUS.fail,
|
RESPONSE_STATUS.fail,
|
||||||
@ -145,9 +153,8 @@ export async function buyPaidSubscription(
|
|||||||
redirectURL: string,
|
redirectURL: string,
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const { stripeAccountCountry } = await getUserStripeAccountCountry(
|
const { stripeAccountCountry } =
|
||||||
paymentToken,
|
await getUserStripeAccountCountry(paymentToken);
|
||||||
);
|
|
||||||
const stripe = await getStripe(redirectURL, stripeAccountCountry);
|
const stripe = await getStripe(redirectURL, stripeAccountCountry);
|
||||||
const { sessionID } = await createCheckoutSession(
|
const { sessionID } = await createCheckoutSession(
|
||||||
productID,
|
productID,
|
||||||
@ -158,7 +165,7 @@ export async function buyPaidSubscription(
|
|||||||
sessionId: sessionID,
|
sessionId: sessionID,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError(e, 'subscription purchase failed');
|
logError(e, "subscription purchase failed");
|
||||||
redirectToApp(
|
redirectToApp(
|
||||||
redirectURL,
|
redirectURL,
|
||||||
RESPONSE_STATUS.fail,
|
RESPONSE_STATUS.fail,
|
||||||
@ -180,7 +187,7 @@ async function createCheckoutSession(
|
|||||||
redirectURL,
|
redirectURL,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'X-Auth-Token': paymentToken,
|
"X-Auth-Token": paymentToken,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response.data;
|
return response.data;
|
||||||
@ -192,9 +199,8 @@ export async function updateSubscription(
|
|||||||
redirectURL: string,
|
redirectURL: string,
|
||||||
) {
|
) {
|
||||||
try {
|
try {
|
||||||
const { stripeAccountCountry } = await getUserStripeAccountCountry(
|
const { stripeAccountCountry } =
|
||||||
paymentToken,
|
await getUserStripeAccountCountry(paymentToken);
|
||||||
);
|
|
||||||
const stripe = await getStripe(redirectURL, stripeAccountCountry);
|
const stripe = await getStripe(redirectURL, stripeAccountCountry);
|
||||||
const { result } = await subscriptionUpdateRequest(
|
const { result } = await subscriptionUpdateRequest(
|
||||||
paymentToken,
|
paymentToken,
|
||||||
@ -245,7 +251,7 @@ export async function updateSubscription(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logError(e, 'subscription update failed');
|
logError(e, "subscription update failed");
|
||||||
redirectToApp(
|
redirectToApp(
|
||||||
redirectURL,
|
redirectURL,
|
||||||
RESPONSE_STATUS.fail,
|
RESPONSE_STATUS.fail,
|
||||||
@ -266,7 +272,7 @@ async function subscriptionUpdateRequest(
|
|||||||
},
|
},
|
||||||
undefined,
|
undefined,
|
||||||
{
|
{
|
||||||
'X-Auth-Token': paymentToken,
|
"X-Auth-Token": paymentToken,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
return response.data;
|
return response.data;
|
||||||
|
@ -1,21 +1,25 @@
|
|||||||
/* ubuntu-regular - latin */
|
/* ubuntu-regular - latin */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Ubuntu';
|
font-family: "Ubuntu";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
src: local(''), url('/fonts/ubuntu-v15-latin-regular.woff2') format('woff2'),
|
src:
|
||||||
|
local(""),
|
||||||
|
url("/fonts/ubuntu-v15-latin-regular.woff2") format("woff2"),
|
||||||
/* Chrome 26+, Opera 23+, Firefox 39+ */
|
/* Chrome 26+, Opera 23+, Firefox 39+ */
|
||||||
url('/fonts/ubuntu-v15-latin-regular.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
url("/fonts/ubuntu-v15-latin-regular.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ubuntu-700 - latin */
|
/* ubuntu-700 - latin */
|
||||||
@font-face {
|
@font-face {
|
||||||
font-family: 'Ubuntu';
|
font-family: "Ubuntu";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
src: local(''), url('/fonts/ubuntu-v15-latin-700.woff2') format('woff2'),
|
src:
|
||||||
|
local(""),
|
||||||
|
url("/fonts/ubuntu-v15-latin-700.woff2") format("woff2"),
|
||||||
/* Chrome 26+, Opera 23+, Firefox 39+ */
|
/* Chrome 26+, Opera 23+, Firefox 39+ */
|
||||||
url('/fonts/ubuntu-v15-latin-700.woff') format('woff'); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
url("/fonts/ubuntu-v15-latin-700.woff") format("woff"); /* Chrome 6+, Firefox 3.6+, IE 9+, Safari 5.1+ */
|
||||||
}
|
}
|
||||||
html,
|
html,
|
||||||
body {
|
body {
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
export function runningInBrowser() {
|
export function runningInBrowser() {
|
||||||
return typeof window !== 'undefined';
|
return typeof window !== "undefined";
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export const CUSTOM_ERROR = {
|
export const CUSTOM_ERROR = {
|
||||||
DIRECT_OPEN_WITH_NO_QUERY_PARAMS: 'direct open with no query params',
|
DIRECT_OPEN_WITH_NO_QUERY_PARAMS: "direct open with no query params",
|
||||||
MISSING_REQUIRED_QUERY_PARAM: 'missing required query param',
|
MISSING_REQUIRED_QUERY_PARAM: "missing required query param",
|
||||||
INVALID_ACTION: 'invalid action',
|
INVALID_ACTION: "invalid action",
|
||||||
};
|
};
|
||||||
|
@ -1,28 +0,0 @@
|
|||||||
import { logError } from 'utils/sentry';
|
|
||||||
|
|
||||||
export enum LS_KEYS {
|
|
||||||
AnonymizeUserID = 'anonymizedUserID',
|
|
||||||
}
|
|
||||||
|
|
||||||
export const getData = (key: LS_KEYS) => {
|
|
||||||
try {
|
|
||||||
if (
|
|
||||||
typeof localStorage === 'undefined' ||
|
|
||||||
typeof key === 'undefined' ||
|
|
||||||
typeof localStorage.getItem(key) === 'undefined'
|
|
||||||
) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const data = localStorage.getItem(key);
|
|
||||||
return data && JSON.parse(data);
|
|
||||||
} catch (e) {
|
|
||||||
logError(e, 'Failed to Parse JSON');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
export const setData = (key: LS_KEYS, value: object) => {
|
|
||||||
if (typeof localStorage === 'undefined') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
localStorage.setItem(key, JSON.stringify(value));
|
|
||||||
};
|
|
@ -1,14 +1,3 @@
|
|||||||
import * as Sentry from '@sentry/nextjs';
|
export const logError = (e: unknown, msg?: string) => {
|
||||||
import { getUserAnonymizedID } from 'utils/user';
|
console.error(msg, e);
|
||||||
|
|
||||||
export const logError = (e: any, msg?: string) => {
|
|
||||||
Sentry.captureException(e, {
|
|
||||||
level: "info",
|
|
||||||
user: { id: getUserAnonymizedID() },
|
|
||||||
contexts: {
|
|
||||||
context: {
|
|
||||||
message: msg,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
import { getConstantValue } from './vernacularStrings';
|
|
||||||
|
|
||||||
const constants = getConstantValue();
|
|
||||||
export default constants;
|
|
6
web/apps/payments/src/utils/strings/constants.tsx
Normal file
6
web/apps/payments/src/utils/strings/constants.tsx
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
const englishConstants = {
|
||||||
|
TITLE: "Payments | ente.io",
|
||||||
|
SOMETHING_WENT_WRONG: "Oops, something went wrong.",
|
||||||
|
NOT_FOUND: "404 | This page could not be found.",
|
||||||
|
};
|
||||||
|
export default englishConstants;
|
@ -1,6 +0,0 @@
|
|||||||
const englishConstants = {
|
|
||||||
TITLE: 'Payments | ente.io',
|
|
||||||
SOMETHING_WENT_WRONG: 'Oops, something went wrong.',
|
|
||||||
NOT_FOUND: '404 | This page could not be found.',
|
|
||||||
};
|
|
||||||
export default englishConstants;
|
|
@ -1,87 +0,0 @@
|
|||||||
import { runningInBrowser } from 'utils/common';
|
|
||||||
import englishConstants from './englishConstants';
|
|
||||||
|
|
||||||
/** Enums of supported locale */
|
|
||||||
export enum locale {
|
|
||||||
en = 'en',
|
|
||||||
hi = 'hi',
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Defines a template with placeholders which can then be
|
|
||||||
* substituted at run time. Enabling the developer to create
|
|
||||||
* different template for different locale and populate them
|
|
||||||
* at run time.
|
|
||||||
*
|
|
||||||
* @param strings
|
|
||||||
* @param keys
|
|
||||||
* @returns string
|
|
||||||
*/
|
|
||||||
export function template(
|
|
||||||
strings: TemplateStringsArray,
|
|
||||||
...keys: string[] | number[]
|
|
||||||
) {
|
|
||||||
return (...values: any[]) => {
|
|
||||||
const dict = values[values.length - 1] || {};
|
|
||||||
const result = [strings[0]];
|
|
||||||
keys.forEach((key, i) => {
|
|
||||||
const value = typeof key === 'number' ? values[key] : dict[key];
|
|
||||||
result.push(value, strings[i + 1]);
|
|
||||||
});
|
|
||||||
return result.join('');
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Type for vernacular string constants */
|
|
||||||
export type VernacularConstants<T> = {
|
|
||||||
[locale.en]: T;
|
|
||||||
[locale.hi]?: {
|
|
||||||
[x in keyof T]?: string;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a valid locale from string and defaults
|
|
||||||
* to English.
|
|
||||||
*
|
|
||||||
* @param lang
|
|
||||||
*/
|
|
||||||
export const getLocale = (lang: string) => {
|
|
||||||
switch (lang) {
|
|
||||||
case locale.hi:
|
|
||||||
return locale.hi;
|
|
||||||
default:
|
|
||||||
return locale.en;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Global constants
|
|
||||||
*/
|
|
||||||
const globalConstants: VernacularConstants<typeof englishConstants> = {
|
|
||||||
en: englishConstants,
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Function to extend global constants with local constants
|
|
||||||
* @param localConstants
|
|
||||||
*/
|
|
||||||
export function getConstantValue<T>(localConstants?: VernacularConstants<T>) {
|
|
||||||
const searchParam = runningInBrowser() ? window.location.search : '';
|
|
||||||
const query = new URLSearchParams(searchParam);
|
|
||||||
const currLocale = getLocale(query.get('lang') ?? 'en');
|
|
||||||
|
|
||||||
if (currLocale !== 'en') {
|
|
||||||
return {
|
|
||||||
...globalConstants.en,
|
|
||||||
...localConstants?.en,
|
|
||||||
...globalConstants[currLocale],
|
|
||||||
...localConstants?.[currLocale],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
...globalConstants[currLocale],
|
|
||||||
...localConstants?.[currLocale],
|
|
||||||
};
|
|
||||||
}
|
|
@ -1,23 +0,0 @@
|
|||||||
import { getData, LS_KEYS, setData } from 'utils/localStorage';
|
|
||||||
|
|
||||||
export function makeID(length: number) {
|
|
||||||
let result = '';
|
|
||||||
const characters =
|
|
||||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
|
||||||
const charactersLength = characters.length;
|
|
||||||
for (let i = 0; i < length; i++) {
|
|
||||||
result += characters.charAt(
|
|
||||||
Math.floor(Math.random() * charactersLength),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getUserAnonymizedID() {
|
|
||||||
let anonymizeUserID = getData(LS_KEYS.AnonymizeUserID)?.id;
|
|
||||||
if (!anonymizeUserID) {
|
|
||||||
anonymizeUserID = makeID(6);
|
|
||||||
setData(LS_KEYS.AnonymizeUserID, { id: anonymizeUserID });
|
|
||||||
}
|
|
||||||
return anonymizeUserID;
|
|
||||||
}
|
|
@ -1,31 +1,20 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es5",
|
"target": "es5",
|
||||||
"lib": [
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"dom",
|
"skipLibCheck": true,
|
||||||
"dom.iterable",
|
"strict": true,
|
||||||
"esnext"
|
"forceConsistentCasingInFileNames": true,
|
||||||
],
|
"noEmit": true,
|
||||||
"allowJs": true,
|
"esModuleInterop": true,
|
||||||
"skipLibCheck": true,
|
"module": "esnext",
|
||||||
"strict": true,
|
"moduleResolution": "node",
|
||||||
"forceConsistentCasingInFileNames": true,
|
"resolveJsonModule": true,
|
||||||
"noEmit": true,
|
"isolatedModules": true,
|
||||||
"esModuleInterop": true,
|
"jsx": "preserve",
|
||||||
"module": "esnext",
|
"baseUrl": "./src",
|
||||||
"moduleResolution": "node",
|
"incremental": true
|
||||||
"resolveJsonModule": true,
|
},
|
||||||
"isolatedModules": true,
|
"include": ["next-env.d.ts", "src/**/*.ts", "src/**/*.tsx"],
|
||||||
"jsx": "preserve",
|
"exclude": ["node_modules", "next.config.js"]
|
||||||
"baseUrl": "./src",
|
|
||||||
"incremental": true
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"next-env.d.ts",
|
|
||||||
"**/*.ts",
|
|
||||||
"**/*.tsx"
|
|
||||||
],
|
|
||||||
"exclude": [
|
|
||||||
"node_modules"
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -37,10 +37,6 @@
|
|||||||
#
|
#
|
||||||
# NEXT_PUBLIC_ENTE_ACCOUNTS_ENDPOINT = http://localhost:3001
|
# NEXT_PUBLIC_ENTE_ACCOUNTS_ENDPOINT = http://localhost:3001
|
||||||
|
|
||||||
# The Ente API endpoint for payments related functionality
|
|
||||||
#
|
|
||||||
# NEXT_PUBLIC_ENTE_PAYMENT_ENDPOINT = http://localhost:3001
|
|
||||||
|
|
||||||
# The URL for the shared albums deployment
|
# The URL for the shared albums deployment
|
||||||
#
|
#
|
||||||
# The shared albums are served from the photos app code, and "albums.ente.io" is
|
# The shared albums are served from the photos app code, and "albums.ente.io" is
|
||||||
@ -68,6 +64,10 @@
|
|||||||
#
|
#
|
||||||
# NEXT_PUBLIC_ENTE_FAMILY_PORTAL_ENDPOINT = http://localhost:3003
|
# NEXT_PUBLIC_ENTE_FAMILY_PORTAL_ENDPOINT = http://localhost:3003
|
||||||
|
|
||||||
|
# The Ente API endpoint for payments related functionality
|
||||||
|
#
|
||||||
|
# NEXT_PUBLIC_ENTE_PAYMENTS_ENDPOINT = http://localhost:3004
|
||||||
|
|
||||||
# The JSON which describes the expected results of our integration tests. See
|
# The JSON which describes the expected results of our integration tests. See
|
||||||
# `upload.test.ts` for more details of the expected format.
|
# `upload.test.ts` for more details of the expected format.
|
||||||
#
|
#
|
||||||
|
@ -11,16 +11,19 @@
|
|||||||
"build:accounts": "yarn workspace accounts next build",
|
"build:accounts": "yarn workspace accounts next build",
|
||||||
"build:auth": "yarn workspace auth next build",
|
"build:auth": "yarn workspace auth next build",
|
||||||
"build:cast": "yarn workspace cast next build",
|
"build:cast": "yarn workspace cast next build",
|
||||||
|
"build:payments": "yarn workspace payments next build",
|
||||||
"build:photos": "yarn workspace photos next build",
|
"build:photos": "yarn workspace photos next build",
|
||||||
"deploy:accounts": "open 'https://github.com/ente-io/ente/compare/deploy/accounts...main?quick_pull=1&title=[web]+Deploy+accounts&body=Deploy+accounts.ente.io'",
|
"deploy:accounts": "open 'https://github.com/ente-io/ente/compare/deploy/accounts...main?quick_pull=1&title=[web]+Deploy+accounts&body=Deploy+accounts.ente.io'",
|
||||||
"deploy:auth": "open 'https://github.com/ente-io/ente/compare/deploy/auth...main?quick_pull=1&title=[web]+Deploy+auth&body=Deploy+auth.ente.io'",
|
"deploy:auth": "open 'https://github.com/ente-io/ente/compare/deploy/auth...main?quick_pull=1&title=[web]+Deploy+auth&body=Deploy+auth.ente.io'",
|
||||||
"deploy:cast": "open 'https://github.com/ente-io/ente/compare/deploy/cast...main?quick_pull=1&title=[web]+Deploy+cast&body=Deploy+cast.ente.io'",
|
"deploy:cast": "open 'https://github.com/ente-io/ente/compare/deploy/cast...main?quick_pull=1&title=[web]+Deploy+cast&body=Deploy+cast.ente.io'",
|
||||||
|
"deploy:payments": "open 'https://github.com/ente-io/ente/compare/deploy/payments...main?quick_pull=1&title=[web]+Deploy+payments&body=Deploy+payments.ente.io'",
|
||||||
"deploy:photos": "open 'https://github.com/ente-io/ente/compare/deploy/photos...main?quick_pull=1&title=[web]+Deploy+photos&body=Deploy+web.ente.io'",
|
"deploy:photos": "open 'https://github.com/ente-io/ente/compare/deploy/photos...main?quick_pull=1&title=[web]+Deploy+photos&body=Deploy+web.ente.io'",
|
||||||
"dev": "yarn dev:photos",
|
"dev": "yarn dev:photos",
|
||||||
"dev:accounts": "yarn workspace accounts next dev",
|
"dev:accounts": "yarn workspace accounts next dev -p 3001",
|
||||||
"dev:albums": "yarn workspace photos next dev -p 3002",
|
"dev:albums": "yarn workspace photos next dev -p 3002",
|
||||||
"dev:auth": "yarn workspace auth next dev",
|
"dev:auth": "yarn workspace auth next dev",
|
||||||
"dev:cast": "yarn workspace cast next dev",
|
"dev:cast": "yarn workspace cast next dev",
|
||||||
|
"dev:payments": "yarn workspace photos next dev -p 3004",
|
||||||
"dev:photos": "yarn workspace photos next dev",
|
"dev:photos": "yarn workspace photos next dev",
|
||||||
"lint": "yarn prettier --check . && yarn workspaces run eslint .",
|
"lint": "yarn prettier --check . && yarn workspaces run eslint .",
|
||||||
"lint-fix": "yarn prettier --write . && yarn workspaces run eslint --fix ."
|
"lint-fix": "yarn prettier --write . && yarn workspaces run eslint --fix ."
|
||||||
|
@ -70,14 +70,6 @@ export const getAccountsURL = () => {
|
|||||||
return `https://accounts.ente.io`;
|
return `https://accounts.ente.io`;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const getPaymentsURL = () => {
|
|
||||||
const paymentsURL = process.env.NEXT_PUBLIC_ENTE_PAYMENT_ENDPOINT;
|
|
||||||
if (paymentsURL) {
|
|
||||||
return paymentsURL;
|
|
||||||
}
|
|
||||||
return `https://payments.ente.io`;
|
|
||||||
};
|
|
||||||
|
|
||||||
export const getAlbumsURL = () => {
|
export const getAlbumsURL = () => {
|
||||||
const albumsURL = process.env.NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT;
|
const albumsURL = process.env.NEXT_PUBLIC_ENTE_ALBUMS_ENDPOINT;
|
||||||
if (albumsURL) {
|
if (albumsURL) {
|
||||||
@ -97,3 +89,14 @@ export const getFamilyPortalURL = () => {
|
|||||||
}
|
}
|
||||||
return `https://family.ente.io`;
|
return `https://family.ente.io`;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the URL for the host that handles payment related functionality.
|
||||||
|
*/
|
||||||
|
export const getPaymentsURL = () => {
|
||||||
|
const paymentsURL = process.env.NEXT_PUBLIC_ENTE_PAYMENTS_ENDPOINT;
|
||||||
|
if (paymentsURL) {
|
||||||
|
return paymentsURL;
|
||||||
|
}
|
||||||
|
return `https://payments.ente.io`;
|
||||||
|
};
|
||||||
|
@ -538,7 +538,7 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.7.2.tgz#2d4260033e199b3032a08b41348ac10de21c47e9"
|
resolved "https://registry.yarnpkg.com/@rushstack/eslint-patch/-/eslint-patch-1.7.2.tgz#2d4260033e199b3032a08b41348ac10de21c47e9"
|
||||||
integrity sha512-RbhOOTCNoCrbfkRyoXODZp75MlpiHMgbE5MEBZAnnnLyQNgrigEj4p0lzsMDyc1zVsJDLrivB58tgg3emX0eEA==
|
integrity sha512-RbhOOTCNoCrbfkRyoXODZp75MlpiHMgbE5MEBZAnnnLyQNgrigEj4p0lzsMDyc1zVsJDLrivB58tgg3emX0eEA==
|
||||||
|
|
||||||
"@stripe/stripe-js@^1.13.2":
|
"@stripe/stripe-js@^1.13.2", "@stripe/stripe-js@^1.17.0":
|
||||||
version "1.54.2"
|
version "1.54.2"
|
||||||
resolved "https://registry.yarnpkg.com/@stripe/stripe-js/-/stripe-js-1.54.2.tgz#0665848e22cbda936cfd05256facdfbba121438d"
|
resolved "https://registry.yarnpkg.com/@stripe/stripe-js/-/stripe-js-1.54.2.tgz#0665848e22cbda936cfd05256facdfbba121438d"
|
||||||
integrity sha512-R1PwtDvUfs99cAjfuQ/WpwJ3c92+DAMy9xGApjqlWQMj0FKQabUAys2swfTRNzuYAYJh7NqK2dzcYVNkKLEKUg==
|
integrity sha512-R1PwtDvUfs99cAjfuQ/WpwJ3c92+DAMy9xGApjqlWQMj0FKQabUAys2swfTRNzuYAYJh7NqK2dzcYVNkKLEKUg==
|
||||||
@ -1151,6 +1151,13 @@ axe-core@=4.7.0:
|
|||||||
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf"
|
resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf"
|
||||||
integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==
|
integrity sha512-M0JtH+hlOL5pLQwHOLNYZaXuhqmvS8oExsqB1SBYgA4Dk7u/xx+YdGHXaK5pyUfed5mYXdlYiphWq3G8cRi5JQ==
|
||||||
|
|
||||||
|
axios@^0.21.1:
|
||||||
|
version "0.21.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.4.tgz#c67b90dc0568e5c1cf2b0b858c43ba28e2eda575"
|
||||||
|
integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==
|
||||||
|
dependencies:
|
||||||
|
follow-redirects "^1.14.0"
|
||||||
|
|
||||||
axios@^1.6.7:
|
axios@^1.6.7:
|
||||||
version "1.6.7"
|
version "1.6.7"
|
||||||
resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.7.tgz#7b48c2e27c96f9c68a2f8f31e2ab19f59b06b0a7"
|
resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.7.tgz#7b48c2e27c96f9c68a2f8f31e2ab19f59b06b0a7"
|
||||||
@ -1210,6 +1217,11 @@ blazeface-back@^0.0.9:
|
|||||||
resolved "https://registry.yarnpkg.com/blazeface-back/-/blazeface-back-0.0.9.tgz#a8a26a0022950eb21136693f2fca3c52315ad2a4"
|
resolved "https://registry.yarnpkg.com/blazeface-back/-/blazeface-back-0.0.9.tgz#a8a26a0022950eb21136693f2fca3c52315ad2a4"
|
||||||
integrity sha512-t0i5V117j074d7d7mlLaRq9n/bYchXcSEgpWVbGGloV68A6Jn22t4SNoEC3t+MOsU8H+eXoDv2/6+JsqActM1g==
|
integrity sha512-t0i5V117j074d7d7mlLaRq9n/bYchXcSEgpWVbGGloV68A6Jn22t4SNoEC3t+MOsU8H+eXoDv2/6+JsqActM1g==
|
||||||
|
|
||||||
|
bootstrap@4.6.0:
|
||||||
|
version "4.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.6.0.tgz#97b9f29ac98f98dfa43bf7468262d84392552fd7"
|
||||||
|
integrity sha512-Io55IuQY3kydzHtbGvQya3H+KorS/M9rSNyfCGCg9WZ4pyT/lCxIlpJgG1GXW/PswzC84Tr2fBYi+7+jFVQQBw==
|
||||||
|
|
||||||
bootstrap@^4.5.2:
|
bootstrap@^4.5.2:
|
||||||
version "4.6.2"
|
version "4.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.6.2.tgz#8e0cd61611728a5bf65a3a2b8d6ff6c77d5d7479"
|
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-4.6.2.tgz#8e0cd61611728a5bf65a3a2b8d6ff6c77d5d7479"
|
||||||
@ -2042,6 +2054,11 @@ flatted@^3.2.9:
|
|||||||
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a"
|
resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.1.tgz#21db470729a6734d4997002f439cb308987f567a"
|
||||||
integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==
|
integrity sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==
|
||||||
|
|
||||||
|
follow-redirects@^1.14.0:
|
||||||
|
version "1.15.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.6.tgz#7f815c0cda4249c74ff09e95ef97c23b5fd0399b"
|
||||||
|
integrity sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==
|
||||||
|
|
||||||
follow-redirects@^1.15.4:
|
follow-redirects@^1.15.4:
|
||||||
version "1.15.5"
|
version "1.15.5"
|
||||||
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020"
|
resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.5.tgz#54d4d6d062c0fa7d9d17feb008461550e3ba8020"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user