diff --git a/public/card/sora-card-front.png b/public/card/sora-card-front.png new file mode 100644 index 000000000..6412ad2bc Binary files /dev/null and b/public/card/sora-card-front.png differ diff --git a/public/card/sora-card.png b/public/card/sora-card.png new file mode 100644 index 000000000..f3273daa3 Binary files /dev/null and b/public/card/sora-card.png differ diff --git a/src/assets/img/sora-card/sora-card-front.svg b/src/assets/img/sora-card/sora-card-front.svg deleted file mode 100644 index 0e6246db5..000000000 --- a/src/assets/img/sora-card/sora-card-front.svg +++ /dev/null @@ -1,68 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/assets/img/sora-card/sora-card.svg b/src/assets/img/sora-card/sora-card.svg deleted file mode 100644 index aa95d2d85..000000000 --- a/src/assets/img/sora-card/sora-card.svg +++ /dev/null @@ -1,512 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/components/SoraCard/ConfirmationInfo.vue b/src/components/SoraCard/ConfirmationInfo.vue new file mode 100644 index 000000000..d933b8e6e --- /dev/null +++ b/src/components/SoraCard/ConfirmationInfo.vue @@ -0,0 +1,152 @@ + + + + + diff --git a/src/components/SoraCard/Paywings/PaywingsDialog.vue b/src/components/SoraCard/Paywings/PaywingsDialog.vue new file mode 100644 index 000000000..3d3e31229 --- /dev/null +++ b/src/components/SoraCard/Paywings/PaywingsDialog.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/src/components/SoraCard/SoraCardIntroPage.vue b/src/components/SoraCard/SoraCardIntroPage.vue index 9c9339f6a..7231bd48d 100644 --- a/src/components/SoraCard/SoraCardIntroPage.vue +++ b/src/components/SoraCard/SoraCardIntroPage.vue @@ -1,27 +1,63 @@ @@ -29,39 +65,42 @@ import { Component, Mixins } from 'vue-property-decorator'; import { mixins } from '@soramitsu/soraneo-wallet-web'; import { FPNumber } from '@sora-substrate/math'; -import SoraCard from '@/assets/img/sora-card/sora-card.svg?inline'; + import { getter, state } from '@/store/decorators'; -import { PageNames } from '@/consts'; -import router from '@/router'; -import { delay, clearTokensFromSessionStorage } from '@/utils'; +import router, { lazyComponent } from '@/router'; +import { PageNames, Components } from '@/consts'; +import { delay } from '@/utils'; +import { clearTokensFromSessionStorage } from '@/utils/card'; import TranslationMixin from '../mixins/TranslationMixin'; @Component({ components: { - SoraCard, + X1Dialog: lazyComponent(Components.X1Dialog), + PaywingsDialog: lazyComponent(Components.PaywingsDialog), }, }) export default class SoraCardIntroPage extends Mixins(mixins.LoadingMixin, TranslationMixin) { @state.soraCard.euroBalance private euroBalance!: string; @state.soraCard.xorToDeposit private xorToDeposit!: FPNumber; - @getter.soraCard.isEuroBalanceEnough private isEuroBalanceEnough!: boolean; + + @getter.soraCard.isEuroBalanceEnough isEuroBalanceEnough!: boolean; @getter.wallet.account.isLoggedIn isLoggedIn!: boolean; isPriceCalculated = false; + showX1Dialog = false; + showPaywingsDialog = false; get buttonText(): string { if (!this.isLoggedIn) { return this.t('connectWalletText'); } - if (this.isEuroBalanceEnough) { - return 'APPLY FOR CARD'; - } - return `GET ${100 - parseInt(this.euroBalance, 10)}€ OF XOR TO QUALIFY`; + + return 'GET SORA CARD FOR FREE'; } - get balanceIndicatorText(): string { + get balanceIndicatorAmount(): string { const euroBalance = parseInt(this.euroBalance, 10); - return `${this.isEuroBalanceEnough ? '100' : euroBalance}€/100€ of XOR in your wallet`; + return `€${this.isEuroBalanceEnough ? '100' : euroBalance}/100`; } getIconClass(): string { @@ -71,27 +110,48 @@ export default class SoraCardIntroPage extends Mixins(mixins.LoadingMixin, Trans return ''; } + get btnLoading(): boolean { + return this.loading || !this.isPriceCalculated; + } + + openX1(): void { + this.showX1Dialog = true; + } + + bridgeTokens(): void { + if (!this.isEuroBalanceEnough) { + router.push({ name: PageNames.Bridge, params: { xorToDeposit: this.xorToDeposit.toString() } }); + } + } + + issueCardByPaywings(): void { + this.showPaywingsDialog = true; + } + handleConfirm(): void { if (!this.isLoggedIn) { router.push({ name: PageNames.Wallet }); return; } - if (!this.isEuroBalanceEnough) { - router.push({ name: PageNames.Bridge, params: { xorToDeposit: this.xorToDeposit.toString() } }); - } this.$emit('confirm-apply'); } + loginUser(): void { + clearTokensFromSessionStorage(); + const userApplied = true; + this.$emit('confirm-apply', userApplied); + } + async priceLoading(): Promise { this.isPriceCalculated = false; - await delay(800); + // TODO: write logic to do actual check for price calculations + await delay(700); // don't allow user do too preliminary click before its balance calculated this.isPriceCalculated = true; } mounted(): void { this.priceLoading(); - clearTokensFromSessionStorage(); } } @@ -103,6 +163,8 @@ $color: #ee2233; flex-direction: column; justify-content: center; align-items: center; + max-width: 520px; + margin-top: 30px; &__intro { display: flex; @@ -114,20 +176,32 @@ $color: #ee2233; width: 85%; text-align: center; font-weight: 600; + margin-top: var(--s-size-mini); + font-size: 28px; } &-info { - margin-top: 16px; + margin-top: $basic-spacing; + margin-bottom: 20px; font-weight: 300; - width: 80%; + line-height: 19px; + width: 90%; text-align: center; + padding-inline: 10px; } + } - &-name { - margin: 24px; - font-size: 18px; - font-weight: 600; - color: #fff; + &__options { + width: 100%; + } + + &__user-applied { + margin-top: 24px; + color: var(--s-color-base-content-secondary); + padding-bottom: calc(var(--s-basic-spacing) / 2); + border-bottom: 1px solid var(--s-color-base-content-secondary); + &:hover { + cursor: pointer; } } @@ -137,24 +211,60 @@ $color: #ee2233; } &__balance-indicator { - margin-top: 24px; + background-color: var(--s-color-base-border-primary); + padding: calc(var(--s-basic-spacing) / 2) var(--s-basic-spacing); + margin-top: var(--s-basic-spacing); + border-radius: calc(var(--s-basic-spacing) / 2); &-text { display: inline-block; - font-size: 16px; + font-size: var(--s-font-size-small); + &--bold { + font-weight: 600; + } } .s-icon-basic-check-mark-24 { - margin-right: 16px; + margin-right: var(--s-basic-spacing); color: var(--s-color-base-content-tertiary); } .sora-card__icon--checked { - color: $color; + color: var(--s-color-theme-accent); } } + + &__btn { + width: 100%; + &--fiat-buy, + &--bridge { + width: 48%; + .text { + font-size: var(--s-heading4-font-size); + } + } + &--fiat-issuance { + width: 100%; + } + } +} + +.line { + width: 100%; + display: flex; + margin-top: var(--s-basic-spacing); + margin-bottom: var(--s-basic-spacing); + flex-direction: row; + text-transform: uppercase; + color: var(--s-color-base-content-secondary); } -.el-button.is-loading { - background-color: unset !important; +.line::before, +.line::after { + content: ''; + flex: 1 1; + border-bottom: 2px solid var(--s-color-base-border-primary); + margin: auto; + margin-left: 10px; + margin-right: 10px; } diff --git a/src/components/SoraCard/SoraCardKYC.vue b/src/components/SoraCard/SoraCardKYC.vue index 43e6b4800..5d1e87c51 100644 --- a/src/components/SoraCard/SoraCardKYC.vue +++ b/src/components/SoraCard/SoraCardKYC.vue @@ -1,14 +1,13 @@ - - diff --git a/src/components/SoraCard/steps/KycView.vue b/src/components/SoraCard/steps/KycView.vue index 160294961..7384fcab3 100644 --- a/src/components/SoraCard/steps/KycView.vue +++ b/src/components/SoraCard/steps/KycView.vue @@ -1,7 +1,7 @@ @@ -64,9 +78,9 @@ export default class TermsAndConditions extends Mixins(TranslationMixin, mixins. width: 100%; background-color: var(--s-color-base-background); border-radius: var(--s-border-radius-small); - box-shadow: -5px -5px 10px #ffffff, 1px 1px 10px rgba(0, 0, 0, 0.1), inset 1px 1px 2px rgba(255, 255, 255, 0.8); - padding: 20px 16px; - margin-bottom: 16px; + box-shadow: var(--s-shadow-dialog); + padding: 20px $basic-spacing; + margin-bottom: $basic-spacing; position: relative; &-header { @@ -76,7 +90,7 @@ export default class TermsAndConditions extends Mixins(TranslationMixin, mixins. &-paragraph { color: var(--s-color-base-content-secondary); - margin-bottom: 8px; + margin-bottom: calc(var(--s-basic-spacing) / 2); } &-warning-icon { @@ -108,9 +122,9 @@ export default class TermsAndConditions extends Mixins(TranslationMixin, mixins. width: 100%; background-color: var(--s-color-base-background); border-radius: var(--s-border-radius-small); - box-shadow: -5px -5px 10px #ffffff, 1px 1px 10px rgba(0, 0, 0, 0.1), inset 1px 1px 2px rgba(255, 255, 255, 0.8); - padding: 20px 16px; - margin-bottom: 16px; + box-shadow: var(--s-shadow-dialog); + padding: 20px $basic-spacing; + margin-bottom: $basic-spacing; position: relative; &-block { @@ -141,33 +155,24 @@ export default class TermsAndConditions extends Mixins(TranslationMixin, mixins. &-header { font-weight: 500; margin-bottom: 10px; - padding-right: 24px; + padding-right: var(--s-size-mini); } &-paragraph { color: var(--s-color-base-content-secondary); - margin-bottom: 24px; - padding-right: 24px; + margin-bottom: var(--s-size-mini); + padding-right: var(--s-size-mini); } } + .sora-card__btn { + width: 100%; + } + .line { height: 1px; margin: 14px 0; background-color: var(--s-color-base-border-secondary); } } - -[design-system-theme='dark'] { - .tos { - &__disclaimer { - box-shadow: -5px -5px 10px rgba(155, 111, 165, 0.25), 2px 2px 15px #492067, - inset 1px 1px 2px rgba(155, 111, 165, 0.25); - } - &__section { - box-shadow: -5px -5px 10px rgba(155, 111, 165, 0.25), 2px 2px 15px #492067, - inset 1px 1px 2px rgba(155, 111, 165, 0.25); - } - } -} diff --git a/src/components/SoraCard/steps/ToSDialog.vue b/src/components/SoraCard/steps/ToSDialog.vue index 03df998be..e23823a18 100644 --- a/src/components/SoraCard/steps/ToSDialog.vue +++ b/src/components/SoraCard/steps/ToSDialog.vue @@ -1,7 +1,7 @@ @@ -22,14 +22,15 @@ export default class TermsAndConditionsDialog extends Mixins(TranslationMixin, m loading = true; - updated(): void { - setTimeout(() => (this.loading = false), 500); + onIFrameLoad(): void { + this.loading = false; } } @@ -38,10 +39,12 @@ export default class TermsAndConditionsDialog extends Mixins(TranslationMixin, m .tos__section { width: 100%; height: 600px; - background-color: var(--s-color-base-background); + // background-color: var(--s-color-base-background); box-shadow: var(--s-shadow-element); - border-radius: var(--s-border-radius-small); + border-radius: 10px; padding: 0; + padding-left: 20px; + padding-right: 4px; overflow: hidden; } diff --git a/src/components/X1/X1Dialog.vue b/src/components/X1/X1Dialog.vue new file mode 100644 index 000000000..4b8cd64a1 --- /dev/null +++ b/src/components/X1/X1Dialog.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/src/consts/index.ts b/src/consts/index.ts index 4dc96b89f..5b6186dc8 100644 --- a/src/consts/index.ts +++ b/src/consts/index.ts @@ -153,11 +153,11 @@ export enum Components { SoraCard = 'SoraCard', SoraCardIntroPage = 'SoraCard/SoraCardIntroPage', SoraCardKYC = 'SoraCard/SoraCardKYC', + ConfirmationInfo = 'SoraCard/ConfirmationInfo', TermsAndConditions = 'SoraCard/steps/TermsAndConditions', ToSDialog = 'SoraCard/steps/ToSDialog', RoadMap = 'SoraCard/steps/RoadMap', KycView = 'SoraCard/steps/KycView', - ConfirmationInfo = 'SoraCard/steps/ConfirmationInfo', SwapConfirm = 'Swap/Confirm', SwapChart = 'Swap/Chart', StatusActionBadge = 'Swap/StatusActionBadge', @@ -213,6 +213,8 @@ export enum Components { // Button SortButton = 'Button/SortButton', SvgIconButton = 'Button/SvgIconButton/SvgIconButton', + X1Dialog = 'X1/X1Dialog', + PaywingsDialog = 'SoraCard/Paywings/PaywingsDialog', } export enum RewardsTabsItems { @@ -316,8 +318,19 @@ export const StoreLinks = { }; export const TosExternalLinks = { - Terms: `https://soracard.com/terms/`, - Privacy: `https://soracard.com/privacy/`, + Terms: `https://soracard.com/terms/en/polkaswap/`, + Privacy: `https://soracard.com/privacy/en/polkaswap/`, + getLinks: function (darkMode = 'light') { + return darkMode === 'dark' + ? { + Terms: this.Terms.concat('?dark'), + Privacy: this.Privacy.concat('?dark'), + } + : { + Terms: this.Terms, + Privacy: this.Privacy, + }; + }, }; export const FaucetLink: SidebarMenuItemLink = { diff --git a/src/store/soraCard/actions.ts b/src/store/soraCard/actions.ts index 3c870d98c..2a277cade 100644 --- a/src/store/soraCard/actions.ts +++ b/src/store/soraCard/actions.ts @@ -2,8 +2,10 @@ import { defineActions } from 'direct-vuex'; import { api } from '@soramitsu/soraneo-wallet-web'; import { FPNumber } from '@sora-substrate/util'; -import { getXorPerEuroRatio, waitForAccountPair } from '@/utils'; +import { waitForAccountPair } from '@/utils'; +import { defineUserStatus, getXorPerEuroRatio } from '@/utils/card'; import { soraCardActionContext } from './../soraCard'; +import { Status } from '@/types/card'; const actions = defineActions({ calculateXorRestPrice(context, xorPerEuro): void { @@ -15,10 +17,10 @@ const actions = defineActions({ commit.setXorPriceToDeposit(euroToPayInXor); }, - async calculateXorBalanceInEuros(context, xorTotalBalance: FPNumber): Promise { + async calculateXorBalanceInEuros(context, { xorPerEuro, xorTotalBalance }): Promise { const { commit, dispatch } = soraCardActionContext(context); + try { - const xorPerEuro: string = await getXorPerEuroRatio(); const xorPerEuroFPN = FPNumber.fromNatural(xorPerEuro); const euroBalance = xorTotalBalance.mul(xorPerEuroFPN).toNumber(); commit.setEuroBalance(euroBalance.toString()); @@ -36,10 +38,12 @@ const actions = defineActions({ if (!rootGetters.wallet.account.isLoggedIn) return; + const xorPerEuro: string = await getXorPerEuroRatio(); + await waitForAccountPair(async () => { const subscription = api.assets.getTotalXorBalanceObservable().subscribe((xorTotalBalance: FPNumber) => { commit.setTotalXorBalance(xorTotalBalance); - dispatch.calculateXorBalanceInEuros(xorTotalBalance); + dispatch.calculateXorBalanceInEuros({ xorPerEuro, xorTotalBalance }); }); commit.setTotalXorBalanceUpdates(subscription); @@ -48,9 +52,16 @@ const actions = defineActions({ async unsubscribeFromTotalXorBalance(context): Promise { const { commit } = soraCardActionContext(context); - setTimeout(() => { - commit.resetTotalXorBalanceUpdates(); - }, 1000 * 60 * 5); + commit.resetTotalXorBalanceUpdates(); + }, + + async getUserStatus(context): Promise { + const { commit } = soraCardActionContext(context); + + const { kycStatus, verificationStatus }: Status = await defineUserStatus(); + + commit.setKycStatus(kycStatus); + commit.setVerificationStatus(verificationStatus); }, }); diff --git a/src/store/soraCard/getters.ts b/src/store/soraCard/getters.ts index 75b1a4e95..e4e6d5ce1 100644 --- a/src/store/soraCard/getters.ts +++ b/src/store/soraCard/getters.ts @@ -1,14 +1,46 @@ +import { KycStatus, VerificationStatus } from '@/types/card'; import { defineGetters } from 'direct-vuex'; import { soraCardGetterContext } from '.'; import { SoraCardState } from './types'; const getters = defineGetters()({ + accountAddress(...args): string { + const { rootState } = soraCardGetterContext(args); + return rootState.wallet.account.address; + }, isEuroBalanceEnough(...args): boolean { const { state } = soraCardGetterContext(args); const euroBalance = parseInt(state.euroBalance, 10); return euroBalance > 100; }, + currentStatus(...args): Nullable { + // CHECKME: carefully check what each status defines. + const { state } = soraCardGetterContext(args); + const { kycStatus, verificationStatus } = state; + + if (!kycStatus) return null; + if (!verificationStatus) return null; + if (kycStatus === KycStatus.Started) return null; + + if ( + [KycStatus.Completed, KycStatus.Successful].includes(kycStatus) && + verificationStatus === VerificationStatus.Pending + ) { + return VerificationStatus.Pending; + } + + if ( + [KycStatus.Completed, KycStatus.Successful].includes(kycStatus) && + verificationStatus === VerificationStatus.Accepted + ) { + return VerificationStatus.Accepted; + } + + if ([KycStatus.Failed, KycStatus.Rejected].includes(kycStatus)) { + return VerificationStatus.Rejected; + } + }, }); export default getters; diff --git a/src/store/soraCard/mutations.ts b/src/store/soraCard/mutations.ts index c122d54fc..8f2046102 100644 --- a/src/store/soraCard/mutations.ts +++ b/src/store/soraCard/mutations.ts @@ -1,3 +1,4 @@ +import { KycStatus, VerificationStatus } from '@/types/card'; import { defineMutations } from 'direct-vuex'; import type { SoraCardState } from './types'; @@ -19,6 +20,12 @@ const mutations = defineMutations()({ state.totalXorBalanceUpdates?.unsubscribe(); state.totalXorBalanceUpdates = null; }, + setKycStatus(state, status: Nullable) { + state.kycStatus = status; + }, + setVerificationStatus(state, status: Nullable) { + state.verificationStatus = status; + }, }); export default mutations; diff --git a/src/store/soraCard/state.ts b/src/store/soraCard/state.ts index e9a0f67f7..8ba69c83c 100644 --- a/src/store/soraCard/state.ts +++ b/src/store/soraCard/state.ts @@ -4,6 +4,8 @@ import { FPNumber } from '@sora-substrate/util'; function initialState(): SoraCardState { return { + kycStatus: undefined, + verificationStatus: undefined, euroBalance: ZeroStringValue, totalXorBalance: FPNumber.ZERO, xorToDeposit: FPNumber.ZERO, diff --git a/src/store/soraCard/types.ts b/src/store/soraCard/types.ts index 2ad51ec83..3256044a9 100644 --- a/src/store/soraCard/types.ts +++ b/src/store/soraCard/types.ts @@ -1,7 +1,10 @@ import type { Subscription } from 'rxjs'; import { FPNumber } from '@sora-substrate/util'; +import { KycStatus, VerificationStatus } from '@/types/card'; export type SoraCardState = { + kycStatus: Nullable; + verificationStatus: Nullable; euroBalance: string; totalXorBalance: FPNumber; xorToDeposit: FPNumber; diff --git a/src/types/card.ts b/src/types/card.ts new file mode 100644 index 000000000..523aa64fc --- /dev/null +++ b/src/types/card.ts @@ -0,0 +1,20 @@ +export enum KycStatus { + Started = 'Started', + Completed = 'Completed', + Failed = 'Failed', + Rejected = 'Rejected', + Successful = 'Successful', +} + +export enum VerificationStatus { + Pending = 'Pending', + Accepted = 'Accepted', + Rejected = 'Rejected', +} + +export type Token = 'accessToken' | 'refreshToken'; + +export interface Status { + verificationStatus: Nullable; + kycStatus: Nullable; +} diff --git a/src/utils/card.ts b/src/utils/card.ts new file mode 100644 index 000000000..de451591c --- /dev/null +++ b/src/utils/card.ts @@ -0,0 +1,190 @@ +import jwtDecode, { JwtPayload } from 'jwt-decode'; +import { WALLET_CONSTS } from '@soramitsu/soraneo-wallet-web'; +import store from '../store'; + +import { KycStatus, Status, VerificationStatus } from '../types/card'; + +// Defines user's KYC status. +// If accessToken expired, tries to get new JWT pair via refreshToken; +// if not, forces user to pass phone number again to create new JWT pair in sessionStorage. +export async function defineUserStatus(): Promise { + const sessionRefreshToken = sessionStorage.getItem('refresh-token'); + let sessionAccessToken = sessionStorage.getItem('access-token'); + + if (!(sessionAccessToken && sessionRefreshToken)) { + return emptyStatusFields(); + } + + if (isAccessTokenExpired(sessionAccessToken)) { + const accessToken = await getUpdatedJwtPair(sessionRefreshToken); + + if (accessToken) { + sessionAccessToken = accessToken; + } else { + return emptyStatusFields(); + } + } + + const { kycStatus, verificationStatus } = await getUserStatus(sessionAccessToken); + + return { kycStatus, verificationStatus }; +} + +async function getUpdatedJwtPair(refreshToken: string): Promise> { + const soraNetwork = store.state.wallet.settings.soraNetwork || WALLET_CONSTS.SoraNetwork.Test; + const { apiKey } = soraCard(soraNetwork).authService; + const buffer = Buffer.from(apiKey); + + try { + const response = await fetch('https://api-auth-test.soracard.com/RequestNewAccessToken', { + method: 'POST', + headers: { + Authorization: `Basic ${buffer.toString('base64')}, Bearer ${refreshToken}`, + }, + }); + + if (response.status === 200 && response.ok === true) { + const accessToken = response.headers.get('accesstoken'); + const expirationTime = response.headers.get('expirationtime'); + + if (accessToken && expirationTime) { + sessionStorage.setItem('access-token', accessToken); + sessionStorage.setItem('expiration-time', expirationTime); + } + + return accessToken; + } + } catch (error) { + console.error('[SoraCard]: Error while getting new JWT pair', error); + } + + return null; +} + +async function getUserStatus(accessToken: string): Promise { + if (!accessToken) return emptyStatusFields(); + + try { + const result = await fetch('https://sora-card.sc1.dev.sora2.soramitsu.co.jp/kyc-last-status', { + method: 'GET', + headers: { + Authorization: `Bearer ${accessToken}`, + }, + }); + + const lastRecord = await result.json(); + + if (!lastRecord) return emptyStatusFields(); + + const verificationStatus: VerificationStatus = lastRecord.verification_status; + const kycStatus: KycStatus = lastRecord.kyc_status; + + if (Object.keys(VerificationStatus).includes(verificationStatus) && Object.keys(KycStatus).includes(kycStatus)) { + return { verificationStatus, kycStatus }; + } + + return emptyStatusFields(); + } catch (error) { + console.error('[SoraCard]: Error while getting KYC and verification statuses', error); + return emptyStatusFields(); + } +} + +const isAccessTokenExpired = (accessToken: string): boolean => { + try { + const decoded: JwtPayload = jwtDecode(accessToken); + + if (decoded.exp) { + if (Date.now() <= decoded.exp * 1000) { + return false; + } + } + + return true; + } catch { + return true; + } +}; + +export const getXorPerEuroRatio = async () => { + try { + const priceResult = await fetch('https://api.coingecko.com/api/v3/simple/price?ids=sora&vs_currencies=eur'); + + const parsedData = await priceResult.json(); + + return parsedData.sora.eur; + } catch (error) { + console.error(error); + } +}; + +export const clearTokensFromSessionStorage = () => { + sessionStorage.removeItem('access-token'); + sessionStorage.removeItem('refresh-token'); + sessionStorage.removeItem('expiration-time'); +}; + +const emptyStatusFields = (): Status => ({ + verificationStatus: undefined, + kycStatus: undefined, +}); + +export function soraCard(soraNetwork: string) { + const getAuthServiceData = (soraNetwork: string) => { + const test = { + sdkURL: 'https://auth-test.paywings.io/auth/sdk.js', + authURL: 'https://auth-test.soracard.com', + apiKey: '6974528a-ee11-4509-b549-a8d02c1aec0d', + }; + + const prod = { + sdkURL: '', + authURL: '', + apiKey: '', + }; + + return soraNetwork === WALLET_CONSTS.SoraNetwork.Prod ? prod : test; + }; + + const getKycServiceData = (soraNetwork: string) => { + const test = { + sdkURL: 'https://kyc-test.soracard.com/web/v2/webkyc.js', + username: 'E7A6CB83-630E-4D24-88C5-18AAF96032A4', + pass: '75A55B7E-A18F-4498-9092-58C7D6BDB333', + env: WALLET_CONSTS.SoraNetwork.Test, + unifiedApiKey: '6974528a-ee11-4509-b549-a8d02c1aec0d', + }; + + const prod = { + sdkURL: '', + username: '', + pass: '', + env: WALLET_CONSTS.SoraNetwork.Prod, + unifiedApiKey: '', + }; + + return soraNetwork === WALLET_CONSTS.SoraNetwork.Prod ? prod : test; + }; + + const getSoraProxyEndpoints = (soraNetwork: string) => { + const test = { + referenceNumberEndpoint: 'https://sora-card.sc1.dev.sora2.soramitsu.co.jp/get-reference-number', + }; + + const prod = { + referenceNumberEndpoint: '', + }; + + return soraNetwork === WALLET_CONSTS.SoraNetwork.Prod ? prod : test; + }; + + const authService = getAuthServiceData(soraNetwork); + const kycService = getKycServiceData(soraNetwork); + const soraProxy = getSoraProxyEndpoints(soraNetwork); + + return { + authService, + kycService, + soraProxy, + }; +} diff --git a/src/utils/index.ts b/src/utils/index.ts index 9796492f4..84dd7efad 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -175,22 +175,6 @@ export const getAssetDecimals = (asset: any, { internal = true } = {}): number | return internal ? asset.decimals : asset.externalDecimals; }; -export const getXorPerEuroRatio = async () => { - try { - const priceResult = await fetch('https://api.coingecko.com/api/v3/simple/price?ids=sora&vs_currencies=eur'); - const parsedData = await priceResult.json(); - return parsedData.sora.eur; - } catch (error) { - console.error(error); - } -}; - -export const clearTokensFromSessionStorage = () => { - sessionStorage.removeItem('access-token'); - sessionStorage.removeItem('refresh-token'); - sessionStorage.removeItem('expiration-time'); -}; - export const formatAssetBalance = ( asset: any, { diff --git a/src/utils/x1.ts b/src/utils/x1.ts new file mode 100644 index 000000000..db2ad3b56 --- /dev/null +++ b/src/utils/x1.ts @@ -0,0 +1,15 @@ +import { WALLET_CONSTS } from '@soramitsu/soraneo-wallet-web'; + +export interface X1Widget { + sdkUrl: string; + widgetId: string; +} + +export class X1Api { + public static getWidget(soraNetwork: string): X1Widget { + if (soraNetwork === WALLET_CONSTS.SoraNetwork.Prod) { + return { sdkUrl: 'https://x1ex.com/widgets/sdk.js', widgetId: 'sprkwdgt-WUQBA5U2' }; + } + return { sdkUrl: 'https://dev.x1ex.com/widgets/sdk.js', widgetId: 'sprkwdgt-WYL6QBNC' }; + } +} diff --git a/src/views/About.vue b/src/views/About.vue index be13eb038..fd7e79ddb 100644 --- a/src/views/About.vue +++ b/src/views/About.vue @@ -158,7 +158,6 @@ import type Theme from '@soramitsu/soramitsu-js-ui/lib/types/Theme'; import TranslationMixin from '@/components/mixins/TranslationMixin'; import Web3Logo from '@/components/logo/Web3.vue'; -import { app } from '@/consts'; import { getter } from '@/store/decorators'; @Component({ diff --git a/src/views/SoraCard.vue b/src/views/SoraCard.vue index 69480d7f4..2e83c1361 100644 --- a/src/views/SoraCard.vue +++ b/src/views/SoraCard.vue @@ -1,122 +1,111 @@