diff --git a/.github/workflows/deploy-prod.yml b/.github/workflows/deploy-prod.yml index 3242661..133609f 100644 --- a/.github/workflows/deploy-prod.yml +++ b/.github/workflows/deploy-prod.yml @@ -1,4 +1,4 @@ -name: Action | Auto deploy "develop" to wen.soonaverse.com +name: Action | Auto deploy "production" to soonaverse.com on: release: @@ -21,7 +21,7 @@ jobs: - name: Install Dependencies run: npm install - name: Build project - run: npm run build + run: npm run build:prod - name: Publish to Cloudflare Pages uses: cloudflare/pages-action@v1 with: diff --git a/.github/workflows/ui_eslint.yml b/.github/workflows/ui_eslint.yml index 648216d..d4dfa5b 100644 --- a/.github/workflows/ui_eslint.yml +++ b/.github/workflows/ui_eslint.yml @@ -1,9 +1,6 @@ name: UI | ES Lint -on: - pull_request: - paths: - - packages/ui/** +on: push jobs: front_end_es_lint: @@ -21,8 +18,6 @@ jobs: - name: Install Dependencies run: npm install - name: Lint - working-directory: packages/ui run: npm run lint - name: Prettier - working-directory: packages/ui run: npx prettier --check . diff --git a/.prettierignore b/.prettierignore index 2c23c59..e8afab7 100644 --- a/.prettierignore +++ b/.prettierignore @@ -5,3 +5,7 @@ lib **/lib **/node_modules .angular +.github +CONTRIBUTING.md +MANIFESTO.md +README.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 810222e..e823d32 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,6 +8,37 @@ We want to make contributing to this project as easy and transparent as possible - Proposing new features - Becoming a maintainer +SOON token is used to reward contributors for their effort. + +## SOON token Rewards + +All contributions are rewarded through SOON tokens. Yes, your contribution is valued. + +Current code review committee: +- @adam_unchained +- @flyingrabbit-lab + +Core reviewer labels appropriate category on the PR or github issue. If no category is defined on either of them make sure to ask code reviewer by tagging them. SOON reward can be discussed prior on the Github issue before the work even starts. This allows interested parties to understand potential reward. + +There are three categories of contribution: + +**Category 1 (up to 1000 SOON):** + +- Requires one approval on PR by code review committee member. + +**Category 2 (up to 5000 SOON):** + +- Requires one approval on PR by code review committee member. +- Requires majority SOON Committee approval. + +**Category 3 (unrestricted):** + +- Requires one approval on PR by code review committee member. +- Requires majority SOON Committee approval. +- Requires SOON vote through Soonaverse on-chain votting. + +Please note, contributor is responsible to notify and reach out to members for approval. + ## We Develop with Github We use github to host code, to track issues and feature requests, as well as accept pull requests. @@ -27,7 +58,7 @@ Pull requests are the best way to propose changes to the codebase (we use [Githu In short, when you submit code changes, your submissions are understood to be under the same [MIT License](http://choosealicense.com/licenses/mit/) that covers the project. Feel free to contact the maintainers if that's a concern. -## Report bugs using Github's [issues](https://github.com/soonaverse/soonaverse/issues) +## Report bugs using Github's [issues](https://github.com/soonaverse/app/issues) We use GitHub issues to track public bugs. Report a bug by [opening a new issue](https://docs.github.com/en/github/managing-your-work-on-github/creating-an-issue) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md new file mode 100644 index 0000000..0e4402d --- /dev/null +++ b/CONTRIBUTORS.md @@ -0,0 +1,7 @@ +# List of all contributors and SOON token reward + +This table provides complete history into each contributions and their SOON reward. + +User | PR | SOON Reward | SMR Address | Authorized By | Comments | +---- | -- | ----------- | ----------- | ------------- | -------- | +[@emmap3-do](https://github.com/emmap3-do) | https://github.com/soonaverse/app/pull/47 | 500 | smr1qzt5qs6m6s2us8ll0hdfefzpr43cdz2xmjzywmrkz0sc2uyegvzjwazr6f8 | [@adam_unchained](https://github.com/adam_unchained) | Testing, continuous support in #dev channel diff --git a/MANIFESTO.md b/MANIFESTO.md new file mode 100644 index 0000000..faccc78 --- /dev/null +++ b/MANIFESTO.md @@ -0,0 +1,44 @@ +# The Soonaverse Manifesto + +Soonaverse is a collaboration between dedicated professionals, skilled in navigating the constant tension between invention and production to find ways to create, build, and get things done. We have different backgrounds, skills, and experiences, but share a singular goal, a shared vision, a common mantra - together we can build the impossible. + +Our current “impossible” is building a more equitable world through decentralization. A world where centralized systems have NOT concentrated society’s influence, power and wealth into the hands of an infinitesimally small number of individuals and organizations. + +Decentralization will enable us to avoid cronyism and chaos. Where we are, what we’ve done, and how we’re SEEN is based on merit not image, value not celebrity. + +Like the DAOs we create, we believe that contributions should be judged without bias, blind to color, class, and creed, where every vote counts, where “we” is stronger than “me”, and organizations are equal and flat because that’s the way they should be. + +We believe that privacy isn’t just a cloak, it's a shield, and an anonymous voice is still a voice. DAOs must have trust, they must have reputation for members to create meaningful connections, so when people gather they become makers not mobs. + +Your voice matters and NO ONE should demand a fee for expressing your opinion, no one should force you to pay to exercise your right to vote, decentralization must be an enabler not a wall. + +Our DAOs will bring the change the world needs, by spreading the power of every decision across 7.7 billion points of humanity, where everyone's an influencer, because everyone has influence. + +Ask WHO we need. We’ll say, YOU. + +Ask HOW can it be done. We’ll say, TOGETHER. + +Ask WHERE it will happen. We’ll say, RIGHT BEFORE YOU EYES. + +And then ask us WHEN. No, ask us WEN and we will say SOON, because THAT is always our answer. + +## Our DAOs + +### The Soonaverse + +#### Founding Principles + +1. "All Voting MUST be FREE and Securely ON-Chain" +2. “DAOs must have immutable TRUST and REPUTATION” +3. “An anonymous voice is STILL A VOICE and members must be HEARD” + +#### Commitments + +* The Soonaverse is committed to building the foundation for organizations that enable DAOs and embrace personal sovereignty - where every person and community has the power to vote, the power to choose. +* The Soonaverse will remove the “dysfunction from decentralization” and steer communities towards its better angels through trust and reputation. +* The Soonaverse prioritizes the will of DAOs and its communities by creating equitable systems of proposal management. We believe that members should make their case, give people their vote and let the best ideas win. +* We will always strive to be a place for experimentation and innovation, but not at the cost of our members. +* The Soonaverse will be built with the most reliable and advanced decentralization technologies available, once they are PROVEN to be safe. +* We will embrace transparency and honesty in our approaches, especially when it comes to transitioning from centralized to decentralized technologies. +* The SOON token is a means to govern the platform and is woven into the very fabric of the system. We avoid fees wherever possible, especially when it comes to voting. +* We will create tokenomics that keep the platform funded and thriving to support the ecosystem, our members, and the DAOs we are creating. diff --git a/README.md b/README.md index e77f8f1..b6bd3cf 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,92 @@ +

