This repository contains source code for Email sign up Airdrop website.
Solution has 3 main parts. Admin dashboard, page for NFT claim and page for users to sign up for receiving an NFT. In admin dashboard, admin adds emails, see their status, statistic, ...
In the sign up page the end users can solve captcha and add their email address to reserve an NFT or get added to the waitlist. Users have a limited amount of time to claim their NFT or the next in line gets it.
Cron job runs in the background and sends claim email when time set for sending passes.
Users receives an email that redirects him to the claim page. On the claim page he connects the wallets and triggers the claiming process on the backend.
In lib/config/
we can find configs for different environments.
const config: ConfigInterface = {
APP_URL: 'http://localhost:3000',
API_BASE: 'http://localhost:3001',
CHAIN_ID: 1287,
CONTRACT_ADDRESS: null,
METADATA_BASE_URI: null,
METADATA_TOKEN: null,
};
You need to update this config for a smoother frontend experience.
APP_URL
presents the URL where the frontend website lives.API_BASE
presents the URL where backend (API) lives.CHAIN_ID
is the ID of the EVM chain that you NFTs are.CONTRACT_ADDRESS
is the onchain contract address of your NFT collection.METADATA_BASE_URI
presents the base uri where you NFTs metadata live (IPNS if created via apillon).METADATA_TOKEN
presents the JWT token of the NFTs metadata URI.
If METADATA_BASE_URI
and METADATA_TOKEN
are not present, the website still works normally but the users need to have their metamask connected to load a NFT after it was minted.
- node 18.16.1
- Nuxt 3
- Vue 3 w/ TypeScript
- Pinia Store
- NaiveUI
- TailwindCSS
Naive UI is used for default frontend components.
Its styles can be modified globally in /lib/config/naive.ts
- docs.
Each naive component also has the :theme-overrides
prop to overwrite styles per specific usage.
<n-tabs
type="segment"
size="small"
:theme-overrides="{ panePaddingSmall: '1.5rem 0 0 0' }"
></n-tabs>
API interaction should be done with api wrapper globally imported as $api
(/lib/utils/api.ts
).
API global interceptors (onRequest, onResponse, onForbidden) are also defined in /lib/utils/api.ts
.
Api requests throw errors, handle them with try catches. useHandleError(e)
can be used for general error handling (eg. toast display).
try {
await $api.post('/login', formData);
} catch (e: any) {
useHandleError(e);
}
Many common tasks can be solved with using helper functions from vueuse. Use those instead of reinventing the wheel.
eg.
useIntersectionObserver();
useInfiniteScroll();
useScroll();
useScrollLock();
Add icon svg to /assets/icons
, then use <NuxtIcon :name="" />
component to use the icon - set name prop to filename. Implements nuxt-icons.
Control size with font-size.
<NuxtIcon name="close" class="inline-block text-[18px] mr-3 align-middle" />
For basic styles, use tailwind breakpoint system. For js usage, use useScreen
composable.
const screens = reactive(useScreen());
// or
const { isXl } = useScreen();
<div v-if="screens.isXl" class="w-8 h-8 bg-red"></div>
<div v-else class="w-8 h-8 bg-blue"></div>
Implements naive-ui modal.
<Modal v-model:show="isModal" title="MY Modal">
<div>ETC</div>
</Modal>
Wallet integration can be implemented with use-wagmi and viem. Docs for wagmi: docs (react docs, but most hooks are supported).
Check for implementation on branch crypto
.
Configuration is in /plugins/use-wagmi.ts
.
Helpers are in /composables/blockchain/**
and /components/parts/Wallet/**
.
Use Nuxt i18n.
Check for implementation on branch i18n
. Basically:
- install module and add config to
nuxt.config.ts
- add translation json file:
/locales/en.json
- add language switch component
In template
In script
const { t } = useI18n();
const label = t('investments.details.location');
Internal links can be simple paths if using strategy: 'no_prefix'
. Otherwise localePath()
helper should be used.