Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to hide swap widgets #1374

Merged
merged 10 commits into from
Apr 2, 2024
1 change: 0 additions & 1 deletion src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ export default class App extends Mixins(mixins.TransactionMixin, NodeErrorMixin)
@state.router.loading pageLoading!: boolean;

@getter.settings.nodeIsConnected nodeIsConnected!: boolean;
@getter.settings.chartsEnabled private chartsEnabled!: boolean;
@getter.wallet.transactions.firstReadyTx firstReadyTransaction!: Nullable<HistoryItem>;
@getter.wallet.account.isLoggedIn isSoraAccountConnected!: boolean;
@getter.libraryTheme libraryTheme!: Theme;
Expand Down
17 changes: 0 additions & 17 deletions src/components/pages/Swap/Widget/Form.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,6 @@
<s-button class="el-button--settings" type="action" icon="basic-settings-24" @click="openSettingsDialog" />
</template>
</swap-status-action-badge>

<svg-icon-button
v-if="chartsFlagEnabled"
icon="line-icon"
size="medium"
:tooltip="t('dexSettings.сhartsDescription')"
:active="chartsEnabled"
@click="toggleChart"
/>
</template>

<div class="swap-form">
Expand Down Expand Up @@ -184,7 +175,6 @@ import type { Subscription } from 'rxjs';
SelectToken: lazyComponent(Components.SelectToken),
TokenInput: lazyComponent(Components.TokenInput),
ValueStatusWrapper: lazyComponent(Components.ValueStatusWrapper),
SvgIconButton: lazyComponent(Components.SvgIconButton),
FormattedAmount: components.FormattedAmount,
},
})
Expand All @@ -204,15 +194,12 @@ export default class SwapFormWidget extends Mixins(

@getter.assets.xor private xor!: AccountAsset;
@getter.swap.swapLiquiditySource liquiditySource!: Nullable<LiquiditySourceTypes>;
@getter.settings.chartsFlagEnabled chartsFlagEnabled!: boolean;
@getter.settings.nodeIsConnected nodeIsConnected!: boolean;
@getter.settings.chartsEnabled chartsEnabled!: boolean;
@getter.wallet.account.isLoggedIn isLoggedIn!: boolean;
@getter.swap.tokenFrom tokenFrom!: Nullable<AccountAsset>;
@getter.swap.tokenTo tokenTo!: Nullable<AccountAsset>;
@getter.swap.swapMarketAlgorithm swapMarketAlgorithm!: MarketAlgorithms;

@mutation.settings.setChartsEnabled private setChartsEnabled!: (value: boolean) => void;
@mutation.swap.setFromValue private setFromValue!: (value: string) => void;
@mutation.swap.setToValue private setToValue!: (value: string) => void;
@mutation.swap.setAmountWithoutImpact private setAmountWithoutImpact!: (amount?: CodecString) => void;
Expand Down Expand Up @@ -561,10 +548,6 @@ export default class SwapFormWidget extends Mixins(
this.showSettings = true;
}

toggleChart(): void {
this.setChartsEnabled(!this.chartsEnabled);
}

private enableSwapSubscriptions(): void {
this.updateBalanceSubscriptions();
this.subscribeOnQuote();
Expand Down
94 changes: 94 additions & 0 deletions src/components/shared/Widget/Customise.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
<template>
<base-widget v-bind="$attrs" :title="t('customisePageText')">
<template #filters>
<el-popover popper-class="customise-widget-popper" trigger="click" v-model="visible" :visible-arrow="false">
<s-button slot="reference" type="action" alternative size="small" icon="basic-settings-24" />

<div class="customise">
<div class="customise-title">{{ t('customisePageText') }}</div>

<div v-for="(model, name) in { widgets, options }" :key="name" class="customise-options">
<s-divider />
<label v-for="(value, key) in model" :key="key" class="customise-option">
<s-switch :value="value" @input="toggle(name, model, key, $event)" />
<span>{{ getLabel(key, name) }}</span>
</label>
</div>

<slot />
</div>
</el-popover>
</template>
</base-widget>
</template>

<script lang="ts">
import { Component, Mixins, ModelSync, PropSync, Prop } from 'vue-property-decorator';

import TranslationMixin from '@/components/mixins/TranslationMixin';
import { Components, ObjectInit } from '@/consts';
import { lazyComponent } from '@/router';
import type { WidgetsVisibilityModel } from '@/types/layout';

@Component({
components: {
BaseWidget: lazyComponent(Components.BaseWidget),
},
})
export default class CustomiseWidget extends Mixins(TranslationMixin) {
@PropSync('widgetsModel', { default: ObjectInit, type: Object }) readonly widgets!: WidgetsVisibilityModel;
@PropSync('optionsModel', { default: ObjectInit, type: Object }) readonly options!: WidgetsVisibilityModel;
@Prop({ default: ObjectInit, type: Object }) readonly labels!: Record<string, string>;

@ModelSync('value', 'input', { type: Boolean }) visible!: boolean;

toggle(name: string, model: WidgetsVisibilityModel, key: string, value: boolean): void {
this[name] = { ...model, [key]: value };
}

getLabel(key: string, name: string): string {
if (key in this.labels) return this.labels[key];

return this.t(`${name}.${key}`);
}
}
</script>

<style lang="scss">
.customise-widget-popper.el-popover.el-popper {
@include popper-content;
}
</style>

<style lang="scss" scoped>
.customise-widget-icon {
@include icon-styles(true);
}

.customise {
display: flex;
flex-flow: column nowrap;
gap: $inner-spacing-medium;

@include vertical-divider('el-divider', 0);

&-title {
font-size: var(--s-font-size-small);
font-weight: 500;
}

&-options {
display: flex;
flex-flow: column nowrap;
gap: $inner-spacing-medium;
}

&-option {
cursor: pointer;
display: flex;
flex-flow: row nowrap;
gap: $inner-spacing-small;
text-transform: capitalize;
}
}
</style>
1 change: 1 addition & 0 deletions src/consts/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,7 @@ export enum Components {
BaseWidget = 'shared/Widget/Base',
IFrameWidget = 'shared/Widget/IFrame',
PriceChartWidget = 'shared/Widget/PriceChart',
CustomiseWidget = 'shared/Widget/Customise',
// Shared Buttons
SortButton = 'shared/Button/SortButton',
SvgIconButton = 'shared/Button/SvgIconButton/SvgIconButton',
Expand Down
4 changes: 3 additions & 1 deletion src/lang/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1558,5 +1558,7 @@
},
"pricePerToken": "Price per 1 {token}"
},
"calculatingText": "Calculating"
"calculatingText": "Calculating",
"customisePageText": "Customise page",
"priceChartText": "Price chart"
}
8 changes: 0 additions & 8 deletions src/store/settings/getters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,6 @@ const getters = defineGetters<SettingsState>()({
const { state, getters } = settingsGetterContext(args);
return !!getters.x1ApiKey && !!state.featureFlags.x1ex;
},
chartsFlagEnabled(...args): boolean {
const { state } = settingsGetterContext(args);
return !!state.featureFlags.charts;
},
chartsEnabled(...args): boolean {
const { state } = settingsGetterContext(args);
return !!state.featureFlags.charts && state.chartsEnabled;
},
soraCardEnabled(...args): Nullable<boolean> {
const { state } = settingsGetterContext(args);
return state.featureFlags.soraCard;
Expand Down
4 changes: 0 additions & 4 deletions src/store/settings/mutations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ const mutations = defineMutations<SettingsState>()({
state.marketAlgorithm = value;
storage.set('marketAlgorithm', value);
},
setChartsEnabled(state, value: boolean): void {
state.chartsEnabled = value;
storage.set('сhartsEnabled', value); // TODO: replace Cyrillic character
},
setTransactionDeadline(state, value: number): void {
state.transactionDeadline = value;
storage.set('transactionDeadline', value);
Expand Down
2 changes: 0 additions & 2 deletions src/store/settings/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import type { SettingsState } from './types';

function initialState(): SettingsState {
const disclaimerApprove = settingsStorage.get('disclaimerApprove');
const chartsEnabled = storage.get('сhartsEnabled');
const isBrowserNotificationApiAvailable = 'Notification' in window;
const appConnection = new NodesConnection(settingsStorage, connection);

Expand All @@ -18,7 +17,6 @@ function initialState(): SettingsState {
featureFlags: {},
slippageTolerance: storage.get('slippageTolerance') || DefaultSlippageTolerance,
marketAlgorithm: (storage.get('marketAlgorithm') || DefaultMarketAlgorithm) as MarketAlgorithms,
chartsEnabled: chartsEnabled ? Boolean(JSON.parse(chartsEnabled)) : true,
userDisclaimerApprove: disclaimerApprove ? JSON.parse(disclaimerApprove) : false,
transactionDeadline: Number(storage.get('transactionDeadline')) || 20,
isBrowserNotificationApiAvailable,
Expand Down
1 change: 0 additions & 1 deletion src/store/settings/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ export type SettingsState = {
featureFlags: FeatureFlags;
slippageTolerance: string;
marketAlgorithm: MarketAlgorithms;
chartsEnabled: boolean;
userDisclaimerApprove: boolean;
transactionDeadline: number;
language: string;
Expand Down
4 changes: 4 additions & 0 deletions src/utils/storage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { Storage } from '@sora-substrate/util';
import { storage as soraStorage } from '@soramitsu/soraneo-wallet-web';

export { settingsStorage } from '@soramitsu/soraneo-wallet-web';

export default soraStorage;

export const layoutsStorage = new Storage('layouts');
49 changes: 45 additions & 4 deletions src/views/Swap.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
<div class="swap-container">
<div class="column column--small">
<swap-form-widget :parent-loading="loadingState" class="swap-form-widget" />
<swap-distribution-widget />
<customise-widget :widgets-model.sync="widgetsSync" :labels="labels" />
<swap-distribution-widget v-if="widgets[SwapWidgets.Distribution]" />
</div>
<div class="column">
<swap-chart-widget :parent-loading="loadingState" v-if="chartsEnabled" class="swap-chart-widget" />
<swap-transactions-widget :parent-loading="loadingState" />
<swap-chart-widget v-if="widgets[SwapWidgets.Chart]" :parent-loading="loadingState" class="swap-chart-widget" />
<swap-transactions-widget v-if="widgets[SwapWidgets.Transactions]" :parent-loading="loadingState" />
</div>
</div>
</template>
Expand All @@ -21,28 +22,62 @@ import TranslationMixin from '@/components/mixins/TranslationMixin';
import { Components, PageNames } from '@/consts';
import { lazyComponent } from '@/router';
import { action, getter, state } from '@/store/decorators';
import { layoutsStorage } from '@/utils/storage';

import type { AccountAsset } from '@sora-substrate/util/build/assets/types';

enum SwapWidgets {
Chart = 'swapChart',
Transactions = 'swapTransactions',
Distribution = 'swapDistribution',
}

const storageTemporaryKey = 'swapWidgets';

@Component({
components: {
SwapFormWidget: lazyComponent(Components.SwapFormWidget),
SwapChartWidget: lazyComponent(Components.SwapChartWidget),
SwapTransactionsWidget: lazyComponent(Components.SwapTransactionsWidget),
SwapDistributionWidget: lazyComponent(Components.SwapDistributionWidget),
CustomiseWidget: lazyComponent(Components.CustomiseWidget),
},
})
export default class Swap extends Mixins(mixins.LoadingMixin, TranslationMixin, SelectedTokenRouteMixin) {
@state.swap.isAvailable isAvailable!: boolean;
@state.router.prev private prevRoute!: Nullable<PageNames>;

@getter.settings.chartsEnabled chartsEnabled!: boolean;
@getter.swap.tokenFrom tokenFrom!: Nullable<AccountAsset>;
@getter.swap.tokenTo tokenTo!: Nullable<AccountAsset>;

@action.swap.setTokenFromAddress private setTokenFromAddress!: (address?: string) => Promise<void>;
@action.swap.setTokenToAddress private setTokenToAddress!: (address?: string) => Promise<void>;

readonly SwapWidgets = SwapWidgets;

widgets: Record<string, boolean> = {
[SwapWidgets.Chart]: true,
[SwapWidgets.Distribution]: true,
[SwapWidgets.Transactions]: false,
};

get widgetsSync() {
return this.widgets;
}

set widgetsSync(widgetsModel) {
this.widgets = widgetsModel;
layoutsStorage.set(storageTemporaryKey, JSON.stringify(widgetsModel));
}

get labels(): Record<string, string> {
return {
[SwapWidgets.Chart]: this.t('priceChartText'),
[SwapWidgets.Distribution]: this.t('swap.route'),
[SwapWidgets.Transactions]: this.tc('transactionText', 2),
};
}

@Watch('tokenFrom')
@Watch('tokenTo')
private updateRouteTokensParams() {
Expand All @@ -54,6 +89,12 @@ export default class Swap extends Mixins(mixins.LoadingMixin, TranslationMixin,
}

created(): void {
const widgetsModel = layoutsStorage.get(storageTemporaryKey);

if (widgetsModel) {
this.widgets = JSON.parse(widgetsModel);
}

this.withApi(async () => {
this.parseCurrentRoute();
// Need to wait the previous page beforeDestroy somehow to set the route params
Expand Down