Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
onmax committed Jan 23, 2025
1 parent 45c035f commit ea24d5f
Show file tree
Hide file tree
Showing 9 changed files with 991 additions and 36 deletions.
25 changes: 17 additions & 8 deletions src/components/layouts/Sidebar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,7 @@

<div class="trade-actions" v-if="!isLegacyAccount">
<Tooltip
v-if="(
$config.fastspot.enabled
&& fastspotEnabledCryptoSwapAssets.length
&& fastspotEnabledFiatSwapAssets.length
)
|| $config.moonpay.enabled
|| $config.simplex.enabled"
v-if="canBuy"
preferredPosition="top right"
:container="$parent"
theme="inverse"
Expand All @@ -63,8 +57,12 @@
}}</template>
</Tooltip>

<button v-if="isDemoEnabled" class="nq-button-s inverse"
@click="openModal('demo-sell', { direction: 'sell' })" @mousedown.prevent="hideTooltips">
{{ $t('Sell') }}
</button>
<Tooltip
v-if="/* (fastspotEnabledCryptoSwapAssets.length && fastspotEnabledFiatSwapAssets.length)
v-else-if="/* (fastspotEnabledCryptoSwapAssets.length && fastspotEnabledFiatSwapAssets.length)
|| */ $config.moonpay.enabled"
preferredPosition="top right"
:container="$parent"
Expand Down Expand Up @@ -203,6 +201,7 @@ import AttentionDot from '../AttentionDot.vue';
import { useAddressStore } from '../../stores/Address';
import { useBtcAddressStore } from '../../stores/BtcAddress';
import { usePolygonAddressStore } from '../../stores/PolygonAddress';
import { useDemoStore } from '../../stores/Demo';
import { useSettingsStore } from '../../stores/Settings';
import { useAccountStore, AccountType } from '../../stores/Account';
import { useAccountSettingsStore } from '../../stores/AccountSettings';
Expand Down Expand Up @@ -328,6 +327,14 @@ export default defineComponent({
: null;
});
const { isDemoEnabled } = useDemoStore();
const canBuy = computed(() => (
config.fastspot.enabled
&& fastspotEnabledCryptoSwapAssets.value.length && fastspotEnabledFiatSwapAssets.value.length)
|| config.moonpay.enabled || config.simplex.enabled || isDemoEnabled,
);
return {
CryptoCurrency,
navigateTo,
Expand All @@ -338,6 +345,8 @@ export default defineComponent({
priceChartTimeRange,
switchPriceChartTimeRange,
isLegacyAccount,
canBuy,
isDemoEnabled,
walletActivatedCurrencies,
fastspotEnabledFiatSwapAssets,
fastspotEnabledCryptoSwapAssets,
Expand Down
4 changes: 4 additions & 0 deletions src/components/modals/BuyOptionsModal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,7 @@
<script lang="ts">
import { computed, defineComponent, onMounted, ref } from '@vue/composition-api';
import { PageBody, FiatAmount, CircleSpinner } from '@nimiq/vue-components';
import { useDemoStore } from '@/stores/Demo';
import Modal from './Modal.vue';
import CountrySelector from '../CountrySelector.vue';
import CountryFlag from '../CountryFlag.vue';
Expand Down Expand Up @@ -234,13 +235,16 @@ export default defineComponent({
const country = ref<Country>(null);
const { isDemoEnabled } = useDemoStore();
const isMoonpayAvailable = computed(() => { // eslint-disable-line arrow-body-style
if (isDemoEnabled.value) return true;
if (!config.moonpay.enabled) return false;
if (!country.value) return true;
return MOONPAY_COUNTRY_CODES.includes(country.value.code);
});
const isSimplexAvailable = computed(() => { // eslint-disable-line arrow-body-style
if (isDemoEnabled.value) return true;
if (!config.simplex.enabled) return false;
if (!country.value) return true;
return SIMPLEX_COUNTRY_CODES.includes(country.value.code);
Expand Down
3 changes: 2 additions & 1 deletion src/components/modals/Modal.vue
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,8 @@ const Modal = defineComponent({
while (context.root.$route.matched.find((routeRecord) => 'modal' in routeRecord.components
|| 'persistent-modal' in routeRecord.components
|| Object.values(routeRecord.components).some((component) => /modal/i.test(component.name || '')))
|| Object.values(routeRecord.components).some((component) => /modal/i.test(
'name' in component ? component.name as string : '')))
) {
context.root.$router.back();
Expand Down
151 changes: 151 additions & 0 deletions src/components/modals/demos/DemoBuySell.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
<template>
<Modal :showOverlay="showOverlay">
<PageHeader class="flex-column">
<h1 class="nq-h1" v-if="direction === 'buy'">{{ $t('Buy NIM') }}</h1>
<h1 class="nq-h1" v-else>{{ $t('Sell NIM') }}</h1>
<div class="demo-warning nq-label">
{{ $t('DEMO') }}
</div>
</PageHeader>
<PageBody>
<div class="flex-row">

<AmountInput v-model="amount" :decimals="5">
<AmountMenu slot="suffix" class="ticker" currency="nim" :open="amountMenuOpened"
:activeCurrency="activeCurrency" :fiatCurrency="fiatCurrency" :feeOption="false"
:otherFiatCurrencies="otherFiatCurrencies"
@click.native.stop="amountMenuOpened = !amountMenuOpened" :sendAllOption="direction === 'sell'"
/>
</AmountInput>
</div>
</PageBody>
<PageFooter>
<button class="nq-button light-blue" @click="buyDummyNim" :disabled="!amount">
<template v-if="direction === 'buy'">{{ $t('Buy NIM') }}</template>
<template v-else>{{ $t('Sell NIM') }}</template>
</button>
</PageFooter>

<PageBody slot="overlay" class="overlay-content">
<HighFiveIcon />
<h2 class="nq-h2">
<template v-if="direction === 'buy'">{{ $t('Your NIM is under its way!') }}</template>
<template v-else>{{ $t('Your NIM has been sold!') }}</template>
</h2>
<p>
{{ $t('This transaction is instant and secure.') }}
</p>
</PageBody>
</Modal>
</template>

<script lang="ts">
import { computed, defineComponent, ref } from '@vue/composition-api';
import { PageBody, PageHeader, PageFooter } from '@nimiq/vue-components';
import AmountInput from '@/components/AmountInput.vue';
import AmountMenu from '@/components/AmountMenu.vue';
import Modal from '@/components/modals/Modal.vue';
import { useAccountStore } from '@/stores/Account';
import { useFiatStore } from '@/stores/Fiat';
import { FIAT_CURRENCIES_OFFERED } from '@/lib/Constants';
// import { useTransactionsStore } from '@/stores/Transactions';
import { useDemoStore } from '@/stores/Demo';
import { useRouter } from '@/router';
import HighFiveIcon from '@/components/icons/HighFiveIcon.vue';
import { useAddressStore } from '@/stores/Address';
export default defineComponent({
props: {
direction: String,
},
setup() {
const { activeCurrency } = useAccountStore();
const { currency: fiatCurrency } = useFiatStore();
const { activeAddressInfo } = useAddressStore();
const otherFiatCurrencies = computed(() =>
FIAT_CURRENCIES_OFFERED.filter((fiat) => fiat !== fiatCurrency.value));
const amount = ref(0);
const amountMenuOpened = ref(false);
const showOverlay = ref(false);
const router = useRouter();
const maxSendableAmount = computed(() => Math.max((activeAddressInfo.value!.balance || 0), 0));
const sendMax = () => amount.value = maxSendableAmount.value;
function buyDummyNim() {
useDemoStore().buyDemoNim(amount.value);
showOverlay.value = true;
setTimeout(() => {
showOverlay.value = false;
router.push('/');
}, 4000);
}
return {
amount,
activeCurrency,
fiatCurrency,
otherFiatCurrencies,
amountMenuOpened,
buyDummyNim,
showOverlay,
sendMax,
};
},
components: {
Modal,
AmountInput,
AmountMenu,
PageHeader,
PageBody,
PageFooter,
HighFiveIcon,
},
});
</script>

<style scoped lang="scss">
.small-page {
> .page-header {
overflow: hidden;
.demo-warning {
margin: 0;
text-align: center;
position: absolute;
top: 0;
left: 0;
right: 0;
background: var(--nimiq-orange-bg);
color: white;
padding: 0.5rem 0;
}
}
}
::v-deep .nq-card.overlay {
background: var(--nimiq-green);
color: white;
.overlay-content {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
svg {
width: 128px;
height: 128px;
}
p {
margin-top: 0;
text-wrap: pretty;
}
}
.close-button {
display: none;
}
}
</style>
35 changes: 35 additions & 0 deletions src/components/modals/demos/DemoHubMock.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<template>
<Modal>
<PageHeader class="flex-column">
<h1 class="nq-h1">{{ $t('Nimiq Demo') }}</h1>
</PageHeader>
<PageBody>
<p class="nq-p">
{{ $t('This is not a real Nimiq Wallet. It is just a demo so it is limited in functionality.') }}
</p>
<p>
{{ $t('You can open a free NIM account in less than a minute.') }}
</p>
</PageBody>
<PageFooter>
<a href="https://wallet.nimiq.com" target="_blank" class="nq-button light-blue">
{{ $t('Open Nimiq Wallet') }}
</a>
</PageFooter>
</Modal>
</template>

<script lang="ts">
import { defineComponent } from '@vue/composition-api';
import { PageBody, PageHeader, PageFooter } from '@nimiq/vue-components';
import Modal from '../Modal.vue';
export default defineComponent({
components: {
Modal,
PageHeader,
PageBody,
PageFooter,
},
});
</script>
4 changes: 2 additions & 2 deletions src/hub.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import { WELCOME_MODAL_LOCALSTORAGE_KEY, WELCOME_STAKING_MODAL_LOCALSTORAGE_KEY
import { usePwaInstallPrompt } from './composables/usePwaInstallPrompt';
import type { SetupSwapWithKycResult, SWAP_KYC_HANDLER_STORAGE_KEY } from './swap-kyc-handler'; // avoid bundling
import type { RelayServerInfo } from './lib/usdc/OpenGSN';
import { HubApiMock, isPlaygroundEnabled } from './stores/Playground';
import { DemoHubApi, checkIfDemoIsActive } from './stores/Demo';

export function shouldUseRedirects(ignoreSettings = false): boolean {
if (!ignoreSettings) {
Expand Down Expand Up @@ -115,7 +115,7 @@ function getBehavior({

// We can't use the reactive config via useConfig() here because that one can only be used after the composition-api
// plugin has been registered in Vue 2.
const hubApi = new HubApi(Config.hubEndpoint);
const hubApi = checkIfDemoIsActive() ? DemoHubApi.create() : new HubApi(Config.hubEndpoint);

hubApi.on(HubApi.RequestType.ONBOARD, async (accounts) => {
const { config } = useConfig();
Expand Down
62 changes: 38 additions & 24 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { launchElectrum } from './electrum';
import { launchPolygon } from './ethers';
import { useAccountStore } from './stores/Account';
import { useFiatStore } from './stores/Fiat';
import { useDemoStore } from './stores/Demo';
import { useSettingsStore } from './stores/Settings';
import router from './router';
import { i18n, loadLanguage } from './i18n/i18n-setup';
Expand Down Expand Up @@ -48,14 +49,21 @@ Vue.use(VuePortal, { name: 'Portal' });

async function start() {
initPwa(); // Must be called as soon as possible to catch early browser events related to PWA
await initStorage(); // Must be awaited before starting Vue
initTrials(); // Must be called after storage was initialized, can affect Config
// Must run after VueCompositionApi has been enabled and after storage was initialized. Could potentially run in
// background and in parallel to syncFromHub, but RedirectRpcClient.init does not actually run async code anyways.
await initHubApi();
syncFromHub(); // Can run parallel to Vue initialization; must be called after storage was initialized.

serviceWorkerHasUpdate.then((hasUpdate) => useSettingsStore().state.updateAvailable = hasUpdate);
const { isDemoEnabled } = useDemoStore();

if (!isDemoEnabled.value) {
await initStorage(); // Must be awaited before starting Vue
initTrials(); // Must be called after storage was initialized, can affect Config
// Must run after VueCompositionApi has been enabled and after storage was initialized. Could potentially run in
// background and in parallel to syncFromHub, but RedirectRpcClient.init does not actually run async code
// anyways.
await initHubApi();
syncFromHub(); // Can run parallel to Vue initialization; must be called after storage was initialized.

serviceWorkerHasUpdate.then((hasUpdate) => useSettingsStore().state.updateAvailable = hasUpdate);
} else {
useDemoStore().initialize(router);
}

// Update exchange rates every 2 minutes or every 10 minutes, depending on whether the Wallet is currently actively
// used. If an update takes longer than that time due to a provider's rate limit, wait until the update succeeds
Expand Down Expand Up @@ -94,28 +102,34 @@ async function start() {
const { language } = useSettingsStore();
loadLanguage(language.value);

startSentry();
if (!isDemoEnabled.value) {
startSentry();
}

const { config } = useConfig();

if (config.environment !== ENV_MAIN) {
if (isDemoEnabled.value) {
document.title = 'Nimiq Wallet Demo';
} else if (config.environment !== ENV_MAIN) {
document.title = 'Nimiq Testnet Wallet';
}

watch(() => {
if (!config.fastspot.apiEndpoint || !config.fastspot.apiKey) return;
initFastspotApi(config.fastspot.apiEndpoint, config.fastspot.apiKey);
});

watch(() => {
if (!config.oasis.apiEndpoint) return;
initOasisApi(config.oasis.apiEndpoint);
});

watch(() => {
if (!config.ten31Pass.enabled) return;
initKycConnection();
});
if (!isDemoEnabled.value) {
watch(() => {
if (!config.fastspot.apiEndpoint || !config.fastspot.apiKey) return;
initFastspotApi(config.fastspot.apiEndpoint, config.fastspot.apiKey);
});

watch(() => {
if (!config.oasis.apiEndpoint) return;
initOasisApi(config.oasis.apiEndpoint);
});

watch(() => {
if (!config.ten31Pass.enabled) return;
initKycConnection();
});
}

// Make reactive config accessible in components
Vue.prototype.$config = config;
Expand Down
Loading

0 comments on commit ea24d5f

Please sign in to comment.