diff --git a/packages/desktop/components/popup/popups/EvmTransactionFromDappPopup.svelte b/packages/desktop/components/popup/popups/EvmTransactionFromDappPopup.svelte index 1055a5c96b..24012d7507 100644 --- a/packages/desktop/components/popup/popups/EvmTransactionFromDappPopup.svelte +++ b/packages/desktop/components/popup/popups/EvmTransactionFromDappPopup.svelte @@ -87,7 +87,7 @@ }, }) } catch (err) { - callback({ error: err }) + modifyPopupState({ preventClose: false }, true) handleError(err) } } diff --git a/packages/desktop/components/popup/popups/ImportErc721TokenFormPopup.svelte b/packages/desktop/components/popup/popups/ImportErc721TokenFormPopup.svelte index c3850b5116..ebc80a4c7a 100644 --- a/packages/desktop/components/popup/popups/ImportErc721TokenFormPopup.svelte +++ b/packages/desktop/components/popup/popups/ImportErc721TokenFormPopup.svelte @@ -8,6 +8,7 @@ import { closePopup } from '@desktop/auxiliary/popup' import { showNotification } from '@auxiliary/notification' import { + addNftsToDownloadQueue, addNewTrackedNftToActiveProfile, persistErc721Nft, updateAllAccountNftsForAccount, @@ -45,6 +46,7 @@ const l2Address = getAddressFromAccountForNetwork(account, networkId) const nft = buildNftFromPersistedErc721Nft(persistedNft, l2Address) updateAllAccountNftsForAccount(account.index, nft) + void addNftsToDownloadQueue([nft]) } showNotification({ diff --git a/packages/desktop/components/popup/popups/SignMessagePopup.svelte b/packages/desktop/components/popup/popups/SignMessagePopup.svelte index 57ca57e321..a6446ba4f7 100644 --- a/packages/desktop/components/popup/popups/SignMessagePopup.svelte +++ b/packages/desktop/components/popup/popups/SignMessagePopup.svelte @@ -63,7 +63,6 @@ }, }) } catch (err) { - callback({ error: err }) handleError(err) } finally { isBusy = false diff --git a/packages/desktop/features/analytics.features.ts b/packages/desktop/features/analytics.features.ts index 3cff6bd6f6..0e8e9ffb91 100644 --- a/packages/desktop/features/analytics.features.ts +++ b/packages/desktop/features/analytics.features.ts @@ -35,6 +35,9 @@ const analyticsFeatures: IAnalyticsFeatures = { buySell: { enabled: true, }, + campaigns: { + enabled: true, + }, }, loginRoute: { enabled: true, diff --git a/packages/desktop/features/campaigns.features.ts b/packages/desktop/features/campaigns.features.ts new file mode 100644 index 0000000000..334e5d4ae9 --- /dev/null +++ b/packages/desktop/features/campaigns.features.ts @@ -0,0 +1,10 @@ +import { ICampaignsFeatures } from '@lib/features/interfaces' + +const campaignsFeatures: ICampaignsFeatures = { + enabled: true, + importCampaign: { + enabled: false, + }, +} + +export default campaignsFeatures diff --git a/packages/desktop/features/features.ts b/packages/desktop/features/features.ts index e82fbd12c3..a3e36311bb 100644 --- a/packages/desktop/features/features.ts +++ b/packages/desktop/features/features.ts @@ -1,18 +1,19 @@ +import analyticsFeatures from './analytics.features' import appFeatures from './app.features' +import buySellFeatures from './buy-sell.features' +import campaignsFeatures from './campaigns.features' import collectiblesFeatures from './collectibles.features' import contactsFeatures from './contacts.features' import developerToolsFeatures from './developer-tools.features' import electronFeatures from './electron.features' import governanceFeatures from './governance.features' +import { IDesktopFeatures } from './interfaces' import loginFeatures from './login.features' import networkFeatures from './network.features' import onboardingFeatures from './onboarding.features' import settingsFeatures from './settings.features' -import walletFeatures from './wallet.features' import walletConnectFeatures from './wallet-connect.features' -import analyticsFeatures from './analytics.features' -import buySellFeatures from './buy-sell.features' -import { IDesktopFeatures } from './interfaces' +import walletFeatures from './wallet.features' const features: IDesktopFeatures = { app: appFeatures, @@ -29,6 +30,7 @@ const features: IDesktopFeatures = { wallet: walletFeatures, walletConnect: walletConnectFeatures, buySell: buySellFeatures, + campaigns: campaignsFeatures, } export default features diff --git a/packages/desktop/features/interfaces/analytics-features.interface.ts b/packages/desktop/features/interfaces/analytics-features.interface.ts index ec972a4d81..4fced8c685 100644 --- a/packages/desktop/features/interfaces/analytics-features.interface.ts +++ b/packages/desktop/features/interfaces/analytics-features.interface.ts @@ -15,6 +15,7 @@ export interface IAnalyticsFeatures extends IFeatureFlag { sendFlow: IFeatureFlag } buySell: IFeatureFlag + campaigns: IFeatureFlag } loginRoute: IFeatureFlag onboardingRoute: IFeatureFlag diff --git a/packages/desktop/lib/routers/actions/initialiseRouters.ts b/packages/desktop/lib/routers/actions/initialiseRouters.ts index b6cc0e2f6a..f231ef4dd0 100644 --- a/packages/desktop/lib/routers/actions/initialiseRouters.ts +++ b/packages/desktop/lib/routers/actions/initialiseRouters.ts @@ -11,6 +11,7 @@ import { settingsRouter, } from '@core/router/routers' import { loginRouter, LoginRouter } from '@core/router/subrouters' +import { CampaignsRouter, campaignsRouter } from '@views/dashboard/campaigns' import { OnboardingRouter, onboardingRouter } from '@views/onboarding' export function initialiseRouters(): void { @@ -33,6 +34,7 @@ function initialiseBaseRouters(): void { settingsRouter.set(new SettingsRouter()) collectiblesRouter.set(new CollectiblesRouter()) governanceRouter.set(new GovernanceRouter()) + campaignsRouter.set(new CampaignsRouter()) initialiseBaseOnboardingRouters() } diff --git a/packages/desktop/views/dashboard/Dashboard.svelte b/packages/desktop/views/dashboard/Dashboard.svelte index c309b57ab4..a45312112b 100644 --- a/packages/desktop/views/dashboard/Dashboard.svelte +++ b/packages/desktop/views/dashboard/Dashboard.svelte @@ -25,6 +25,7 @@ import { Settings } from '../settings' import { Background } from '@views/components' import { BuySell } from './buy-sell' + import { CampaignsRouterView } from './campaigns' const tabs = { wallet: Wallet, @@ -33,6 +34,7 @@ governance: Governance, developer: Developer, buySell: BuySell, + campaigns: CampaignsRouterView, } let previousAccountIndex = get(selectedAccountIndex) diff --git a/packages/desktop/views/dashboard/campaigns/CampaignsRouterView.svelte b/packages/desktop/views/dashboard/campaigns/CampaignsRouterView.svelte new file mode 100644 index 0000000000..024e1bf7e7 --- /dev/null +++ b/packages/desktop/views/dashboard/campaigns/CampaignsRouterView.svelte @@ -0,0 +1,24 @@ + + +
+ {#if $campaignsRoute === CampaignsRoute.Gallery} + + {/if} + {#if $campaignsRoute === CampaignsRoute.CampaignDetails} + + {/if} +
diff --git a/packages/desktop/views/dashboard/campaigns/campaigns-route.enum.ts b/packages/desktop/views/dashboard/campaigns/campaigns-route.enum.ts new file mode 100644 index 0000000000..804cc3ec1f --- /dev/null +++ b/packages/desktop/views/dashboard/campaigns/campaigns-route.enum.ts @@ -0,0 +1,4 @@ +export enum CampaignsRoute { + Gallery = 'gallery', + CampaignDetails = 'campaignDetails', +} diff --git a/packages/desktop/views/dashboard/campaigns/campaigns-router.ts b/packages/desktop/views/dashboard/campaigns/campaigns-router.ts new file mode 100644 index 0000000000..0a4f3457ac --- /dev/null +++ b/packages/desktop/views/dashboard/campaigns/campaigns-router.ts @@ -0,0 +1,30 @@ +import { Router } from '@core/router' +import { appRouter } from '@core/router/routers/app-router' +import { get, writable } from 'svelte/store' +import { CampaignsRoute } from './campaigns-route.enum' + +export const campaignsRoute = writable(undefined) +export const campaignsRouter = writable(undefined) + +export class CampaignsRouter extends Router { + protected breadcrumb: string | undefined + constructor() { + super(CampaignsRoute.Gallery, campaignsRoute) + } + + previous(): void { + if (this.history.length > 0) { + super.previous() + } else { + get(appRouter).previous() + } + } + + setBreadcrumb(breadcrumb: string | undefined): void { + this.breadcrumb = breadcrumb + } + + getBreadcrumb(): string | undefined { + return this.breadcrumb + } +} diff --git a/packages/desktop/views/dashboard/campaigns/components/CampaignHeader.svelte b/packages/desktop/views/dashboard/campaigns/components/CampaignHeader.svelte new file mode 100644 index 0000000000..e8db0b7c08 --- /dev/null +++ b/packages/desktop/views/dashboard/campaigns/components/CampaignHeader.svelte @@ -0,0 +1,120 @@ + + + + {#if campaign.imageUrl && !imageLoadError} +
+ {campaign?.title} (imageLoadError = true)} + /> +
+ {:else} +
+ +
+ {/if} +
+
+ {campaign.title} +
+
+
+
+ {description} +
+
+ + + + +
+ openUrlInBrowser(campaign.url)} + /> +
+
+
+
diff --git a/packages/desktop/views/dashboard/campaigns/components/CampaignNft.svelte b/packages/desktop/views/dashboard/campaigns/components/CampaignNft.svelte new file mode 100644 index 0000000000..adfe28fbeb --- /dev/null +++ b/packages/desktop/views/dashboard/campaigns/components/CampaignNft.svelte @@ -0,0 +1,42 @@ + + +
+ +
+ +
+ {localize(`views.campaigns.details.${nft ? 'nftBadge' : 'noNftBadge'}`)} +
+
+
+
+
+ {#if nft} + + + + {:else} + + {/if} +
diff --git a/packages/desktop/views/dashboard/campaigns/components/CampaignParticipantsPill.svelte b/packages/desktop/views/dashboard/campaigns/components/CampaignParticipantsPill.svelte new file mode 100644 index 0000000000..0e2333eae0 --- /dev/null +++ b/packages/desktop/views/dashboard/campaigns/components/CampaignParticipantsPill.svelte @@ -0,0 +1,15 @@ + + + +
+ +
+ {campaign.participants ?? 0} +
+
+
diff --git a/packages/desktop/views/dashboard/campaigns/components/CampaignRewardsPill.svelte b/packages/desktop/views/dashboard/campaigns/components/CampaignRewardsPill.svelte new file mode 100644 index 0000000000..50500d0e80 --- /dev/null +++ b/packages/desktop/views/dashboard/campaigns/components/CampaignRewardsPill.svelte @@ -0,0 +1,16 @@ + + + +
+ +
+ {localize(`general.${campaign.ERC20Reward ? 'raffle' : 'nft'}`)} +
+
+
diff --git a/packages/desktop/views/dashboard/campaigns/components/CampaignStatusPill.svelte b/packages/desktop/views/dashboard/campaigns/components/CampaignStatusPill.svelte new file mode 100644 index 0000000000..107c0bf37b --- /dev/null +++ b/packages/desktop/views/dashboard/campaigns/components/CampaignStatusPill.svelte @@ -0,0 +1,28 @@ + + + +
+ {#if campaignStatus === CampaignStatus.Active} + + {/if} +
+ {localize(`general.${campaignStatus}`)} +
+
+
diff --git a/packages/desktop/views/dashboard/campaigns/components/CampaignTimestampPill.svelte b/packages/desktop/views/dashboard/campaigns/components/CampaignTimestampPill.svelte new file mode 100644 index 0000000000..a247fd1adc --- /dev/null +++ b/packages/desktop/views/dashboard/campaigns/components/CampaignTimestampPill.svelte @@ -0,0 +1,19 @@ + + +{#if timeDifference} + +
+ +
{getTimeDifference(new Date(campaign.endTime), $time)}
+
+
+{/if} diff --git a/packages/desktop/views/dashboard/campaigns/components/CampaignsGallery.svelte b/packages/desktop/views/dashboard/campaigns/components/CampaignsGallery.svelte new file mode 100644 index 0000000000..7a3c7a2acf --- /dev/null +++ b/packages/desktop/views/dashboard/campaigns/components/CampaignsGallery.svelte @@ -0,0 +1,17 @@ + + +
+ {#each campaigns as campaign} + + {/each} +
diff --git a/packages/desktop/views/dashboard/campaigns/components/CampaignsGalleryItem.svelte b/packages/desktop/views/dashboard/campaigns/components/CampaignsGalleryItem.svelte new file mode 100644 index 0000000000..72e0aa2217 --- /dev/null +++ b/packages/desktop/views/dashboard/campaigns/components/CampaignsGalleryItem.svelte @@ -0,0 +1,84 @@ + + + + + diff --git a/packages/desktop/views/dashboard/campaigns/components/FeaturedPill.svelte b/packages/desktop/views/dashboard/campaigns/components/FeaturedPill.svelte new file mode 100644 index 0000000000..33c676f1d8 --- /dev/null +++ b/packages/desktop/views/dashboard/campaigns/components/FeaturedPill.svelte @@ -0,0 +1,13 @@ + + + +
+ +
+ {localize('general.featured')} +
+
+
diff --git a/packages/desktop/views/dashboard/campaigns/components/Leaderboard.svelte b/packages/desktop/views/dashboard/campaigns/components/Leaderboard.svelte new file mode 100644 index 0000000000..28b26cfbc4 --- /dev/null +++ b/packages/desktop/views/dashboard/campaigns/components/Leaderboard.svelte @@ -0,0 +1,114 @@ + + +{#if leaderboardItems?.length} + + + + + + + {#each leaderboardItems as leaderboardItem, index} + {@const user = getSubjectFromAddress(leaderboardItem.address, networkId)} + + + + + {/each} + +
{localize('views.campaigns.details.top10')}
+ {#if index <= 2} + + {:else if leaderboardItem.address === userAddress} + + {:else} + + {/if} + {#if user?.type === 'account'} + + {truncateString(user.account.name, 14)} + + {:else} +
+ {leaderboardItem.address.substring( + 0, + leaderboardItem.address.length - 7 + )} + {leaderboardItem.address.substring( + leaderboardItem.address.length - 7, + leaderboardItem.address.length - 1 + )} +
+ {/if} +
+
+ Badges: {leaderboardItem.rewardClaimed} + Tasks: {leaderboardItem.taskDone} +
+ {leaderboardItem.totalXp} xp +
+
+{:else} + +
+ {localize('views.campaigns.details.top10')} +
+ {#if error} +
+ +
+ {:else if loading} +
+ +
+ {:else} +
+ +
+ {/if} +
+{/if} + + diff --git a/packages/desktop/views/dashboard/campaigns/components/TideLogo.svelte b/packages/desktop/views/dashboard/campaigns/components/TideLogo.svelte new file mode 100644 index 0000000000..9644d3d785 --- /dev/null +++ b/packages/desktop/views/dashboard/campaigns/components/TideLogo.svelte @@ -0,0 +1,35 @@ + + + + + + + + + + + + diff --git a/packages/desktop/views/dashboard/campaigns/components/UserPositionCard.svelte b/packages/desktop/views/dashboard/campaigns/components/UserPositionCard.svelte new file mode 100644 index 0000000000..12011bd5c8 --- /dev/null +++ b/packages/desktop/views/dashboard/campaigns/components/UserPositionCard.svelte @@ -0,0 +1,41 @@ + + +
+ +
+ {localize('views.campaigns.details.myPosition')} + {#if userPosition?.position} + {userPosition.position} + {:else} + {userPosition?.position ?? '-'} + {/if} +
+
+ {localize('views.campaigns.details.points')} + {userPosition?.totalXp ?? 0}xp +
+
+ {localize('views.campaigns.details.tasksComplete')} + + {`${userPosition?.taskDone ?? '0'}/${numberOfTasks ?? '-'}`} + +
+
+ +
+
+
diff --git a/packages/desktop/views/dashboard/campaigns/components/index.ts b/packages/desktop/views/dashboard/campaigns/components/index.ts new file mode 100644 index 0000000000..c594ad6482 --- /dev/null +++ b/packages/desktop/views/dashboard/campaigns/components/index.ts @@ -0,0 +1,11 @@ +export { default as CampaignHeader } from './CampaignHeader.svelte' +export { default as CampaignNft } from './CampaignNft.svelte' +export { default as CampaignParticipantsPill } from './CampaignParticipantsPill.svelte' +export { default as CampaignRewardsPill } from './CampaignRewardsPill.svelte' +export { default as CampaignsGallery } from './CampaignsGallery.svelte' +export { default as CampaignsGalleryItem } from './CampaignsGalleryItem.svelte' +export { default as CampaignStatusPill } from './CampaignStatusPill.svelte' +export { default as CampaignTimestampPill } from './CampaignTimestampPill.svelte' +export { default as Leaderboard } from './Leaderboard.svelte' +export { default as UserPositionCard } from './UserPositionCard.svelte' +export { default as TideLogo } from './TideLogo.svelte' diff --git a/packages/desktop/views/dashboard/campaigns/index.ts b/packages/desktop/views/dashboard/campaigns/index.ts new file mode 100644 index 0000000000..f35aadf8a5 --- /dev/null +++ b/packages/desktop/views/dashboard/campaigns/index.ts @@ -0,0 +1,4 @@ +export { default as CampaignsRouterView } from './CampaignsRouterView.svelte' + +export * from './campaigns-route.enum' +export * from './campaigns-router' diff --git a/packages/desktop/views/dashboard/campaigns/views/CampaignDetailsView.svelte b/packages/desktop/views/dashboard/campaigns/views/CampaignDetailsView.svelte new file mode 100644 index 0000000000..8179dd43b1 --- /dev/null +++ b/packages/desktop/views/dashboard/campaigns/views/CampaignDetailsView.svelte @@ -0,0 +1,144 @@ + + +
+ + +
+
+ +
+
+ +
+
+
diff --git a/packages/desktop/views/dashboard/campaigns/views/CampaignsGalleryView.svelte b/packages/desktop/views/dashboard/campaigns/views/CampaignsGalleryView.svelte new file mode 100644 index 0000000000..15aa966fd1 --- /dev/null +++ b/packages/desktop/views/dashboard/campaigns/views/CampaignsGalleryView.svelte @@ -0,0 +1,152 @@ + + + +
+
+ {localize('views.campaigns.gallery.title')} + + {String(sortedCampaigns.length ?? '')} + +
+ +
+ {#if campaigns.length} + + {/if} + {#if features.campaigns.importCampaign.enabled} + + + {/if} +
+
+ {#if campaigns.length} + {#if queriedCampaigns.length} + + {:else} +
+ +
+ {/if} + {:else if loading} +
+ +
+ {:else} +
+ +
+ {/if} +
+ + diff --git a/packages/desktop/views/dashboard/campaigns/views/index.ts b/packages/desktop/views/dashboard/campaigns/views/index.ts new file mode 100644 index 0000000000..763aaa405e --- /dev/null +++ b/packages/desktop/views/dashboard/campaigns/views/index.ts @@ -0,0 +1,2 @@ +export { default as CampaignDetailsView } from './CampaignDetailsView.svelte' +export { default as CampaignsGalleryView } from './CampaignsGalleryView.svelte' diff --git a/packages/desktop/views/dashboard/collectibles/components/CollectibleDetails.svelte b/packages/desktop/views/dashboard/collectibles/components/CollectibleDetails.svelte index 1af95f0a9d..77702acd70 100644 --- a/packages/desktop/views/dashboard/collectibles/components/CollectibleDetails.svelte +++ b/packages/desktop/views/dashboard/collectibles/components/CollectibleDetails.svelte @@ -1,5 +1,5 @@ diff --git a/packages/shared/package.json b/packages/shared/package.json index 271652bca7..b8d87c7120 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -5,7 +5,7 @@ "author": "Bloom Labs Ltd ", "license": "Apache-2.0", "dependencies": { - "@bloomwalletio/ui": "0.19.5", + "@bloomwalletio/ui": "0.19.9", "@iota/bundle": "1.0.0-beta.30", "@iota/converter": "1.0.0-beta.30", "@iota/crypto.js": "1.8.6", @@ -22,6 +22,7 @@ "http-status-codes": "2.3.0", "lottie-web": "5.12.2", "qrious": "4.0.2", + "sanitize-html": "^2.11.0", "sha3": "2.1.4", "svelte": "3.58.0", "svelte-i18n": "3.7.4", @@ -39,6 +40,7 @@ "@swc/jest": "0.2.24", "@types/big.js": "6.2.1", "@types/jest": "29.5.11", + "@types/sanitize-html": "^2.9.5", "autoprefixer": "10.4.16", "jest": "29.7.0", "jest-environment-jsdom": "29.6.2", diff --git a/packages/shared/src/components/molecules/MediaIcon.svelte b/packages/shared/src/components/molecules/MediaIcon.svelte index 93d46863ca..b135927e82 100644 --- a/packages/shared/src/components/molecules/MediaIcon.svelte +++ b/packages/shared/src/components/molecules/MediaIcon.svelte @@ -1,15 +1,12 @@ - + diff --git a/packages/shared/src/components/molecules/MediaPlaceholder.svelte b/packages/shared/src/components/molecules/MediaPlaceholder.svelte index 0022e4732e..8e65cedba5 100644 --- a/packages/shared/src/components/molecules/MediaPlaceholder.svelte +++ b/packages/shared/src/components/molecules/MediaPlaceholder.svelte @@ -1,21 +1,17 @@ - + diff --git a/packages/shared/src/components/molecules/NftGalleryItem.svelte b/packages/shared/src/components/molecules/NftGalleryItem.svelte index dae39f80a7..d20d621803 100644 --- a/packages/shared/src/components/molecules/NftGalleryItem.svelte +++ b/packages/shared/src/components/molecules/NftGalleryItem.svelte @@ -1,21 +1,32 @@ -