Compare commits
9
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2212e607cf | ||
|
|
a50ff841a0 | ||
|
|
d2020664d5 | ||
|
|
e2b2af6680 | ||
|
|
3b4af29bd5 | ||
|
|
37ca83b29f | ||
|
|
8959364dee | ||
|
|
d24a02f7b9 | ||
|
|
caaea7e475 |
@@ -3,6 +3,7 @@ VITE_BASE_URL=
|
|||||||
VITE_ALCHEMY_API_KEY=
|
VITE_ALCHEMY_API_KEY=
|
||||||
|
|
||||||
VITE_PK_ENCRYPTION_KEY=
|
VITE_PK_ENCRYPTION_KEY=
|
||||||
|
VITE_ROUTER_TYPE=
|
||||||
|
|
||||||
VITE_V3_TOKEN_ADDRESS=
|
VITE_V3_TOKEN_ADDRESS=
|
||||||
VITE_TOKEN_MIGRATION_URI=
|
VITE_TOKEN_MIGRATION_URI=
|
||||||
|
|||||||
@@ -0,0 +1,41 @@
|
|||||||
|
name: Publish ApplicationRecord to Registry
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [published]
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- registry
|
||||||
|
- test
|
||||||
|
|
||||||
|
env:
|
||||||
|
CERC_REGISTRY_USER_KEY: ${{ secrets.CICD_LACONIC_USER_KEY }}
|
||||||
|
CERC_REGISTRY_BOND_ID: ${{ secrets.CICD_LACONIC_BOND_ID }}
|
||||||
|
COREPACK_ENABLE_STRICT: 0
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
cns_publish:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: "Clone project repository"
|
||||||
|
uses: actions/checkout@v3
|
||||||
|
- name: Use Node.js
|
||||||
|
uses: actions/setup-node@v3
|
||||||
|
with:
|
||||||
|
node-version: 18
|
||||||
|
- name: "Install Yarn"
|
||||||
|
run: npm install -g yarn
|
||||||
|
- name: "Install Corepack"
|
||||||
|
run: npm install -g corepack
|
||||||
|
- name: "Enable Corepack"
|
||||||
|
run: corepack enable
|
||||||
|
- name: "Install registry CLI"
|
||||||
|
run: |
|
||||||
|
npm config set @cerc-io:registry https://git.vdb.to/api/packages/cerc-io/npm/
|
||||||
|
yarn global add @cerc-io/laconic-registry-cli
|
||||||
|
- name: "Install jq"
|
||||||
|
run: apt -y update && apt -y install jq
|
||||||
|
- name: "Publish Application Record"
|
||||||
|
run: scripts/publish-app-record.sh
|
||||||
|
- name: "Request Deployment"
|
||||||
|
run: scripts/request-app-deployment.sh
|
||||||
|
|
||||||
@@ -66,10 +66,12 @@ This will automatically open your default browser at `http://localhost:61000`.
|
|||||||
|
|
||||||
Add or modify the relevant endpoints, links and options in `/public/configs/env.json`.
|
Add or modify the relevant endpoints, links and options in `/public/configs/env.json`.
|
||||||
You'll need to provide a Wallet Connect project id to enable onboarding and wallet connection:
|
You'll need to provide a Wallet Connect project id to enable onboarding and wallet connection:
|
||||||
|
|
||||||
- Create a project on https://cloud.walletconnect.com/app
|
- Create a project on https://cloud.walletconnect.com/app
|
||||||
- Copy over the project ID into this [field](https://github.com/dydxprotocol/v4-web/blob/67ecbd75b43e0c264b7b4d2d9b3d969830b0621c/public/configs/env.json#L822C33-L822C46)
|
- Copy over the project ID into this [field](https://github.com/dydxprotocol/v4-web/blob/67ecbd75b43e0c264b7b4d2d9b3d969830b0621c/public/configs/env.json#L822C33-L822C46)
|
||||||
|
|
||||||
## Part 4: Set Enviornment variables
|
## Part 4: Set Enviornment variables
|
||||||
|
|
||||||
Set environment variables via `.env`.
|
Set environment variables via `.env`.
|
||||||
|
|
||||||
- `VITE_BASE_URL` (required): The base URL of the deployment (e.g., `https://www.example.com`).
|
- `VITE_BASE_URL` (required): The base URL of the deployment (e.g., `https://www.example.com`).
|
||||||
@@ -96,10 +98,12 @@ Select "Import Git Repository" from your dashboard, and provide the URL of this
|
|||||||
### Step 2: Configure your project
|
### Step 2: Configure your project
|
||||||
|
|
||||||
For the "Build & Development Settings", we recommend the following:
|
For the "Build & Development Settings", we recommend the following:
|
||||||
|
|
||||||
- Framework Preset: `Vite`
|
- Framework Preset: `Vite`
|
||||||
- Build Command (override): `pnpm run build`
|
- Build Command (override): `pnpm run build`
|
||||||
|
|
||||||
By default, the dev server runs in development mode and the build command runs in production mode. To override the default mode, you can pass in the `--mode` option flag. For example, if you want to build your app for testnet:
|
By default, the dev server runs in development mode and the build command runs in production mode. To override the default mode, you can pass in the `--mode` option flag. For example, if you want to build your app for testnet:
|
||||||
|
|
||||||
```
|
```
|
||||||
pnpm run build --mode testnet
|
pnpm run build --mode testnet
|
||||||
```
|
```
|
||||||
@@ -114,6 +118,14 @@ For more details, check out Vercel's [official documentation](https://vercel.com
|
|||||||
|
|
||||||
## Deploying to IPFS
|
## Deploying to IPFS
|
||||||
|
|
||||||
|
### Must Enable HashRouting
|
||||||
|
|
||||||
|
Add the following to `.env` file
|
||||||
|
|
||||||
|
```
|
||||||
|
VITE_ROUTER_TYPE=hash
|
||||||
|
```
|
||||||
|
|
||||||
### web3.storage: deploy to IPFS via web3.storage using the provided script
|
### web3.storage: deploy to IPFS via web3.storage using the provided script
|
||||||
|
|
||||||
Export the API token as an environment variable (replace `your_token` with the generated token), and run the script to build and deploy to IPFS:
|
Export the API token as an environment variable (replace `your_token` with the generated token), and run the script to build and deploy to IPFS:
|
||||||
@@ -150,12 +162,14 @@ Replace `your_cid` with the actual CID.
|
|||||||
We recommend that you add your website to Cloudflare for additional security settings.
|
We recommend that you add your website to Cloudflare for additional security settings.
|
||||||
|
|
||||||
To block OFAC Sanctioned countries:
|
To block OFAC Sanctioned countries:
|
||||||
|
|
||||||
1. Navigate Websites > Domain > Security > WAF
|
1. Navigate Websites > Domain > Security > WAF
|
||||||
|
|
||||||
2. Create Rule with the following settings:
|
2. Create Rule with the following settings:
|
||||||
* If incoming requests match
|
|
||||||
`(ip.geoip.country eq "CU") or (ip.geoip.country eq "IR") or (ip.geoip.country eq "KP") or (ip.geoip.country eq "SY") or (ip.geoip.country eq "MM") or (ip.geoip.subdivision_1_iso_code eq "UA-09") or (ip.geoip.subdivision_1_iso_code eq "UA-14") or (ip.geoip.subdivision_1_iso_code eq "UA-43")`
|
- If incoming requests match
|
||||||
* This rule will bring up a Cloudflare page when a restricted geography tries to access your site. You will have the option to display:
|
`(ip.geoip.country eq "CU") or (ip.geoip.country eq "IR") or (ip.geoip.country eq "KP") or (ip.geoip.country eq "SY") or (ip.geoip.country eq "MM") or (ip.geoip.subdivision_1_iso_code eq "UA-09") or (ip.geoip.subdivision_1_iso_code eq "UA-14") or (ip.geoip.subdivision_1_iso_code eq "UA-43")`
|
||||||
1. Custom Text
|
- This rule will bring up a Cloudflare page when a restricted geography tries to access your site. You will have the option to display:
|
||||||
- (e.g. `Because you appear to be a resident of, or trading from, a jurisdiction that violates our terms of use, or have engaged in activity that violates our terms of use, you have been blocked. You may withdraw your funds from the protocol at any time.`)
|
1. Custom Text
|
||||||
2. Default Cloudflare WAF block page
|
- (e.g. `Because you appear to be a resident of, or trading from, a jurisdiction that violates our terms of use, or have engaged in activity that violates our terms of use, you have been blocked. You may withdraw your funds from the protocol at any time.`)
|
||||||
|
2. Default Cloudflare WAF block page
|
||||||
|
|||||||
+2
-1
@@ -1,5 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "dydx-chain-web",
|
"name": "@lx-mars/dydx-chain-web",
|
||||||
|
"repository": "https://git.vdb.to/LaconicNetwork/dydx-v4-web",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
|
|||||||
@@ -72,7 +72,7 @@
|
|||||||
"strideZoneApp": "https://testnet.stride.zone",
|
"strideZoneApp": "https://testnet.stride.zone",
|
||||||
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
|
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
|
||||||
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet",
|
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet",
|
||||||
"launchIncentive": "https://cloud.chaoslabs.co/"
|
"launchIncentive": "https://cloud.chaoslabs.co"
|
||||||
},
|
},
|
||||||
"dydx-testnet-4": {
|
"dydx-testnet-4": {
|
||||||
"tos": "https://dydx.exchange/v4-terms",
|
"tos": "https://dydx.exchange/v4-terms",
|
||||||
@@ -94,7 +94,7 @@
|
|||||||
"strideZoneApp": "https://testnet.stride.zone",
|
"strideZoneApp": "https://testnet.stride.zone",
|
||||||
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
|
"accountExportLearnMore": "https://help.dydx.exchange/en/articles/8565867-secret-phrase-on-dydx-chain",
|
||||||
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet",
|
"walletLearnMore": "https://www.dydx.academy/video/defi-wallet",
|
||||||
"launchIncentive": "https://cloud.chaoslabs.co/"
|
"launchIncentive": "https://cloud.chaoslabs.co"
|
||||||
},
|
},
|
||||||
"[mainnet chain id]": {
|
"[mainnet chain id]": {
|
||||||
"tos": "[HTTP link to TOS]",
|
"tos": "[HTTP link to TOS]",
|
||||||
|
|||||||
Executable
+70
@@ -0,0 +1,70 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
RECORD_FILE=tmp.rf.$$
|
||||||
|
CONFIG_FILE=`mktemp`
|
||||||
|
|
||||||
|
CERC_APP_TYPE=${CERC_APP_TYPE:-"webapp"}
|
||||||
|
CERC_REPO_REF=${CERC_REPO_REF:-${GITHUB_SHA:-`git log -1 --format="%H"`}}
|
||||||
|
CERC_IS_LATEST_RELEASE=${CERC_IS_LATEST_RELEASE:-"true"}
|
||||||
|
|
||||||
|
rcd_name=$(jq -r '.name' package.json | sed 's/null//')
|
||||||
|
rcd_desc=$(jq -r '.description' package.json | sed 's/null//')
|
||||||
|
rcd_repository=$(jq -r '.repository' package.json | sed 's/null//')
|
||||||
|
rcd_homepage=$(jq -r '.homepage' package.json | sed 's/null//')
|
||||||
|
rcd_license=$(jq -r '.license' package.json | sed 's/null//')
|
||||||
|
rcd_author=$(jq -r '.author' package.json | sed 's/null//')
|
||||||
|
rcd_app_version=$(jq -r '.version' package.json | sed 's/null//')
|
||||||
|
|
||||||
|
cat <<EOF > "$CONFIG_FILE"
|
||||||
|
services:
|
||||||
|
cns:
|
||||||
|
restEndpoint: '${CERC_REGISTRY_REST_ENDPOINT:-http://console.laconic.com:1317}'
|
||||||
|
gqlEndpoint: '${CERC_REGISTRY_GQL_ENDPOINT:-http://console.laconic.com:9473/api}'
|
||||||
|
chainId: ${CERC_REGISTRY_CHAIN_ID:-laconic_9000-1}
|
||||||
|
gas: 1750000
|
||||||
|
fees: 20000aphoton
|
||||||
|
EOF
|
||||||
|
|
||||||
|
next_ver=$(laconic -c $CONFIG_FILE cns record list --type ApplicationRecord --all --name "$rcd_name" 2>/dev/null | jq -r -s ".[] | sort_by(.createTime) | reverse | [ .[] | select(.bondId == \"$CERC_REGISTRY_BOND_ID\") ] | .[0].attributes.version" | awk -F. -v OFS=. '{$NF += 1 ; print}')
|
||||||
|
|
||||||
|
if [ -z "$next_ver" ] || [ "1" == "$next_ver" ]; then
|
||||||
|
next_ver=0.0.1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat <<EOF | sed '/.*: ""$/d' > "$RECORD_FILE"
|
||||||
|
record:
|
||||||
|
type: ApplicationRecord
|
||||||
|
version: ${next_ver}
|
||||||
|
name: "$rcd_name"
|
||||||
|
description: "$rcd_desc"
|
||||||
|
homepage: "$rcd_homepage"
|
||||||
|
license: "$rcd_license"
|
||||||
|
author: "$rcd_author"
|
||||||
|
repository:
|
||||||
|
- "$rcd_repository"
|
||||||
|
repository_ref: "$CERC_REPO_REF"
|
||||||
|
app_version: "$rcd_app_version"
|
||||||
|
app_type: "$CERC_APP_TYPE"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
|
||||||
|
cat $RECORD_FILE
|
||||||
|
RECORD_ID=$(laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE --user-key "${CERC_REGISTRY_USER_KEY}" --bond-id ${CERC_REGISTRY_BOND_ID} | jq -r '.id')
|
||||||
|
echo $RECORD_ID
|
||||||
|
|
||||||
|
if [ -z "$CERC_REGISTRY_APP_CRN" ]; then
|
||||||
|
authority=$(echo "$rcd_name" | cut -d'/' -f1 | sed 's/@//')
|
||||||
|
app=$(echo "$rcd_name" | cut -d'/' -f2-)
|
||||||
|
CERC_REGISTRY_APP_CRN="crn://$authority/applications/$app"
|
||||||
|
fi
|
||||||
|
|
||||||
|
laconic -c $CONFIG_FILE cns name set --user-key "${CERC_REGISTRY_USER_KEY}" --bond-id ${CERC_REGISTRY_BOND_ID} "$CERC_REGISTRY_APP_CRN@${rcd_app_version}" "$RECORD_ID"
|
||||||
|
laconic -c $CONFIG_FILE cns name set --user-key "${CERC_REGISTRY_USER_KEY}" --bond-id ${CERC_REGISTRY_BOND_ID} "$CERC_REGISTRY_APP_CRN@${CERC_REPO_REF}" "$RECORD_ID"
|
||||||
|
if [ "true" == "$CERC_IS_LATEST_RELEASE" ]; then
|
||||||
|
laconic -c $CONFIG_FILE cns name set --user-key "${CERC_REGISTRY_USER_KEY}" --bond-id ${CERC_REGISTRY_BOND_ID} "$CERC_REGISTRY_APP_CRN" "$RECORD_ID"
|
||||||
|
fi
|
||||||
|
|
||||||
|
rm -f $RECORD_FILE $CONFIG_FILE
|
||||||
|
|
||||||
Executable
+57
@@ -0,0 +1,57 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
RECORD_FILE=tmp.rf.$$
|
||||||
|
CONFIG_FILE=`mktemp`
|
||||||
|
|
||||||
|
rcd_name=$(jq -r '.name' package.json | sed 's/null//' | sed 's/^@//')
|
||||||
|
rcd_app_version=$(jq -r '.version' package.json | sed 's/null//')
|
||||||
|
|
||||||
|
cat <<EOF > "$CONFIG_FILE"
|
||||||
|
services:
|
||||||
|
cns:
|
||||||
|
restEndpoint: '${CERC_REGISTRY_REST_ENDPOINT:-http://console.laconic.com:1317}'
|
||||||
|
gqlEndpoint: '${CERC_REGISTRY_GQL_ENDPOINT:-http://console.laconic.com:9473/api}'
|
||||||
|
chainId: ${CERC_REGISTRY_CHAIN_ID:-laconic_9000-1}
|
||||||
|
gas: 1550000
|
||||||
|
fees: 20000aphoton
|
||||||
|
EOF
|
||||||
|
|
||||||
|
if [ -z "$CERC_REGISTRY_APP_CRN" ]; then
|
||||||
|
authority=$(echo "$rcd_name" | cut -d'/' -f1 | sed 's/@//')
|
||||||
|
app=$(echo "$rcd_name" | cut -d'/' -f2-)
|
||||||
|
CERC_REGISTRY_APP_CRN="crn://$authority/applications/$app"
|
||||||
|
fi
|
||||||
|
|
||||||
|
APP_RECORD=$(laconic -c $CONFIG_FILE cns name resolve "$CERC_REGISTRY_APP_CRN" | jq '.[0]')
|
||||||
|
if [ -z "$APP_RECORD" ] || [ "null" == "$APP_RECORD" ]; then
|
||||||
|
echo "No record found for $CERC_REGISTRY_APP_CRN."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
cat <<EOF | sed '/.*: ""$/d' > "$RECORD_FILE"
|
||||||
|
record:
|
||||||
|
type: ApplicationDeploymentRequest
|
||||||
|
version: 1.0.0
|
||||||
|
name: "$rcd_name@$rcd_app_version"
|
||||||
|
application: "$CERC_REGISTRY_APP_CRN@$rcd_app_version"
|
||||||
|
dns: "$CERC_REGISTRY_DEPLOYMENT_SHORT_HOSTNAME"
|
||||||
|
deployment: "$CERC_REGISTRY_DEPLOYMENT_CRN"
|
||||||
|
config:
|
||||||
|
env:
|
||||||
|
CERC_WEBAPP_DEBUG: "$rcd_app_version"
|
||||||
|
CERC_MAX_GENERATE_TIME: 180
|
||||||
|
CERC_NEXT_VERSION: 13.4.2
|
||||||
|
meta:
|
||||||
|
note: "Added by CI @ `date`"
|
||||||
|
repository: "`git remote get-url origin`"
|
||||||
|
repository_ref: "${GITHUB_SHA:-`git log -1 --format="%H"`}"
|
||||||
|
EOF
|
||||||
|
|
||||||
|
cat $RECORD_FILE
|
||||||
|
RECORD_ID=$(laconic -c $CONFIG_FILE cns record publish --filename $RECORD_FILE --user-key "${CERC_REGISTRY_USER_KEY}" --bond-id ${CERC_REGISTRY_BOND_ID} | jq -r '.id')
|
||||||
|
echo $RECORD_ID
|
||||||
|
|
||||||
|
rm -f $RECORD_FILE $CONFIG_FILE
|
||||||
|
|
||||||
+16
-5
@@ -1,5 +1,5 @@
|
|||||||
import { lazy, Suspense } from 'react';
|
import { lazy, Suspense, useMemo } from 'react';
|
||||||
import { Navigate, Route, Routes } from 'react-router-dom';
|
import { Navigate, Route, Routes, useLocation } from 'react-router-dom';
|
||||||
import styled, { AnyStyledComponent, css } from 'styled-components';
|
import styled, { AnyStyledComponent, css } from 'styled-components';
|
||||||
import { WagmiConfig } from 'wagmi';
|
import { WagmiConfig } from 'wagmi';
|
||||||
import { QueryClient, QueryClientProvider } from 'react-query';
|
import { QueryClient, QueryClientProvider } from 'react-query';
|
||||||
@@ -26,6 +26,7 @@ import { RestrictionProvider } from '@/hooks/useRestrictions';
|
|||||||
import { SubaccountProvider } from '@/hooks/useSubaccount';
|
import { SubaccountProvider } from '@/hooks/useSubaccount';
|
||||||
|
|
||||||
import { GuardedMobileRoute } from '@/components/GuardedMobileRoute';
|
import { GuardedMobileRoute } from '@/components/GuardedMobileRoute';
|
||||||
|
import { LoadingSpace } from '@/components/Loading/LoadingSpinner';
|
||||||
|
|
||||||
import { HeaderDesktop } from '@/layout/Header/HeaderDesktop';
|
import { HeaderDesktop } from '@/layout/Header/HeaderDesktop';
|
||||||
import { FooterDesktop } from '@/layout/Footer/FooterDesktop';
|
import { FooterDesktop } from '@/layout/Footer/FooterDesktop';
|
||||||
@@ -34,12 +35,12 @@ import { NotificationsToastArea } from '@/layout/NotificationsToastArea';
|
|||||||
import { DialogManager } from '@/layout/DialogManager';
|
import { DialogManager } from '@/layout/DialogManager';
|
||||||
import { GlobalCommandDialog } from '@/views/dialogs/GlobalCommandDialog';
|
import { GlobalCommandDialog } from '@/views/dialogs/GlobalCommandDialog';
|
||||||
|
|
||||||
|
import { parseLocationHash } from '@/lib/urlUtils';
|
||||||
import { config } from '@/lib/wagmi';
|
import { config } from '@/lib/wagmi';
|
||||||
|
|
||||||
import { breakpoints } from '@/styles';
|
import { breakpoints } from '@/styles';
|
||||||
import { GlobalStyle } from '@/styles/globalStyle';
|
import { GlobalStyle } from '@/styles/globalStyle';
|
||||||
import { layoutMixins } from '@/styles/layoutMixins';
|
import { layoutMixins } from '@/styles/layoutMixins';
|
||||||
import { LoadingSpace } from './components/Loading/LoadingSpinner';
|
|
||||||
|
|
||||||
import '@/styles/constants.css';
|
import '@/styles/constants.css';
|
||||||
import '@/styles/fonts.css';
|
import '@/styles/fonts.css';
|
||||||
@@ -68,6 +69,14 @@ const Content = () => {
|
|||||||
const isShowingHeader = isNotTablet;
|
const isShowingHeader = isNotTablet;
|
||||||
const isShowingFooter = useShouldShowFooter();
|
const isShowingFooter = useShouldShowFooter();
|
||||||
const { chainTokenLabel } = useTokenConfigs();
|
const { chainTokenLabel } = useTokenConfigs();
|
||||||
|
const location = useLocation();
|
||||||
|
|
||||||
|
const pathFromHash = useMemo(() => {
|
||||||
|
if (location.hash === '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
return parseLocationHash(location.hash);
|
||||||
|
}, [location.hash]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -102,8 +111,10 @@ const Content = () => {
|
|||||||
|
|
||||||
<Route path={AppRoute.Terms} element={<TermsOfUsePage />} />
|
<Route path={AppRoute.Terms} element={<TermsOfUsePage />} />
|
||||||
<Route path={AppRoute.Privacy} element={<PrivacyPolicyPage />} />
|
<Route path={AppRoute.Privacy} element={<PrivacyPolicyPage />} />
|
||||||
|
<Route
|
||||||
<Route path="*" element={<Navigate to={DEFAULT_TRADE_ROUTE} replace />} />
|
path="*"
|
||||||
|
element={<Navigate to={pathFromHash || DEFAULT_TRADE_ROUTE} replace />}
|
||||||
|
/>
|
||||||
</Routes>
|
</Routes>
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</Styled.Main>
|
</Styled.Main>
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ export enum MobileSettingsRoute {
|
|||||||
Network = 'network',
|
Network = 'network',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const BASE_ROUTE = import.meta.env.VITE_ROUTER_TYPE === 'hash' ? '/#' : '';
|
||||||
export const TRADE_ROUTE = `${AppRoute.Trade}/:market`;
|
export const TRADE_ROUTE = `${AppRoute.Trade}/:market`;
|
||||||
export const PORTFOLIO_ROUTE = `${AppRoute.Portfolio}/:subroute`;
|
export const PORTFOLIO_ROUTE = `${AppRoute.Portfolio}/:subroute`;
|
||||||
export const HISTORY_ROUTE = `${AppRoute.Portfolio}/${PortfolioRoute.History}/:subroute`;
|
export const HISTORY_ROUTE = `${AppRoute.Portfolio}/${PortfolioRoute.History}/:subroute`;
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
import { parseLocationHash } from '@/lib/urlUtils';
|
||||||
|
|
||||||
|
describe('parseLocationHash', () => {
|
||||||
|
it('returns the path separated from hash', () => {
|
||||||
|
const hash = '#/markets';
|
||||||
|
expect(parseLocationHash(hash)).toEqual('/markets');
|
||||||
|
});
|
||||||
|
it('returns the path and query string separated from hash', () => {
|
||||||
|
const hash = '#/markets?displayinitializingmarkets=true';
|
||||||
|
expect(parseLocationHash(hash)).toEqual('/markets?displayinitializingmarkets=true');
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* @param hash location.hash
|
||||||
|
* @returns path and query string if hash parameter is not empty
|
||||||
|
*/
|
||||||
|
export const parseLocationHash = (hash: string) => {
|
||||||
|
if (!hash || hash.length === 0) return '';
|
||||||
|
|
||||||
|
// Remove '#' and split by '?'
|
||||||
|
const [path, queryString] = hash.substring(1).split('?');
|
||||||
|
|
||||||
|
// Reconstruct path and query string
|
||||||
|
return `${path}${queryString ? `?${queryString}` : ''}`;
|
||||||
|
};
|
||||||
+4
-2
@@ -1,7 +1,7 @@
|
|||||||
import './polyfills';
|
import './polyfills';
|
||||||
import { StrictMode } from 'react';
|
import { StrictMode } from 'react';
|
||||||
import ReactDOM from 'react-dom/client';
|
import ReactDOM from 'react-dom/client';
|
||||||
import { HashRouter } from 'react-router-dom';
|
import { BrowserRouter, HashRouter } from 'react-router-dom';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
|
|
||||||
import { store } from '@/state/_store';
|
import { store } from '@/state/_store';
|
||||||
@@ -12,11 +12,13 @@ import './index.css';
|
|||||||
|
|
||||||
import App from './App';
|
import App from './App';
|
||||||
|
|
||||||
|
const Router = import.meta.env.VITE_ROUTER_TYPE === 'hash' ? HashRouter : BrowserRouter;
|
||||||
|
|
||||||
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
|
||||||
<ErrorBoundary>
|
<ErrorBoundary>
|
||||||
<StrictMode>
|
<StrictMode>
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<HashRouter children={<App />} />
|
<Router children={<App />} />
|
||||||
</Provider>
|
</Provider>
|
||||||
</StrictMode>
|
</StrictMode>
|
||||||
</ErrorBoundary>
|
</ErrorBoundary>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { useState } from 'react';
|
|||||||
import styled, { AnyStyledComponent } from 'styled-components';
|
import styled, { AnyStyledComponent } from 'styled-components';
|
||||||
|
|
||||||
import { ButtonAction } from '@/constants/buttons';
|
import { ButtonAction } from '@/constants/buttons';
|
||||||
import { AppRoute } from '@/constants/routes';
|
import { AppRoute, BASE_ROUTE } from '@/constants/routes';
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
import { useStringGetter } from '@/hooks';
|
import { useStringGetter } from '@/hooks';
|
||||||
import breakpoints from '@/styles/breakpoints';
|
import breakpoints from '@/styles/breakpoints';
|
||||||
@@ -40,7 +40,7 @@ export const NewMarketAgreementDialog = ({ acceptTerms, setIsOpen }: ElementProp
|
|||||||
</Styled.Link>
|
</Styled.Link>
|
||||||
),
|
),
|
||||||
TERMS_OF_USE: (
|
TERMS_OF_USE: (
|
||||||
<Styled.Link href={`/#${AppRoute.Terms}`}>
|
<Styled.Link href={`${BASE_ROUTE}${AppRoute.Terms}`}>
|
||||||
{stringGetter({ key: STRING_KEYS.TERMS_OF_USE })}
|
{stringGetter({ key: STRING_KEYS.TERMS_OF_USE })}
|
||||||
</Styled.Link>
|
</Styled.Link>
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import styled, { type AnyStyledComponent } from 'styled-components';
|
|||||||
|
|
||||||
import { useAccounts, useStringGetter } from '@/hooks';
|
import { useAccounts, useStringGetter } from '@/hooks';
|
||||||
|
|
||||||
import { AppRoute } from '@/constants/routes';
|
import { AppRoute, BASE_ROUTE } from '@/constants/routes';
|
||||||
import { STRING_KEYS } from '@/constants/localization';
|
import { STRING_KEYS } from '@/constants/localization';
|
||||||
import { ButtonAction } from '@/constants/buttons';
|
import { ButtonAction } from '@/constants/buttons';
|
||||||
|
|
||||||
@@ -34,12 +34,12 @@ export const AcknowledgeTerms = ({ onClose, onContinue }: ElementProps) => {
|
|||||||
key: STRING_KEYS.TOS_TITLE,
|
key: STRING_KEYS.TOS_TITLE,
|
||||||
params: {
|
params: {
|
||||||
TERMS_LINK: (
|
TERMS_LINK: (
|
||||||
<Styled.Link href={`/#${AppRoute.Terms}`}>
|
<Styled.Link href={`${BASE_ROUTE}${AppRoute.Terms}`}>
|
||||||
{stringGetter({ key: STRING_KEYS.TERMS_OF_USE })}
|
{stringGetter({ key: STRING_KEYS.TERMS_OF_USE })}
|
||||||
</Styled.Link>
|
</Styled.Link>
|
||||||
),
|
),
|
||||||
PRIVACY_POLICY_LINK: (
|
PRIVACY_POLICY_LINK: (
|
||||||
<Styled.Link href={`/#${AppRoute.Privacy}`}>
|
<Styled.Link href={`${BASE_ROUTE}${AppRoute.Privacy}`}>
|
||||||
{stringGetter({ key: STRING_KEYS.PRIVACY_POLICY })}
|
{stringGetter({ key: STRING_KEYS.PRIVACY_POLICY })}
|
||||||
</Styled.Link>
|
</Styled.Link>
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"rewrites": [{ "source": "/(.*)", "destination": "/index.html" }]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user