Soonaverse - Web3 platform for communities build on IOTA & Shimmer

+ +

+ angular-logo +
+ Soonaverse is a platform for communities to create and manage decentralized autonomous organizations (DAOs), NFTs, projects, companies, and markets, on the feeless infrastructure of the IOTA and SMR network. +
+

+ +

+ www.soonaverse.com +
+

+ +

+ Contributing Guidelines + · + Submit an Issue + · + Twitter +
+
+

+ +

+ + Follow on Twitter +   + + Discord conversation + +

+ +
+ # Overview -Soonaverse Application. +Soonaverse delivers DAO Management Tools, NFT Marketplace, Token Management, On-Chain voting and much more. Open source application for everyone to utilize and benefit from. Using [BUILD-5](https://build5.com) platform and IOTA it can deliver feeless on chain functionality. Soonaverse operates on both IOTA and Shimmer network. + +We would love your contributions. Please make sure you read contribution guide to join the effort. Key areas we need help: +- UI Improvements +- Documentation +- Bug fixing +- New modules & integrations + +Soonaverse is governed through SOON token. SOON Tokens are used to reward efforts and contributions. + +## Current Soon Committee +- @adam_unchained +- @DaveRL6 +- @iotaben +- @shonuff +- @TangleAccountant +- @garrett1314 + +# Design +- [WebApp Figma](https://www.figma.com/file/vYJByA2q3c13oAjJ3IHfk1/Soonaverse---WebApp?type=design&node-id=2736%3A37764&mode=design&t=FVgSq8fJghvHAVPS-1) +- [WebApp Dark Figma](https://www.figma.com/file/Qmor0eN2Iwq2GXMoFXB8t0/Soonaverse---WebApp-(Darkmode)?type=design&node-id=2730%3A33049&mode=design&t=KxGswtBYAYrizzcS-1) +- [Responsive Figma](https://www.figma.com/file/P341i2urVRKpZg6GdrrLg0/Soonaverse---Responsive?type=design&node-id=2730%3A33049&mode=design&t=OrwcreWX2tU8ep7M-1) + +# Development Setup + +## Prerequisites + +Install [Node.js](https://nodejs.org/en) which includes [Node Package Manager](https://www.npmjs.com) + +Soonaverse uses key libraries: +- [Angular](https://angular.io/) +- [Tailwind CSS](https://tailwindcss.com/) +- [Ng Zorro](https://ng.ant.design) +- [Build-5/interfaces](https://www.npmjs.com/package/@build-5/interfaces) and [Build-5/lib](https://www.npmjs.com/package/@build-5/lib) +- [Algolia](https://www.algolia.com/) (for searches) + +## Setting Up a Project + +Make sure to install all dependencies: + +```npm install``` + +Run locally: + +```npm start``` + +You can switch between production / sandbox environment by either using environment.ts or environment.prod.ts. # 🤝 Contributing -[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](https://github.com/soonaverse/soonaverse/pulls) +Earn SOON when you contribute!!! -We welcome all contributions. Please read our [CONTRIBUTING.md](https://github.com/soonaverse/app/blob/master/CONTRIBUTING.md) first. You can submit any ideas as [pull requests](https://github.com/soonaverse/app/pulls) or as [GitHub issues](https://github.com/soonaverse/app/issues). +We welcome all contributions. Please read our [CONTRIBUTING.md](CONTRIBUTING.md) first. You can submit any ideas as [pull requests](https://github.com/soonaverse/app/pulls) or as [GitHub issues](https://github.com/soonaverse/app/issues). -Thank you for supporting us free open source licenses. +Thank you for supporting us with free open source licenses. diff --git a/src/app/@api/base.api.ts b/src/app/@api/base.api.ts index 092954d..0ce1d21 100644 --- a/src/app/@api/base.api.ts +++ b/src/app/@api/base.api.ts @@ -9,7 +9,7 @@ import { } from '@build-5/interfaces'; import { Build5Env } from '@build-5/lib'; import { CrudRepository } from '@build-5/lib/lib/repositories/CrudRepository'; -import { Observable, map } from 'rxjs'; +import { Observable, map, of } from 'rxjs'; export const DEFAULT_LIST_SIZE = 50; export const WHERE_IN_BATCH = 10; @@ -29,7 +29,8 @@ export class BaseApi { public listen = (id: string) => this.repo.getByIdLive(id); - public listenMultiple = (ids: EthAddress[]) => this.repo.getManyByIdLive(ids); + public listenMultiple = (ids: EthAddress[]) => + ids.length ? this.repo.getManyByIdLive(ids) : of([]); public top = (lastValue?: string, limit?: number) => this.repo.getTopLive(lastValue, limit); diff --git a/src/app/@api/member.api.ts b/src/app/@api/member.api.ts index 961be57..1ae8a95 100644 --- a/src/app/@api/member.api.ts +++ b/src/app/@api/member.api.ts @@ -33,7 +33,7 @@ import { TransactionRepository, } from '@build-5/lib'; import dayjs from 'dayjs'; -import { Observable, combineLatest, map, switchMap } from 'rxjs'; +import { Observable, combineLatest, map, of, switchMap } from 'rxjs'; import { BaseApi, SOON_ENV } from './base.api'; export interface TokenDistributionWithAirdrops extends TokenDistribution { @@ -91,17 +91,19 @@ export class MemberApi extends BaseApi { }; public listenMultiple = (ids: EthAddress[]) => - this.memberRepo - .getByFieldLive( - ids.map(() => 'uid'), - ids, - ) - .pipe( - map((members) => { - members.sort((a, b) => (a.createdOn?.seconds || 0) - (b.createdOn?.seconds || 0)); - return members; - }), - ); + ids.length + ? this.memberRepo + .getByFieldLive( + ids.map(() => 'uid'), + ids, + ) + .pipe( + map((members) => { + members.sort((a, b) => (a.createdOn?.seconds || 0) - (b.createdOn?.seconds || 0)); + return members; + }), + ) + : of([]); public topStakes = (memberId: EthAddress, lastValue?: string): Observable => this.stakeRepo.getByMemberLive(memberId, lastValue).pipe( @@ -192,15 +194,15 @@ export class MemberApi extends BaseApi { ): Observable { const orderBys = Array.isArray(orderBy) ? orderBy : [orderBy]; - const all = this.transactionRepo - .getTopTransactionsLive(orderBys, lastValue) + const prevOwner = this.transactionRepo + .getTopTransactionsLive(orderBys, lastValue, undefined, memberId) .pipe(map((result) => result.filter((t) => t.member !== memberId))); const members = this.transactionRepo.getTopTransactionsLive(orderBys, lastValue, memberId); - return combineLatest([all, members]).pipe( - map(([notForMember, forMember]) => - [...notForMember, ...forMember].sort((a, b) => { + return combineLatest([prevOwner, members]).pipe( + map((combined) => + combined.flat().sort((a, b) => { const aTime = a.createdOn?.toDate().getTime() || 0; const bTime = b.createdOn?.toDate().getTime() || 0; return -aTime + bTime; diff --git a/src/app/@api/milestone.api.ts b/src/app/@api/milestone.api.ts index c071097..6a1cbb9 100644 --- a/src/app/@api/milestone.api.ts +++ b/src/app/@api/milestone.api.ts @@ -1,13 +1,18 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Milestone, PublicCollections } from '@build-5/interfaces'; -import { BaseApi } from './base.api'; +import { BaseApi, SOON_ENV } from './base.api'; +import { MilestoneRepository } from '@build-5/lib'; @Injectable({ providedIn: 'root', }) export class MilestoneApi extends BaseApi { + protected milestoneRepo = new MilestoneRepository(SOON_ENV); + constructor(protected httpClient: HttpClient) { super(PublicCollections.MILESTONE, httpClient); } + + public getTopMilestonesLive = () => this.milestoneRepo.getTopMilestonesLive(); } diff --git a/src/app/@api/milestone_atoi.api.ts b/src/app/@api/milestone_atoi.api.ts deleted file mode 100644 index c0b7f0b..0000000 --- a/src/app/@api/milestone_atoi.api.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Milestone, PublicCollections } from '@build-5/interfaces'; -import { BaseApi } from './base.api'; - -@Injectable({ - providedIn: 'root', -}) -export class MilestoneAtoiApi extends BaseApi { - constructor(protected httpClient: HttpClient) { - super(PublicCollections.MILESTONE_ATOI, httpClient); - } -} diff --git a/src/app/@api/milestone_rms.api.ts b/src/app/@api/milestone_rms.api.ts deleted file mode 100644 index 1d5ff45..0000000 --- a/src/app/@api/milestone_rms.api.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Milestone, PublicCollections } from '@build-5/interfaces'; -import { BaseApi } from './base.api'; - -@Injectable({ - providedIn: 'root', -}) -export class MilestoneRmsApi extends BaseApi { - constructor(protected httpClient: HttpClient) { - super(PublicCollections.MILESTONE_RMS, httpClient); - } -} diff --git a/src/app/@api/milestone_smr.api.ts b/src/app/@api/milestone_smr.api.ts deleted file mode 100644 index 8e5053a..0000000 --- a/src/app/@api/milestone_smr.api.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { HttpClient } from '@angular/common/http'; -import { Injectable } from '@angular/core'; -import { Milestone, PublicCollections } from '@build-5/interfaces'; -import { BaseApi } from './base.api'; - -@Injectable({ - providedIn: 'root', -}) -export class MilestoneSmrApi extends BaseApi { - constructor(protected httpClient: HttpClient) { - super(PublicCollections.MILESTONE_SMR, httpClient); - } -} diff --git a/src/app/@api/order.api.ts b/src/app/@api/order.api.ts index a2b9660..a868e7e 100644 --- a/src/app/@api/order.api.ts +++ b/src/app/@api/order.api.ts @@ -8,7 +8,7 @@ import { WenRequest, } from '@build-5/interfaces'; import { TransactionRepository } from '@build-5/lib'; -import { Observable } from 'rxjs'; +import { Observable, of } from 'rxjs'; import { BaseApi, SOON_ENV } from './base.api'; @Injectable({ @@ -34,8 +34,10 @@ export class OrderApi extends BaseApi { this.request(WEN_FUNC.openBid, req); public listenMultiple = (ids: EthAddress[]) => - this.transactionRepo.getByFieldLive( - ids.map(() => 'uid'), - ids, - ); + ids.length + ? this.transactionRepo.getByFieldLive( + ids.map(() => 'uid'), + ids, + ) + : of([]); } diff --git a/src/app/@api/space.api.ts b/src/app/@api/space.api.ts index e44f662..45a32dd 100644 --- a/src/app/@api/space.api.ts +++ b/src/app/@api/space.api.ts @@ -1,7 +1,6 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { - Member, PublicCollections, QUERY_MAX_LENGTH, Space, @@ -61,14 +60,37 @@ export class SpaceApi extends BaseApi { public getMembersWithoutData = (spaceId: string, lastValue?: string) => this.spaceMemberRepo.getAll(spaceId, lastValue); - public listenMembers = (spaceId: string, lastValue?: string) => - this.spaceMemberRepo.getAllLive(spaceId, lastValue).pipe(switchMap(this.getMembers)); + public getAllMembersWithoutData = async (spaceId: string) => { + const members: SpaceMember[] = []; + let actMembers: SpaceMember[] = []; + do { + const last = members[members.length - 1]?.uid; + actMembers = await this.getMembersWithoutData(spaceId, last); + members.push(...actMembers); + } while (members.length === QUERY_MAX_LENGTH); + return members; + }; - public listenBlockedMembers = (spaceId: string, lastValue?: string) => - this.spaceBlockedRepo.getAllLive(spaceId, lastValue).pipe(switchMap(this.getMembers)); + public listenMembers = (spaceId: string, lastValue?: string, searchIds?: string[]) => { + const baseObs = searchIds?.length + ? this.spaceMemberRepo.getManyByIdLive(searchIds.slice(0, 100), spaceId) + : this.spaceMemberRepo.getAllLive(spaceId, lastValue); + return baseObs.pipe(switchMap(this.getMembers)); + }; - public listenPendingMembers = (spaceId: string, lastValue?: string) => - this.spaceKnockingRepo.getAllLive(spaceId, lastValue).pipe(switchMap(this.getMembers)); + public listenBlockedMembers = (spaceId: string, lastValue?: string, searchIds?: string[]) => { + const baseObs = searchIds?.length + ? this.spaceBlockedRepo.getManyByIdLive(searchIds.slice(0, 100), spaceId) + : this.spaceBlockedRepo.getAllLive(spaceId, lastValue); + return baseObs.pipe(switchMap(this.getMembers)); + }; + + public listenPendingMembers = (spaceId: string, lastValue?: string, searchIds?: string[]) => { + const baseObs = searchIds?.length + ? this.spaceKnockingRepo.getManyByIdLive(searchIds.slice(0, 100), spaceId) + : this.spaceKnockingRepo.getAllLive(spaceId, lastValue); + return baseObs.pipe(switchMap(this.getMembers)); + }; private getMembers = async (spaceMembers: SpaceMember[]) => { const uids = spaceMembers.map((m) => m.uid); diff --git a/src/app/@api/token.api.ts b/src/app/@api/token.api.ts index f0b31de..3bac963 100644 --- a/src/app/@api/token.api.ts +++ b/src/app/@api/token.api.ts @@ -2,6 +2,7 @@ import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { PublicCollections, + QUERY_MAX_LENGTH, Token, TokenDistribution, Transaction, @@ -9,7 +10,7 @@ import { WenRequest, } from '@build-5/interfaces'; import { TokenDistributionRepository, TokenRepository, TokenStatsRepository } from '@build-5/lib'; -import { Observable, of } from 'rxjs'; +import { Observable, firstValueFrom, lastValueFrom, of } from 'rxjs'; import { BaseApi, SOON_ENV } from './base.api'; @Injectable({ @@ -73,12 +74,33 @@ export class TokenApi extends BaseApi { return this.tokenDistributionRepo.getByIdLive(tokenId.toLowerCase(), memberId.toLowerCase()); } - public getDistributions(tokenId?: string): Observable { + public getDistributionsLive = (tokenId?: string, lastValue?: string) => + tokenId ? this.tokenDistributionRepo.getAllLive(tokenId.toLowerCase(), lastValue) : of([]); + + public getAllDistributions = async (tokenId?: string) => { if (!tokenId) { - return of(undefined); + return []; } - return this.tokenDistributionRepo.getAllLive(tokenId.toLowerCase()); - } + const distributions: TokenDistribution[] = []; + let actDistributions: TokenDistribution[] = []; + do { + const last = distributions[distributions.length - 1]?.uid; + actDistributions = await this.tokenDistributionRepo.getAll(tokenId.toLowerCase(), last); + distributions.push(...actDistributions); + } while (actDistributions.length === QUERY_MAX_LENGTH); + return distributions; + }; + + public getAllTokens = async () => { + const tokens: Token[] = []; + let actTokens: Token[] = []; + do { + const last = tokens[tokens.length - 1]?.uid; + actTokens = await this.tokenRepo.getByField('approved', true, last); + tokens.push(...actTokens); + } while (actTokens.length === QUERY_MAX_LENGTH); + return tokens; + }; public stats(tokenId: string) { if (!tokenId) { diff --git a/src/app/@shell/ui/sider/network-status/network-status.component.ts b/src/app/@shell/ui/sider/network-status/network-status.component.ts index 5218171..3be94c5 100644 --- a/src/app/@shell/ui/sider/network-status/network-status.component.ts +++ b/src/app/@shell/ui/sider/network-status/network-status.component.ts @@ -5,16 +5,13 @@ import { HostListener, OnInit, } from '@angular/core'; -import { MilestoneApi } from '@api/milestone.api'; -import { MilestoneAtoiApi } from '@api/milestone_atoi.api'; -import { MilestoneRmsApi } from '@api/milestone_rms.api'; -import { MilestoneSmrApi } from '@api/milestone_smr.api'; import { DeviceService } from '@core/services/device'; import { environment } from '@env/environment'; -import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; +import { UntilDestroy } from '@ngneat/until-destroy'; import { Milestone, Network, PROD_NETWORKS, TEST_NETWORKS } from '@build-5/interfaces'; import dayjs from 'dayjs'; -import { BehaviorSubject, map } from 'rxjs'; +import { BehaviorSubject } from 'rxjs'; +import { MilestoneApi } from '@api/milestone.api'; const ESCAPE_KEY = 'Escape'; @@ -50,52 +47,16 @@ export class NetworkStatusComponent implements OnInit { constructor( public deviceService: DeviceService, private milestoneApi: MilestoneApi, - private milestoneRmsApi: MilestoneRmsApi, - private milestoneSmrApi: MilestoneSmrApi, - private milestonreAtoiApi: MilestoneAtoiApi, private cd: ChangeDetectorRef, ) {} public ngOnInit(): void { - this.milestoneApi - .top(undefined, 1) - ?.pipe( - untilDestroyed(this), - map((o: Milestone[]) => { - return o[0]; - }), - ) - .subscribe(this.lastIotaMilestone$); - - this.milestoneRmsApi - .top(undefined, 1) - ?.pipe( - untilDestroyed(this), - map((o: Milestone[]) => { - return o[0]; - }), - ) - .subscribe(this.lastRmsMilestone$); - - this.milestonreAtoiApi - .top(undefined, 1) - ?.pipe( - untilDestroyed(this), - map((o: Milestone[]) => { - return o[0]; - }), - ) - .subscribe(this.lastAtoiMilestone$); - - this.milestoneSmrApi - .top(undefined, 1) - ?.pipe( - untilDestroyed(this), - map((o: Milestone[]) => { - return o[0]; - }), - ) - .subscribe(this.lastSmrMilestone$); + this.milestoneApi.getTopMilestonesLive().subscribe((milestones) => { + this.lastIotaMilestone$.next(milestones[Network.IOTA]); + this.lastAtoiMilestone$.next(milestones[Network.ATOI]); + this.lastSmrMilestone$.next(milestones[Network.SMR]); + this.lastRmsMilestone$.next(milestones[Network.RMS]); + }); } public isSmrEnabled(): boolean { diff --git a/src/app/components/auth/services/auth.service.ts b/src/app/components/auth/services/auth.service.ts index 83a1f18..7c8ff10 100644 --- a/src/app/components/auth/services/auth.service.ts +++ b/src/app/components/auth/services/auth.service.ts @@ -413,10 +413,14 @@ export class AuthService { } public monitorMember(address: EthAddress): void { - this.memberSubscription$ = this.memberApi.listen(address).subscribe(this.member$); + this.memberSubscription$ = this.memberApi.listen(address).subscribe((v) => { + this.member$.next(v); + }); this.memberStakingSubscription$ = this.memberApi .soonDistributionStats(address) - .subscribe(this.memberSoonDistribution$); + .subscribe((v) => { + this.memberSoonDistribution$.next(v); + }); } public toHex(stringToConvert: string) { diff --git a/src/app/components/nft/components/nft-sale/nft-sale.component.ts b/src/app/components/nft/components/nft-sale/nft-sale.component.ts index afc0449..a31f360 100644 --- a/src/app/components/nft/components/nft-sale/nft-sale.component.ts +++ b/src/app/components/nft/components/nft-sale/nft-sale.component.ts @@ -50,6 +50,11 @@ export class NftSaleComponent { @Input() set nft(value: Nft | null | undefined) { + // If it's same NFT, we can ignore as we don't want to overwrite users value. + if (this._nft?.uid === value?.uid) { + return; + } + this._nft = value; if (this._nft) { this.fileApi diff --git a/src/app/components/proposal/components/proposal-status/proposal-status.component.ts b/src/app/components/proposal/components/proposal-status/proposal-status.component.ts index fa90ca6..7365364 100644 --- a/src/app/components/proposal/components/proposal-status/proposal-status.component.ts +++ b/src/app/components/proposal/components/proposal-status/proposal-status.component.ts @@ -45,7 +45,7 @@ export class ProposalStatusComponent implements OnInit { } public isComplete(): boolean { - if (!this.proposal) { + if (!this.proposal || !this.proposal.settings?.endDate) { return false; } diff --git a/src/app/components/token/components/token-info/token-info-description.component.ts b/src/app/components/token/components/token-info/token-info-description.component.ts index 84d627a..b038b96 100644 --- a/src/app/components/token/components/token-info/token-info-description.component.ts +++ b/src/app/components/token/components/token-info/token-info-description.component.ts @@ -7,7 +7,7 @@ import { download } from '@core/utils/tools.utils'; import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { DataService } from '@pages/token/services/data.service'; import { HelperService } from '@pages/token/services/helper.service'; -import { Token } from '@build-5/interfaces'; +import { QUERY_MAX_LENGTH, Token, TokenDistribution } from '@build-5/interfaces'; import Papa from 'papaparse'; import { debounceTime } from 'rxjs'; @@ -46,46 +46,43 @@ export class TokenInfoDescriptionComponent { return DescriptionItemType; } - public downloadCurrentDistribution(): void { - this.tokenApi - .getDistributions(this.token?.uid) - .pipe(debounceTime(2500), untilDestroyed(this)) - .subscribe((distributions) => { - const fields = [ - '', - 'ethAddress', - 'tokenOwned', - 'unclaimedTokens', - 'tokenClaimed', - 'lockedForSale', - 'sold', - 'totalBought', - 'refundedAmount', - 'totalPaid', - 'totalDeposit', - ]; - const csv = Papa.unparse({ - fields, - data: - distributions?.map((d) => [ - d.uid, - d.tokenOwned, - d.totalUnclaimedAirdrop || 0, - d.tokenClaimed, - d.lockedForSale, - d.sold, - d.totalBought, - d.refundedAmount, - d.totalPaid, - d.totalDeposit, - ]) || [], - }); + public async downloadCurrentDistribution(): Promise { + const distributions = await this.tokenApi.getAllDistributions(this.token?.uid); + const fields = [ + '', + 'ethAddress', + 'tokenOwned', + 'unclaimedTokens', + 'tokenClaimed', + 'lockedForSale', + 'sold', + 'totalBought', + 'refundedAmount', + 'totalPaid', + 'totalDeposit', + ]; - download( - `data:text/csv;charset=utf-8${csv}`, - `soonaverse_${this.token?.symbol}_distribution.csv`, - ); - this.cd.markForCheck(); - }); + const csv = Papa.unparse({ + fields, + data: + distributions?.map((d) => [ + d.uid, + d.tokenOwned, + d.totalUnclaimedAirdrop || 0, + d.tokenClaimed, + d.lockedForSale, + d.sold, + d.totalBought, + d.refundedAmount, + d.totalPaid, + d.totalDeposit, + ]) || [], + }); + + download( + `data:text/csv;charset=utf-8${csv}`, + `soonaverse_${this.token?.symbol}_distribution.csv`, + ); + this.cd.markForCheck(); } } diff --git a/src/app/components/token/components/token-vote/token-vote.component.ts b/src/app/components/token/components/token-vote/token-vote.component.ts index a487d1f..75f8d71 100644 --- a/src/app/components/token/components/token-vote/token-vote.component.ts +++ b/src/app/components/token/components/token-vote/token-vote.component.ts @@ -354,7 +354,7 @@ export class TokenVoteComponent implements OnInit, OnDestroy { } const params: any = { uid: this.proposal.uid, - values: [this.answer.value], + value: this.answer.value, }; if (this.voteTypeControl.value === VoteType.NATIVE_TOKEN) { diff --git a/src/app/pages/award/pages/new/new.page.ts b/src/app/pages/award/pages/new/new.page.ts index 17b075b..9904e57 100644 --- a/src/app/pages/award/pages/new/new.page.ts +++ b/src/app/pages/award/pages/new/new.page.ts @@ -142,21 +142,17 @@ export class NewPage implements OnInit, OnDestroy { } }); - this.subscriptions$.push( - this.tokenApi - .top(undefined, 1) - .pipe( - map((tokens) => { - return tokens?.filter((t) => { - return ( - TEST_AVAILABLE_MINTABLE_NETWORKS.indexOf(t.mintingData?.network) > -1 || - t.status === TokenStatus.BASE - ); - }); - }), - ) - .subscribe(this.tokens$), - ); + this.tokenApi.getAllTokens().then((tokens) => { + this.tokens$.next( + tokens?.filter((t) => { + return ( + (TEST_AVAILABLE_MINTABLE_NETWORKS.indexOf(t.mintingData?.network) > -1 || + t.status === TokenStatus.BASE) && + t.approved + ); + }), + ); + }); } public trackByUid(index: number, item: any): number { diff --git a/src/app/pages/member/pages/activity/activity.page.ts b/src/app/pages/member/pages/activity/activity.page.ts index e2d832f..2df3e41 100644 --- a/src/app/pages/member/pages/activity/activity.page.ts +++ b/src/app/pages/member/pages/activity/activity.page.ts @@ -27,6 +27,7 @@ import dayjs from 'dayjs'; import { BehaviorSubject, map, Observable } from 'rxjs'; import { CacheService } from './../../../../@core/services/cache/cache.service'; import { DataService, MemberAction } from './../../services/data.service'; +import { ActivatedRoute } from '@angular/router'; @UntilDestroy() @Component({ @@ -56,6 +57,7 @@ export class ActivityPage implements OnInit { public helper: HelperService, public cache: CacheService, public deviceService: DeviceService, + private route: ActivatedRoute, public previewImageService: PreviewImageService, private cd: ChangeDetectorRef, ) { @@ -63,17 +65,19 @@ export class ActivityPage implements OnInit { } public ngOnInit(): void { - this.tokenApi - .listen(environment.production ? SOON_TOKEN : SOON_TOKEN_TEST) - .pipe(untilDestroyed(this)) - .subscribe(this.token$); - - let prev: string | undefined; - this.data.member$?.pipe(untilDestroyed(this)).subscribe((obj) => { - if (prev !== obj?.uid) { - this.data.refreshBadges(); - prev = obj?.uid; - } + this.route.params.subscribe(() => { + this.tokenApi + .listen(environment.production ? SOON_TOKEN : SOON_TOKEN_TEST) + .pipe(untilDestroyed(this)) + .subscribe(this.token$); + + let prev: string | undefined; + this.data.member$?.pipe(untilDestroyed(this)).subscribe((obj) => { + if (prev !== obj?.uid) { + this.data.refreshBadges(); + prev = obj?.uid; + } + }); }); } @@ -94,7 +98,7 @@ export class ActivityPage implements OnInit { public getTotalStaked(): Observable { return this.auth.memberSoonDistribution$.pipe( map((v) => { - return v?.stakes?.[StakeType.DYNAMIC].amount || 0; + return v?.stakes?.[StakeType.DYNAMIC]?.amount || 0; }), ); } @@ -102,7 +106,7 @@ export class ActivityPage implements OnInit { public getTotalStakedValue(): Observable { return this.auth.memberSoonDistribution$.pipe( map((v) => { - return v?.stakes?.[StakeType.DYNAMIC].value || 0; + return v?.stakes?.[StakeType.DYNAMIC]?.value || 0; }), ); } diff --git a/src/app/pages/member/pages/member/member.page.ts b/src/app/pages/member/pages/member/member.page.ts index 27cf90b..6043451 100644 --- a/src/app/pages/member/pages/member/member.page.ts +++ b/src/app/pages/member/pages/member/member.page.ts @@ -121,7 +121,13 @@ export class MemberPage implements OnInit, OnDestroy { this.memberApi.topSpaces(memberId).pipe(untilDestroyed(this)).subscribe(this.data.space$), ); this.subscriptions$.push( - this.memberApi.listen(memberId).pipe(untilDestroyed(this)).subscribe(this.data.member$), + this.memberApi + .listen(memberId) + .pipe(untilDestroyed(this)) + .subscribe((v) => { + // Only pass next stage. + this.data.member$.next(v); + }), ); // Badges. diff --git a/src/app/pages/member/pages/nfts/nfts.page.ts b/src/app/pages/member/pages/nfts/nfts.page.ts index aea02c7..3d76ac3 100644 --- a/src/app/pages/member/pages/nfts/nfts.page.ts +++ b/src/app/pages/member/pages/nfts/nfts.page.ts @@ -45,29 +45,29 @@ export class NFTsPage implements OnInit { this.isDepositNftVisible = true; this.cd.markForCheck(); } - }); - this.data.member$.pipe(untilDestroyed(this)).subscribe((m) => { - if (m) { - this.filterStorageService.memberNftsFitlers$.next({ - sortBy: 'nft_soldOn_desc', - refinementList: { - ...this.filterStorageService.memberNftsFitlers$.value.refinementList, - owner: [m.uid], - }, - }); + this.data.member$.pipe(untilDestroyed(this)).subscribe((m) => { + if (m) { + this.filterStorageService.memberNftsFitlers$.next({ + sortBy: 'nft_soldOn_desc', + refinementList: { + ...this.filterStorageService.memberNftsFitlers$.value.refinementList, + owner: [m.uid], + }, + }); - this.config = { - indexName: COL.NFT, - searchClient: this.algoliaService.searchClient, - initialUiState: { - nft: this.filterStorageService.memberNftsFitlers$.value, - }, - }; + this.config = { + indexName: COL.NFT, + searchClient: this.algoliaService.searchClient, + initialUiState: { + nft: this.filterStorageService.memberNftsFitlers$.value, + }, + }; - // Algolia change detection bug fix - setInterval(() => this.cd.markForCheck(), 200); - } + // Algolia change detection bug fix + setInterval(() => this.cd.markForCheck(), 200); + } + }); }); } diff --git a/src/app/pages/member/pages/spaces/member-spaces.component.ts b/src/app/pages/member/pages/spaces/member-spaces.component.ts index 938ccdc..af34481 100644 --- a/src/app/pages/member/pages/spaces/member-spaces.component.ts +++ b/src/app/pages/member/pages/spaces/member-spaces.component.ts @@ -5,6 +5,7 @@ import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'; import { DataService } from '@pages/member/services/data.service'; import { HelperService } from '@pages/member/services/helper.service'; import { Space } from '@build-5/interfaces'; +import { ActivatedRoute } from '@angular/router'; @UntilDestroy() @Component({ @@ -23,6 +24,7 @@ export class MemberSpacesComponent implements OnInit { public data: DataService, public helper: HelperService, public deviceService: DeviceService, + private route: ActivatedRoute, ) { this.spaceForm = new FormGroup({ space: new FormControl(''), @@ -31,9 +33,13 @@ export class MemberSpacesComponent implements OnInit { } ngOnInit(): void { - this.spaceForm.controls.space.valueChanges - .pipe(untilDestroyed(this)) - .subscribe(this.onSearchValueChange.bind(this)); + this.route.params.subscribe(() => { + this.spaceForm.controls.space.valueChanges + .pipe(untilDestroyed(this)) + .subscribe(this.onSearchValueChange.bind(this)); + + this.onSearchValueChange(); + }); } public onSearchValueChange(): void { diff --git a/src/app/pages/member/pages/tokens/tokens.page.html b/src/app/pages/member/pages/tokens/tokens.page.html index 0f25ecf..ac49545 100644 --- a/src/app/pages/member/pages/tokens/tokens.page.html +++ b/src/app/pages/member/pages/tokens/tokens.page.html @@ -356,7 +356,7 @@ {{ t.type | uppercase }} {{ t.createdOn?.toDate() | date:'short' }} - {{ t.expiresAt?.toDate() | date:'short' }} + {{ t.expiresAt.toDate() | date:'short' }} {{ (t.amount | formatToken: t.tokenRec.uid:true:false | async) + ' ' + t.tokenRec.symbol }} @@ -438,7 +438,7 @@
{{ t.createdOn?.toDate() | date:'short' }} - - {{ t.expiresAt?.toDate() | date:'short' }} + - {{ t.expiresAt.toDate() | date:'short' }}
diff --git a/src/app/pages/member/pages/tokens/tokens.page.ts b/src/app/pages/member/pages/tokens/tokens.page.ts index 42da339..6a13fe8 100644 --- a/src/app/pages/member/pages/tokens/tokens.page.ts +++ b/src/app/pages/member/pages/tokens/tokens.page.ts @@ -131,14 +131,14 @@ export class TokensPage implements OnInit, OnDestroy { if (obj?.tab === 'staking') { this.handleFilterChange(FilterOptions.STAKING); } - }); - this.data.member$?.pipe(untilDestroyed(this)).subscribe((obj) => { - if (obj) { - this.listen(); - } + this.data.member$?.pipe(untilDestroyed(this)).subscribe((obj) => { + if (obj) { + this.listen(); + } + }); + this.handleNotMintedWarning(); }); - this.handleNotMintedWarning(); } public handleFilterChange(filter: FilterOptions): void { diff --git a/src/app/pages/member/pages/transactions/transactions.page.ts b/src/app/pages/member/pages/transactions/transactions.page.ts index 3da8ef6..dd547e2 100644 --- a/src/app/pages/member/pages/transactions/transactions.page.ts +++ b/src/app/pages/member/pages/transactions/transactions.page.ts @@ -54,12 +54,12 @@ export class TransactionsPage implements OnInit, OnDestroy { this.exportTransactions(); this.cd.markForCheck(); } - }); - this.data.member$?.pipe(untilDestroyed(this)).subscribe((obj) => { - if (obj) { - this.listen(); - } + this.data.member$?.pipe(untilDestroyed(this)).subscribe((obj) => { + if (obj) { + this.listen(); + } + }); }); } diff --git a/src/app/pages/proposal/pages/overview/overview.page.ts b/src/app/pages/proposal/pages/overview/overview.page.ts index 16447d3..4027206 100644 --- a/src/app/pages/proposal/pages/overview/overview.page.ts +++ b/src/app/pages/proposal/pages/overview/overview.page.ts @@ -112,23 +112,21 @@ export class OverviewPage implements OnInit { return; } - if (!(this.voteControl.value > -1)) { + if (!this.voteControl.value || !(this.voteControl.value > -1)) { this.nzNotification.error('', 'Please select option first!'); return; } - await this.auth.sign( - { - uid: this.data.proposal$.value.uid, - values: [this.voteControl.value], - }, - (sc, finish) => { - this.notification - .processRequest(this.proposalApi.vote(sc), 'Voted.', finish) - .subscribe(() => { - // none. - }); - }, - ); + const params = { + uid: this.data.proposal$.value.uid, + value: this.voteControl.value, + }; + await this.auth.sign(params, (sc, finish) => { + this.notification + .processRequest(this.proposalApi.vote(sc), 'Voted.', finish) + .subscribe(() => { + // none. + }); + }); } } diff --git a/src/app/pages/proposal/pages/proposal/proposal.page.ts b/src/app/pages/proposal/pages/proposal/proposal.page.ts index 319cba2..9fcf168 100644 --- a/src/app/pages/proposal/pages/proposal/proposal.page.ts +++ b/src/app/pages/proposal/pages/proposal/proposal.page.ts @@ -145,7 +145,7 @@ export class ProposalPage implements OnInit, OnDestroy { // Get badges to show. const awards: Award[] = []; - if (p.settings.awards?.length) { + if (p.settings?.awards?.length) { for (const a of p.settings.awards) { const award: Award | undefined = await firstValueFrom(this.awardApi.listen(a)); if (award) { diff --git a/src/app/pages/proposal/services/helper.service.ts b/src/app/pages/proposal/services/helper.service.ts index 3792189..801bcf4 100644 --- a/src/app/pages/proposal/services/helper.service.ts +++ b/src/app/pages/proposal/services/helper.service.ts @@ -61,7 +61,7 @@ export class HelperService { } public isComplete(proposal?: Proposal | null): boolean { - if (!proposal) { + if (!proposal || !proposal.settings?.endDate) { return false; } diff --git a/src/app/pages/space/pages/members/members.page.ts b/src/app/pages/space/pages/members/members.page.ts index 9dfb3f7..124820e 100644 --- a/src/app/pages/space/pages/members/members.page.ts +++ b/src/app/pages/space/pages/members/members.page.ts @@ -103,18 +103,16 @@ export class MembersPage implements OnInit, OnDestroy { this.overTenRecords = false; if (val && val.length > 0) { from( - this.algoliaService.searchClient - .initIndex(COL.MEMBER) - .search(val || '', { length: 5, offset: 0 }), + this.algoliaService.searchClient.initIndex(COL.MEMBER).search(val || '', { + facetFilters: [`spaces.${this.spaceId}.uid:${this.spaceId}`], + attributesToRetrieve: [], + length: 20, + offset: 0, + }), ) .pipe(first()) .subscribe((r) => { - const ids: string[] = r.hits.map((r) => { - const member = r as unknown as Member; - return member.uid; - }); - - // Top 10 records only supported + const ids = r.hits.map((r) => r.objectID); this.overTenRecords = ids.length > 10; this.onScroll(ids.slice(0, 10)); }); diff --git a/src/app/pages/space/pages/space/space-about/space-about.component.html b/src/app/pages/space/pages/space/space-about/space-about.component.html index c8f9b8b..e1ff5a5 100644 --- a/src/app/pages/space/pages/space/space-about/space-about.component.html +++ b/src/app/pages/space/pages/space/space-about/space-about.component.html @@ -276,7 +276,7 @@

{{ (data.space$ | async)?.name }}

[nzSize]="(deviceService.isDesktop$ | async) ? 'default' : 32" > - @{{ g.name || g.uid | truncate : [16] }} diff --git a/src/app/pages/space/pages/space/space-about/space-about.component.ts b/src/app/pages/space/pages/space/space-about/space-about.component.ts index 3fc1745..28c8e3f 100644 --- a/src/app/pages/space/pages/space/space-about/space-about.component.ts +++ b/src/app/pages/space/pages/space/space-about/space-about.component.ts @@ -135,24 +135,16 @@ export class SpaceAboutComponent implements OnInit, OnDestroy { } this.exportingMembers = true; - const data: string[][] = []; - let members: SpaceMember[] = []; - do { - const last = data[data.length - 1]?.[0]; - members = await this.spaceApi.getMembersWithoutData(space.uid, last); - data.push(...members.map((m) => [m.uid])); - if (members.length < QUERY_MAX_LENGTH) { - break; - } - } while (members.length); + const members = await this.spaceApi.getAllMembersWithoutData(space.uid); - this.exportingMembers = false; const fields = ['', 'address']; - const csv = Papa.unparse({ fields, data }); + const csv = Papa.unparse({ fields, data: members.map((m) => [m.uid]) }); const filteredSpaceName = space?.name?.toLowerCase().replace(/[^a-zA-Z0-9-_]/g, ''); download(`data:text/csv;charset=utf-8${csv}`, `soonaverse_${filteredSpaceName}_members.csv`); this.cd.markForCheck(); + + this.exportingMembers = false; } public isSoonSpace(): Observable { diff --git a/src/app/pages/space/pages/space/space.page.html b/src/app/pages/space/pages/space/space.page.html index c7fa968..f9d172a 100644 --- a/src/app/pages/space/pages/space/space.page.html +++ b/src/app/pages/space/pages/space/space.page.html @@ -50,7 +50,7 @@

{{ (data.space$ | async)!.name }}

nzBlock nzSize="large" i18n - *ngIf="(data.isMemberWithinSpace$ | async) === false && (member$ | async) && ((data.space$ | async)!.open === true || ((data.space$ | async)!.tokenBased && (userStakedEnoughToJoin$() | async)))" + *ngIf="(data.isMemberWithinSpace$ | async) === false && (member$ | async) && ((data.space$ | async)?.open === true || ((data.space$ | async)!.tokenBased && (userStakedEnoughToJoin$() | async)))" > Join Space @@ -62,7 +62,7 @@

{{ (data.space$ | async)!.name }}

nzBlock nzSize="large" [disabled]="(data.isPendingMemberWithSpace$ | async) === true" - *ngIf="(data.isMemberWithinSpace$ | async) === false && (member$ | async) && (data.space$ | async)!.open !== true && !(data.space$ | async)!.tokenBased" + *ngIf="(data.isMemberWithinSpace$ | async) === false && (member$ | async) && (data.space$ | async)?.open !== true && !(data.space$ | async)!.tokenBased" > Pending Request{{ (data.space$ | async)!.name }} nzBlock nzSize="large" i18n - *ngIf="(data.isMemberWithinSpace$ | async) === false && (member$ | async) && ((data.space$ | async)!.open === true || ((data.space$ | async)!.tokenBased && (userStakedEnoughToJoin$() | async)))" + *ngIf="(data.isMemberWithinSpace$ | async) === false && (member$ | async) && ((data.space$ | async)?.open === true || ((data.space$ | async)!.tokenBased && (userStakedEnoughToJoin$() | async)))" > Join Space @@ -125,7 +125,7 @@

{{ (data.space$ | async)!.name }}

nzBlock nzSize="large" [disabled]="(data.isPendingMemberWithSpace$ | async) === true" - *ngIf="(data.isMemberWithinSpace$ | async) === false && (member$ | async) && (data.space$ | async)!.open !== true && !(data.space$ | async)!.tokenBased" + *ngIf="(data.isMemberWithinSpace$ | async) === false && (member$ | async) && (data.space$ | async)?.open !== true && !(data.space$ | async)!.tokenBased" > Pending Request { if (this.exportingCurrentStakers) { return; } this.exportingCurrentStakers = true; - this.tokenApi - .getDistributions(token) - .pipe(debounceTime(2500), untilDestroyed(this)) - .subscribe((transactions: TokenDistribution[] | undefined) => { - if (!transactions) { - return; - } + const distributions = await this.tokenApi.getAllDistributions(token); - this.exportingCurrentStakers = false; - const fields = [ - '', - 'memberId', - 'tokenStakedDynamic', - 'tokenStakedStatic', - 'stakedValueDynamic', - 'stakedValueStatic', - 'totalStakeRewards', - ]; - const csv = Papa.unparse({ - fields, - data: transactions.map((t) => [ - t.uid, - t.stakes?.[StakeType.DYNAMIC]?.amount || 0, - t.stakes?.[StakeType.STATIC]?.amount || 0, - t.stakes?.[StakeType.DYNAMIC]?.value || 0, - t.stakes?.[StakeType.STATIC]?.value || 0, - t.stakeRewards || 0, - ]), - }); + const fields = [ + '', + 'memberId', + 'tokenStakedDynamic', + 'tokenStakedStatic', + 'stakedValueDynamic', + 'stakedValueStatic', + 'totalStakeRewards', + ]; + const csv = Papa.unparse({ + fields, + data: distributions.map((t) => [ + t.uid, + t.stakes?.[StakeType.DYNAMIC]?.amount || 0, + t.stakes?.[StakeType.STATIC]?.amount || 0, + t.stakes?.[StakeType.DYNAMIC]?.value || 0, + t.stakes?.[StakeType.STATIC]?.value || 0, + t.stakeRewards || 0, + ]), + }); - download(`data:text/csv;charset=utf-8${csv}`, `soonaverse_${token}_stakers.csv`); - this.cd.markForCheck(); - }); + download(`data:text/csv;charset=utf-8${csv}`, `soonaverse_${token}_stakers.csv`); + this.cd.markForCheck(); + + this.exportingCurrentStakers = false; } public get bannerUrl$(): Observable { diff --git a/src/app/pages/space/services/data.service.ts b/src/app/pages/space/services/data.service.ts index 618b80d..542ad9e 100644 --- a/src/app/pages/space/services/data.service.ts +++ b/src/app/pages/space/services/data.service.ts @@ -317,28 +317,24 @@ export class DataService implements OnDestroy { ); } - public isLoading(arr: any): boolean { - return arr === undefined; - } + public isLoading = (arr: unknown) => arr === undefined; - public isEmpty(arr: any): boolean { - return Array.isArray(arr) && arr.length === 0; - } + public isEmpty = (arr: unknown) => Array.isArray(arr) && !arr.length; - public listenMembers(spaceId: string, lastValue?: string): void { + public listenMembers(spaceId: string, lastValue?: string, searchIds?: string[]): void { this.subscriptions$.push( this.spaceApi - .listenMembers(spaceId, lastValue) + .listenMembers(spaceId, lastValue, searchIds) .subscribe( this.store.bind(this, this.members$, this.dataStoreMembers, this.dataStoreMembers.length), ), ); } - public listenBlockedMembers(spaceId: string, lastValue?: string): void { + public listenBlockedMembers(spaceId: string, lastValue?: string, searchIds?: string[]): void { this.subscriptions$.push( this.spaceApi - .listenBlockedMembers(spaceId, lastValue) + .listenBlockedMembers(spaceId, lastValue, searchIds) .subscribe( this.store.bind( this, @@ -350,10 +346,10 @@ export class DataService implements OnDestroy { ); } - public listenPendingMembers(spaceId: string, lastValue?: any): void { + public listenPendingMembers(spaceId: string, lastValue?: string, searchIds?: string[]): void { this.subscriptions$.push( this.spaceApi - .listenPendingMembers(spaceId, lastValue) + .listenPendingMembers(spaceId, lastValue, searchIds) .subscribe( this.store.bind( this, @@ -409,8 +405,8 @@ export class DataService implements OnDestroy { } // For initial load stream will not be defiend. - const lastValue = stream ? stream[stream.length - 1].createdOn : undefined; - handler.call(this, spaceId, lastValue); + const lastValue = stream ? stream[stream.length - 1].uid : undefined; + handler.call(this, spaceId, lastValue, searchIds); } public getPendingMembersCount(members?: Member[] | null): number { diff --git a/src/app/pages/token/pages/token/token.page.ts b/src/app/pages/token/pages/token/token.page.ts index 52facd6..32ba089 100644 --- a/src/app/pages/token/pages/token/token.page.ts +++ b/src/app/pages/token/pages/token/token.page.ts @@ -106,7 +106,7 @@ export class TokenPage implements OnInit, OnDestroy { ); this.subscriptions$.push( this.tokenApi - .getDistributions(t.uid) + .getDistributionsLive(t.uid) .pipe(debounceTime(2500), untilDestroyed(this)) .subscribe(this.data.distributions$), );