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

Feat/new update UI #595

Merged
merged 11 commits into from
Jan 14, 2025
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions packages/extension/src/libs/metrics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import {
SendEventType,
SettingEventType,
SwapEventType,
UpdatesEventType,
UpdatesOpenLocation
} from './types';

const metrics = new Metrics();
Expand Down Expand Up @@ -75,6 +77,14 @@ const trackDAppsEvents = (
metrics.track('dapps', { event, ...options });
};

const trackUpdatesEvents = (event: UpdatesEventType, options: {
network: NetworkNames;
location?: UpdatesOpenLocation;
duration?: number;
}) => {
metrics.track('updatesClick', { event, ...options });

}
const optOutofMetrics = (optOut: boolean) => {
if (!__IS_FIREFOX__) {
metrics.setOptOut(false);
Expand All @@ -95,4 +105,5 @@ export {
trackDAppsEvents,
optOutofMetrics,
trackGenericEvents,
trackUpdatesEvents
};
10 changes: 10 additions & 0 deletions packages/extension/src/libs/metrics/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,13 @@ export enum DAppsEventType {
export enum SettingEventType {
OptOut = 'opt_out',
}

export enum UpdatesEventType {
UpdatesOpen = 'updates_open',
UpdatesClosed = 'updates_closed',
}

export enum UpdatesOpenLocation {
settings = 'settings',
logo = "logo",
}
62 changes: 62 additions & 0 deletions packages/extension/src/libs/updates-state/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import BrowserStorage from '../common/browser-storage';
import { InternalStorageNamespace } from '@/types/provider';
import { IState, StorageKeys } from './types';

class UpdatesState {
private storage: BrowserStorage;

constructor() {
this.storage = new BrowserStorage(InternalStorageNamespace.updatesState);
}

async setState(state: IState): Promise<void> {
return this.storage.set(StorageKeys.updatesInfo, state);
}

async getState(): Promise<IState> {
olgakup marked this conversation as resolved.
Show resolved Hide resolved
return this.storage.get(StorageKeys.updatesInfo);
}

async getLastVersionViewed(): Promise<IState['lastVersionViewed']> {
const state: IState | undefined = await this.getState();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const state: IState | null = await this.getState();

if (state && state.lastVersionViewed) {
return state.lastVersionViewed;
}
return '';
}
async setLastVersionViewed(lastVersionViewed: string): Promise<void> {
const state: IState | undefined = await this.getState();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const state: IState | null = await this.getState();

const newState: IState = { ...state, lastVersionViewed }
await this.setState(newState);
}

async getCurrentRelease(): Promise<IState['currentRelease']> {
const state: IState | undefined = await this.getState();
olgakup marked this conversation as resolved.
Show resolved Hide resolved
if (state && state.currentRelease) {
return state.currentRelease;
}
return ''
}

async setCurrentRelease(currentRelease: string): Promise<void> {
const state: IState | undefined = await this.getState();
olgakup marked this conversation as resolved.
Show resolved Hide resolved
const newState: IState = { ...state, currentRelease }
await this.setState(newState);
}

async getCurrentReleaseTimestamp(): Promise<IState['currentReleaseTimestamp']> {
const state: IState | undefined = await this.getState();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const state: IState | null = await this.getState();

if (state && state.currentReleaseTimestamp) {
return state.currentReleaseTimestamp;
}
return 0
}

async setCurrentReleaseTimestamp(currentReleaseTimestamp: number): Promise<void> {
const state: IState | undefined = await this.getState();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const state: IState | null = await this.getState();

const newState: IState = { ...state, currentReleaseTimestamp }
await this.setState(newState);
}
}

export default UpdatesState;
9 changes: 9 additions & 0 deletions packages/extension/src/libs/updates-state/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export enum StorageKeys {
updatesInfo = 'updates-info',
}

export interface IState {
lastVersionViewed: string;
currentRelease: string;
currentReleaseTimestamp: number;
}
1 change: 1 addition & 0 deletions packages/extension/src/types/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ export enum InternalStorageNamespace {
customNetworksState = 'CustomNetworksState',
rateState = 'RateState',
recentlySentAddresses = 'RecentlySentAddresses',
updatesState = 'UpdatesState',
}
export enum EnkryptProviderEventMethods {
persistentEvents = 'PersistentEvents',
Expand Down
139 changes: 136 additions & 3 deletions packages/extension/src/ui/action/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@
<div v-show="!isLoading" ref="appMenuRef" class="app__menu">
<!-- LOGO & TOP MENU -->
<div class="app__menu-row" :class="{ border: networks.length > 9 }">
<logo-min class="app__menu-logo" />
<div class="app__menu-row">
<logo-min class="app__menu-logo" />
<updated-icon
v-if="loadedUpdates && showUpdatesBtn"
@click="openUpdatesDialog(UpdatesOpenLocation.logo)"
class="app__menu-updated"
/>
</div>
<div>
<a ref="toggle" class="app__menu-link" @click="toggleMoreMenu">
<more-icon />
Expand All @@ -21,6 +28,15 @@
<a class="app__menu-dropdown-link" @click="settingsAction">
<settings-icon /> <span>Settings</span>
</a>
<div v-if="loadedUpdates" class="app__menu-dropdown-divider"></div>
<a
v-if="loadedUpdates"
class="app__menu-dropdown-link"
@click="openUpdatesDialog(UpdatesOpenLocation.settings)"
>
<heart-icon class="app__menu-dropdown-link-heart"></heart-icon>
<span> Updates</span>
</a>
</div>
</div>
</div>
Expand Down Expand Up @@ -97,6 +113,13 @@
:latest-version="latestVersion"
@close:popup="updateShow = !updateShow"
/>
<modal-updates
v-if="loadedUpdates && showUpdatesDialog"
:versions="releases?.versions"
:current-version="currentVersion"
:current-network="currentNetwork.name"
@close:popup="closeUpdatesDialog"
/>
</div>
</template>

Expand Down Expand Up @@ -143,21 +166,37 @@ import { AccountsHeaderData } from './types/account';
import AddNetwork from './views/add-network/index.vue';
import ModalRate from './views/modal-rate/index.vue';
import Settings from './views/settings/index.vue';
import ModalUpdates from './views/updates/index.vue';
import { KadenaNetwork } from '@/providers/kadena/types/kadena-network';
import { EnkryptProviderEventMethods, ProviderName } from '@/types/provider';
import { onClickOutside } from '@vueuse/core';
import RateState from '@/libs/rate-state';
import SwapLookingAnimation from '@action/icons/swap/swap-looking-animation.vue';
import { trackBuyEvents, trackNetworkSelected } from '@/libs/metrics';
import {
trackBuyEvents,
trackNetworkSelected,
trackUpdatesEvents,
} from '@/libs/metrics';
import { getLatestEnkryptVersion } from '@action/utils/browser';
import { gt as semverGT } from 'semver';
import { BuyEventType, NetworkChangeEvents } from '@/libs/metrics/types';
import {
BuyEventType,
NetworkChangeEvents,
UpdatesEventType,
UpdatesOpenLocation,
} from '@/libs/metrics/types';
import { NetworksCategory } from '@action/types/network-category';
import { newNetworks } from '@/providers/common/libs/new-features';
import UpdatesState from '@/libs/updates-state';
import UpdatedIcon from '@/ui/action/icons/updates/updated.vue';
import HeartIcon from '@/ui/action/icons/updates/heart.vue';
import { getLatestEnkryptUpdates } from '@action/utils/browser';
import { Updates } from '@/ui/action/types/updates';

const domainState = new DomainState();
const networksState = new NetworksState();
const rateState = new RateState();
const updatesState = new UpdatesState();
const appMenuRef = ref(null);
const showDepositWindow = ref(false);
const accountHeaderData = ref<AccountsHeaderData>({
Expand Down Expand Up @@ -191,7 +230,64 @@ const isLoading = ref(true);
const currentVersion = __PACKAGE_VERSION__;
const latestVersion = ref('');
const enabledTestnetworks = ref<string[]>([]);
/** -------------------
* Updates
-------------------*/
const releases = ref<Updates | undefined>(undefined);
const loadedUpdates = ref<boolean>(false);
const showUpdatesBtn = ref<boolean>(false);
const showUpdatesDialog = ref<boolean>(false);
const stateCurrentReleaseTimestamp = ref<number>(0);

const initUpdateState = async () => {
const currentReleaseInState = await updatesState.getCurrentRelease();
stateCurrentReleaseTimestamp.value =
await updatesState.getCurrentReleaseTimestamp();
if (currentReleaseInState !== currentVersion) {
await updatesState.setCurrentRelease(currentVersion);
const newReleaseTimestamp = Date.now();
await updatesState.setCurrentReleaseTimestamp(newReleaseTimestamp);
stateCurrentReleaseTimestamp.value = newReleaseTimestamp;
}
};

const getShowUpdatesBtn = async () => {
try {
const lastVersionViewed = await updatesState.getLastVersionViewed();
if (
lastVersionViewed === '' ||
(currentVersion && semverGT(currentVersion, lastVersionViewed))
) {
const expireTimestamp = stateCurrentReleaseTimestamp.value + 12096e5; //2 weeks;
showUpdatesBtn.value =
stateCurrentReleaseTimestamp.value < expireTimestamp;
} else {
showUpdatesBtn.value = false;
}
} catch (error) {
console.error('Failed to get show updates button:', error);
}
};
const openUpdatesDialog = (_location: UpdatesOpenLocation) => {
showUpdatesDialog.value = true;
updatesState.setLastVersionViewed(currentVersion);
showUpdatesBtn.value = false;
if (isOpenMore.value) {
closeMoreMenu();
}
trackUpdatesEvents(UpdatesEventType.UpdatesOpen, {
network: currentNetwork.value.name,
location: _location,
});
};

const closeUpdatesDialog = () => {
showUpdatesDialog.value = false;
};

/** -------------------
* Core
-------------------*/
const setActiveNetworks = async () => {
const pinnedNetworkNames = await networksState.getPinnedNetworkNames();
const allNetworks = await getAllNetworks();
Expand Down Expand Up @@ -246,6 +342,7 @@ const isKeyRingLocked = async (): Promise<boolean> => {
tabId: await domainState.getCurrentTabId(),
}).then(res => JSON.parse(res.result || 'true'));
};

const init = async () => {
const curNetwork = await domainState.getSelectedNetWork();
if (curNetwork) {
Expand All @@ -258,6 +355,7 @@ const init = async () => {
await setActiveNetworks();
isLoading.value = false;
};

onMounted(async () => {
const isInitialized = await kr.isInitialized();
if (isInitialized) {
Expand All @@ -268,6 +366,18 @@ onMounted(async () => {
.then(() => (isLoading.value = false));
} else {
init();
try {
await initUpdateState();
releases.value = await getLatestEnkryptUpdates();
if (releases.value) {
await getShowUpdatesBtn();
}
loadedUpdates.value = true;
} catch (error) {
console.error('Failed to get latest enkrypt updates:', error);
loadedUpdates.value = false;
}
olgakup marked this conversation as resolved.
Show resolved Hide resolved

setTimeout(() => {
rateState.showPopup().then(show => {
if (show) {
Expand Down Expand Up @@ -621,6 +731,16 @@ body {
&-logo {
margin-left: 8px;
}
&-updated {
height: 24px;
width: 90px;
cursor: pointer;
transition: 0.3s;
filter: brightness(1);
&:hover {
filter: brightness(0.9);
}
}

&-row {
height: 40px;
Expand Down Expand Up @@ -689,6 +809,13 @@ body {
top: 48px;
z-index: 3;

&-divider {
height: 1px;
width: 90%;
margin: 8px;
background: @gray02;
}

&-link {
width: 100%;
height: 48px;
Expand All @@ -700,6 +827,12 @@ body {
transition: background 300ms ease-in-out;
border-radius: 8px;

&-heart {
width: 18px !important;
height: 18px !important;
margin-right: 18px !important;
}

&:hover,
&.active {
background: rgba(0, 0, 0, 0.04);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,7 @@ const disconnectFromDapp = async () => {
height: 32px;
margin-right: 12px;
border-radius: 50%;
margin-top: 2px;
}
&__active-network {
position: absolute;
Expand Down
5 changes: 5 additions & 0 deletions packages/extension/src/ui/action/icons/updates/heart.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<template>
<svg width="12" height="12" viewBox="0 0 12 12" fill="black" xmlns="http://www.w3.org/2000/svg">
<path d="M5.81836 11.3789C5.75977 11.3789 5.68945 11.3613 5.60742 11.3262C5.5293 11.2949 5.45898 11.2598 5.39648 11.2207C4.29492 10.5176 3.33984 9.78125 2.53125 9.01172C1.72266 8.23828 1.09766 7.44531 0.65625 6.63281C0.21875 5.81641 0 4.99219 0 4.16016C0 3.64062 0.0820312 3.16602 0.246094 2.73633C0.414062 2.30273 0.646484 1.92773 0.943359 1.61133C1.24023 1.29492 1.58594 1.05078 1.98047 0.878906C2.375 0.707031 2.80273 0.621094 3.26367 0.621094C3.83789 0.621094 4.3418 0.767578 4.77539 1.06055C5.20898 1.35352 5.55664 1.74023 5.81836 2.2207C6.08398 1.73633 6.43359 1.34961 6.86719 1.06055C7.30078 0.767578 7.80273 0.621094 8.37305 0.621094C8.83398 0.621094 9.26172 0.707031 9.65625 0.878906C10.0547 1.05078 10.4004 1.29492 10.6934 1.61133C10.9902 1.92773 11.2207 2.30273 11.3848 2.73633C11.5527 3.16602 11.6367 3.64062 11.6367 4.16016C11.6367 4.99219 11.416 5.81641 10.9746 6.63281C10.5371 7.44531 9.91406 8.23828 9.10547 9.01172C8.30078 9.78125 7.34766 10.5176 6.24609 11.2207C6.18359 11.2598 6.11133 11.2949 6.0293 11.3262C5.95117 11.3613 5.88086 11.3789 5.81836 11.3789Z" fill="#202124"/>
</svg>
</template>
Loading
Loading