Thank you for your interest in contributing to the AirSwap web app! We welcome contributions no matter their size.
While we use GitHub for issue tracking and project management, development is generally coordinated on the Discord server, which you should join to learn more about how and where to contribute.
- Craco (Create React App Configuration Override)
- AirSwap protocols
- ethers
- Redux
- Styled components
When multiple people are working on the same body of code, it is important that everyone conforms to a style. We use a linter for code style, which you can use with a simple command.
$ yarn lint
For code formatting we use prettier. This will be run after you commit your code but can also be run manually.
$ yarn prettier
We use styled-components for styling. When styling a component put your scss in a separate *.styles.tsx file in the src/component
folder. We also have a src/styled-components
folder purely for components only meant for styling.
We define dimensions using rem
based on 16px, so use units like 0.125rem
, 0.25rem
, etc.
The order of css properties should be based on matter of importance it has on the box-model. For instance these properties are sorted by their importance: display
, position
, margin
, border
, width
, padding
, line-height
, font-size
, z-index
, background
. This could be a little arbitrary so we're not very strict about this.
When making a new component please take a look at the current components to get an idea what style we are using. Here's an example of the interface of a simple component:
interface CheckboxProps {
hideLabel?: boolean;
label: string;
subLabel?: string;
onChange: (isChecked: boolean) => void;
className?: string;
}
For naming conventions please refer to this article of David Linau.
The order of properties are as following: first we have modifiers (ie: isActive
, hideLabel
), then other data properties (ie: items
, label
), then event handlers (ie: onClick
, onChange
) and finally the className?
which every components needs to have so it can be styled by it's parent.
We use redux toolkit for store management. Use createAsyncThunk for all asynchronous actions. Errors should be transformed to AppError
, processed in the action and saved in the store. An example:
const UsersComponent = () => {
const { user, isLoading, error } = useSelector((state) => state.users)
const dispatch = useDispatch()
const fetchUser = (userId) => {
dispatch(fetchUserById(userId));
}
// render UI here
}
const fetchUserById = createAsyncThunk (
'users/fetchByIdStatus',
async (userId: string, { dispatch }) => {
const user = await userAPI.fetchById(userId);
if (isAppError(user)) {
dispatch(setStatus("failed"));
dispatch(setError(user));
showToast('failed fetching user');
return;
}
dispatch(setStatus("success"));
dispatch(setUser(user))
showToast('success', `Fetched ${user.name}`)
}
);
New translations should be added manually to public/locales/en/translation.json
first. After your PR is merged an admin will add the new translations in POEditor. Everything in public/locales
will eventually be overwritten by POEditor. If you want to help with translating please let us know.
It’s a good idea to make PRs early on. A PR represents the start of a discussion, and doesn’t necessarily need to be the final, completed submission. Create a draft PR if you're looking for feedback but not ready for a final review. If the PR is in response to a GitHub issue, make sure to notate the issue as well.
Usually your PR is connected to a ticket number, so please put the ticket number (for example 101) in the description of your PR like so:
Fixes #101
GitHub’s documentation for working on PRs is available here.
Once your PR is ready, ensure all checks are passing and request a review.