Contributions are welcome!
Check out existing issues (especially Todo), review a pull request, or create a new issue to start a discussion.
Here are a few guidelines to follow:
- Discuss major changes with the maintainers before starting work, our Discord is a good place to do that
- Use Pull Requests (PRs) - commits direclty to
main
branch are not allowed - Use Prettier and automatic code formatting to keep PRs focused on the changes
- Use ESLint to keep code clean and consistent
- Make PRs small and focused on a single change so they are easier to review and merge
- Make PRs complete so that the new feature is functional
- Write tests to prevent regressions, unit tests with Jest in
__tests__
folder, end to end tests with Playwright ine2e
folder - Run tests locally with
npm run test-all
before submitting any PR. This will help you find issues fast. - Try to avoid custom CSS - the project uses DaisyUI and TailwindCSS for styling, whenever possible use the existing components and classes, the full rationale (by creator of TailwindCSS) is here
- Use Redux Dev Tools Extension for easy debugging of redux state. Watch this 1 min video tutorial on how to set it up.
If you happen to use VS Code, install the recommended extensions to get automatic formatting and linting on save, they are listed in .vscode/extensions.json
and VS Code will prompt you to install them.
- Fork the Dexter repository to your github account.
- Clone from your forked repo.
- Make a new branch with a feature name (you can see some examples in closed PRs).
- Make some changes.
- Commit and push local branch changes to your own repo.
- Make a pull request into the original Dexter repo.
Environment variables are set up in .env.testnet
and .env.mainnet
files. If you need to add new variables do NOT use fallbacks in the code (like process.env.REACT_APP_MY_VAR || 'default'
)
anywhere other than in next.config.js
,
so that the app will crash and you will be reminded to set it correctly for both environments early.
Refer to package.json to see what env files are used with which command.
If you have an .env
file it will take precedence over the .env.testnet
and .env.mainnet
files.
Do not run build command without ENV_FILE variable set beforehand, (it's not already set in package.json for deployment purposes).
Follow these steps to configure your wallet for testnet use, enabling developer mode, switching networks, and acquiring test tokens.
Enable Developer Mode
- Access Settings: Navigate to
App settings
from the main menu. - Activate Developer Mode: Within
App settings
, locate and toggle on theDeveloper Mode
option.
Switch to Testnet
- Open Gateways: Within
App settings
, proceed toGateways
. - Select Testnet: From the list of gateways, choose
babylon-stokenet-...
option.
Your wallet is now in developer mode and connected to the testnet.
Acquire Test XRD Tokens
- Follow the standard procedure to
Create a wallet
and set up aPersona
within the app. - Access Test Account: Open your test account profile.
- Navigate to Dev Preferences: Tap the three dots in the top right corner to access more options, then select
Dev preferences
. - Get Test Tokens: Click on
Get XRD Test Tokens
to receive your test currency.
By following these steps, you'll have your wallet set up for testing Dexter on localhost and creating orders using test XRD tokens.
To ensure our application supports multiple languages, all text displayed must be translated. We currently support English (en) and Portuguese (pt). Translations are stored in JSON files at /src/app/states/locales/{{lng}}/{{namespace}}
.json, where lng
is the language code and namespace
is a specific category of content. This structure facilitates potential future integration with server-side internationalization. Upon initial page load, content in all languages is preloaded and instantly available.
To use a translation in a React component:
import React from "react";
import { useTranslations } from "hooks";
const MyComponent = () => {
const t = useTranslations();
return <div>{t("some_key")}</div>;
};
Extend the JSON files with new key-value pairs to add translations. Ensure to add keys for every supported language to avoid displaying the key as fallback text.
For new subpages, create a corresponding namespace. Search for "INSTRUCTIONS_add_namespace" in the codebase and follow the outlined steps. After setup, utilize your namespace as mentioned above.
- Keys in JSON files:
- Use the full text in lowercase, replacing spaces with underscores, e.g., "trade_now".
- Enums or errors should be in uppercase.
- Values should:
- Use title capitalization, capitalizing all main words except for short filler words, e.g., "Trade Now", "History of Transactions".
Placeholders allow the dynamic insertion of content into sentences, accommodating language-specific syntax. For example, "market buy XRD" in English may translate to "comprar XRD a mercado" in Portuguese. To handle this, we use placeholders like <$IDENTIFIER>, for variable content such as token symbols. The translation files define the sentence structure for each language, e.g.:
- en: "market buy <$TOKEN_SYMBOL>"
- pt: "comprar <$TOKEN_SYMBOL> a mercado"
Developers are responsible for replacing placeholders with actual values within the code.
Whenever you need toast notifications, please use our DexterToast
API, which wraps react-hot-toast
and applies Dexter branding to all generated toasts.
Use Toast notifications for:
- ✅ Low attention messages that do not require user action
- ✅ Singular status updates
- ✅ Confirmations
- ✅ Information that does not need to be followed up
Do not use Toast notifications for:
- ❌ High attention and crtitical information
- ❌ Time-sensitive information
- ❌ Requires user action or input
- ❌ Batch updates
There are 3 functions exposed:
DexterToast.success(...)
DexterToast.error(...)
DexterToast.promise(...)
See usage examples:
// Import DexterToast class anywhere in the code
import { DexterToast } from "components/DexterToaster";
// Create success toast
DexterToast.success("Success!");
// Create error toast
DexterToast.error("Oops, something went wrong!");
// Create loading toast that initially has a loading state
// and resolves to either a success or error toast
DexterToast.promise(
() => dispatch(fetchBalances()), // function call, must return a promise
"Fetching balances", // loading text
"Balances fetched", // success text
"Failed to fetch balances" // error text
);
Further reading:
- Toast notifications — how to make it efficient
- When should we “TOAST” use the most? — fix UX.
- Toast notifications Guide
- A UX designer’s guide to implementing toast notifications
The space on top of the trading page can be used to display promo banners, for example:
To add a new banner, follow these steps:
- Each banner needs to be created in 2 versions: dektop (600x80) and mobile (600x200).
- The background for all banners is always a linear gradient from green -> blue (see example for desktop or mobile) and will be painted by the website.
- If you are the designer creating the banner, the content needs to be delivered as an SVG with a transparent background (see examples for desktop or mobile). Furthermore, ensure there is only a single call to action (CTA). Avoid having multiple competing actions like "STAKE NOW" and "learn more". Decide which one is more important and design the banner accordingly :D
- Upload both files to
/public/promo-banners/
. - Fill out
imageUrl
,imageUrlMobile
and optionallyredirecturl
insidesrc/app/layout.tsx
.
Problem
State variables get cached, leading to unpredictable initial renders of components (e.g., initialization based on cookies). This violates React/NextJS patterns and triggers hydration errors.
Handling Hydration Errors
- No Error: If no hydration error occurs, no action is needed.
- Error Detected: Identify the component causing the error.
- Fixing the Component: Add the following code to the problematic component:
import { useHydrationErrorFix } from "hooks";
function ComponentWithHydrationError() {
const isClient = useHydrationErrorFix();
// Additional code like useEffect or other hooks go here!
// ...
if (!isClient) return <></>;
return (
/* Your component JSX */
);
}
Common Causes of Hydration Errors
- Radix Connect Button: Caches logged-in users. Components relying on login status will render differently based on the user's login state.
- Language Detection: Cached in cookies. Components will render differently for users from various regions based on their browser-detected language.