Skip to content

Commit

Permalink
feat: basic fellowship redesign according last available mockups
Browse files Browse the repository at this point in the history
  • Loading branch information
johnthecat committed Jan 24, 2025
1 parent 0105593 commit 2248735
Show file tree
Hide file tree
Showing 58 changed files with 458 additions and 223 deletions.
9 changes: 9 additions & 0 deletions src/renderer/app/bootstrap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@ import { assetsNavigationFeature } from '@/features/assets-navigation';
import { basketNavigationFeature } from '@/features/basket-navigation';
import { contactsNavigationFeature } from '@/features/contacts-navigation';
import { extensionWalletFeature } from '@/features/extension-wallet';
import { fellowshipEvidenceFeature } from '@/features/fellowship-evidence';
import { fellowshipMembersFeature } from '@/features/fellowship-members';
import { fellowshipNavigationFeature } from '@/features/fellowship-navigation';
import { fellowshipProfileFeature } from '@/features/fellowship-profile';
import { fellowshipSalaryFeature } from '@/features/fellowship-salary';
import { flexibleMultisigNavigationFeature } from '@/features/flexible-multisig-navigation';
import { governanceNavigationFeature } from '@/features/governance-navigation';
import { governanceOperationDetailFeature } from '@/features/governance-operation-details';
Expand Down Expand Up @@ -96,6 +100,11 @@ export const bootstrap = () => {
settingsNavigationFeature,
flexibleMultisigNavigationFeature,

fellowshipSalaryFeature,
fellowshipEvidenceFeature,
fellowshipProfileFeature,
fellowshipMembersFeature,

walletSelectFeature.feature,
walletDetailsFeature,

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { memo } from 'react';

import { useI18n } from '@/shared/i18n';
import { Icon } from '@/shared/ui';
import { Box } from '@/shared/ui-kit';

export const EvidenceCard = memo(() => {
const { t } = useI18n();

return (
<button className="rounded-xl border border-filter-border bg-card-background text-button-small">
<Box direction="row" verticalAlign="center" horizontalAlign="space-between" gap={2} padding={4}>
<Box direction="row" verticalAlign="center" gap={2}>
<Icon name="whitelistVoting" size={16} />

{t('fellowship.evidence.cardTitle')}
</Box>

<Icon name="right" size={16} />
</Box>
</button>
);
});
3 changes: 3 additions & 0 deletions src/renderer/features/fellowship-evidence/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const ERROR = {
networkDisabled: 'Network disabled',
};
11 changes: 11 additions & 0 deletions src/renderer/features/fellowship-evidence/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { fellowshipHeaderCardsSlot } from '@/pages/Fellowship/ui/Fellowship';

import { EvidenceCard } from './components/EvidenceCard';
import { fellowshipEvidenceFeature } from './model/feature';

export { fellowshipEvidenceFeature };

fellowshipEvidenceFeature.inject(fellowshipHeaderCardsSlot, {
order: 1,
render: () => <EvidenceCard />,
});
49 changes: 49 additions & 0 deletions src/renderer/features/fellowship-evidence/model/feature.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { combine, sample } from 'effector';

import { $features } from '@/shared/config/features';
import { createFeature } from '@/shared/feature';
import { isDev, nullable } from '@/shared/lib/utils';
import { accountsService } from '@/domains/network';
import { walletModel } from '@/entities/wallet';
import { fellowshipNetworkFeature } from '@/features/fellowship-network';
import { ERROR } from '../constants';

const $input = combine(
{
network: fellowshipNetworkFeature.model.network.$network,
accounts: walletModel.$availableAccounts,
},
({ network, accounts }) => {
if (nullable(network)) return null;

return {
api: network.api,
asset: network.asset,
chain: network.chain,
chainId: network.chainId,
palletType: network.palletType,
accounts: accountsService.filterAccountOnChain(accounts, network.chain),
};
},
);

export const fellowshipEvidenceFeature = createFeature({
name: 'fellowship/evidence',
enable: $features.map(({ fellowship }) => fellowship && isDev()),
input: $input,
filter: input => {
return input.api.isConnected
? null
: {
status: 'failed',
type: 'warning',
error: new Error(ERROR.networkDisabled),
};
},
});

sample({
clock: fellowshipNetworkFeature.model.network.$isActive,
filter: fellowshipNetworkFeature.model.network.$isActive,
target: fellowshipEvidenceFeature.restore,
});
20 changes: 20 additions & 0 deletions src/renderer/features/fellowship-evidence/model/fellowship.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { combine } from 'effector';

import { nullable } from '@/shared/lib/utils';
import { collectiveDomain } from '@/domains/collectives';

import { fellowshipEvidenceFeature } from './feature';

const $fellowshipStore = collectiveDomain.$store.map(store => store['fellowship'] || null);

const $store = combine($fellowshipStore, fellowshipEvidenceFeature.state, (fellowshipStore, state) => {
if (nullable(fellowshipStore) || state.status !== 'running') {
return null;
}

return fellowshipStore[state.data.chainId] ?? null;
});

export const fellowshipModel = {
$store,
};
42 changes: 16 additions & 26 deletions src/renderer/features/fellowship-members/components/MembersCard.tsx
Original file line number Diff line number Diff line change
@@ -1,45 +1,35 @@
import { useGate, useUnit } from 'effector-react';
import { useUnit } from 'effector-react';
import { memo } from 'react';

import { useI18n } from '@/shared/i18n';
import { FootnoteText, Icon, SmallTitleText } from '@/shared/ui';
import { Box, Skeleton, Surface } from '@/shared/ui-kit';
import { Icon } from '@/shared/ui';
import { Box, Skeleton } from '@/shared/ui-kit';
import { ERROR } from '../constants';
import { fellowshipMembersFeature } from '../model/feature';
import { membersModel } from '../model/members';
import { membersFeatureStatus } from '../model/status';

import { MembersModal } from './MembersModal';

type Props = {
// TODO replace with internal modal openning
onClick: () => void;
};

export const MembersCard = memo<Props>(({ onClick }) => {
useGate(membersFeatureStatus.gate);

export const MembersCard = memo(() => {
const { t } = useI18n();

const featureState = useUnit(membersFeatureStatus.state);
const featureState = useUnit(fellowshipMembersFeature.state);
const [members, pending, fulfilled] = useUnit([membersModel.$list, membersModel.$pending, membersModel.$fulfilled]);
const isNetworkDisabled = featureState.status === 'failed' && featureState.error.message === ERROR.networkDisabled;

return (
<MembersModal>
<Surface as="button" disabled={pending || isNetworkDisabled} onClick={onClick}>
<Box direction="row" verticalAlign="center" horizontalAlign="space-between" padding={[6, 4]}>
<Box gap={2}>
<Box direction="row" gap={1}>
<Icon name="members" size={16} />
<FootnoteText className="text-text-secondary">{t('fellowship.members.cardTitle')}</FootnoteText>
</Box>
<Skeleton active={pending && !fulfilled && !isNetworkDisabled}>
<SmallTitleText>{t('fellowship.fellow', { count: members.length })}</SmallTitleText>
</Skeleton>
</Box>
<Icon name="arrowRight" />
<button
className="rounded-xl border border-filter-border bg-card-background text-button-small"
disabled={pending || isNetworkDisabled}
>
<Box direction="row" verticalAlign="center" horizontalAlign="space-between" padding={4} gap={2}>
<Skeleton active={pending && !fulfilled && !isNetworkDisabled}>
{t('fellowship.fellow', { count: members.length })}
</Skeleton>
<Icon name="right" size={16} />
</Box>
</Surface>
</button>
</MembersModal>
);
});
Original file line number Diff line number Diff line change
@@ -1,27 +1,25 @@
import { useGate, useUnit } from 'effector-react';
import { useUnit } from 'effector-react';
import { type PropsWithChildren, useDeferredValue, useMemo, useState } from 'react';

import { useI18n } from '@/shared/i18n';
import { nonNullable, performSearch, toAddress } from '@/shared/lib/utils';
import { FootnoteText } from '@/shared/ui';
import { Box, Modal, ScrollArea, SearchInput } from '@/shared/ui-kit';
import { fellowshipMembersFeature } from '../model/feature';
import { identityModel } from '../model/identity';
import { membersModel } from '../model/members';
import { membersFeatureStatus } from '../model/status';

import { Member } from './Member';
import { MembersListEmptyState } from './MembersListEmptyState';

export const MembersModal = ({ children }: PropsWithChildren) => {
useGate(membersFeatureStatus.gate);

const { t } = useI18n();
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);

const members = useUnit(membersModel.$list);
const identities = useUnit(identityModel.$identity);
const input = useUnit(membersFeatureStatus.input);
const input = useUnit(fellowshipMembersFeature.input);

const chain = input?.chain ?? null;

Expand Down
11 changes: 0 additions & 11 deletions src/renderer/features/fellowship-members/index.ts

This file was deleted.

11 changes: 11 additions & 0 deletions src/renderer/features/fellowship-members/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { fellowshipHeaderCardsSlot } from '@/pages/Fellowship/ui/Fellowship';

import { MembersCard } from './components/MembersCard';
import { fellowshipMembersFeature } from './model/feature';

export { fellowshipMembersFeature };

fellowshipMembersFeature.inject(fellowshipHeaderCardsSlot, {
order: 4,
render: () => <MembersCard />,
});
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import { sample } from 'effector';

import { $features } from '@/shared/config/features';
import { createFeature } from '@/shared/feature';
import { fellowshipNetworkFeature } from '@/features/fellowship-network';
import { ERROR } from '../constants';

export const membersFeatureStatus = createFeature({
export const fellowshipMembersFeature = createFeature({
name: 'fellowship/members',
enable: $features.map(({ fellowship }) => fellowship),
input: fellowshipNetworkFeature.model.network.$network,
filter: input => {
return input.api.isConnected
Expand All @@ -21,5 +23,5 @@ export const membersFeatureStatus = createFeature({
sample({
clock: fellowshipNetworkFeature.model.network.$isActive,
filter: fellowshipNetworkFeature.model.network.$isActive,
target: membersFeatureStatus.restore,
target: fellowshipMembersFeature.restore,
});
4 changes: 2 additions & 2 deletions src/renderer/features/fellowship-members/model/fellowship.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ import { combine } from 'effector';
import { nullable } from '@/shared/lib/utils';
import { collectiveDomain } from '@/domains/collectives';

import { membersFeatureStatus } from './status';
import { fellowshipMembersFeature } from './feature';

const $fellowshipStore = collectiveDomain.$store.map(store => store['fellowship'] || null);

const $store = combine($fellowshipStore, membersFeatureStatus.state, (fellowshipStore, state) => {
const $store = combine($fellowshipStore, fellowshipMembersFeature.state, (fellowshipStore, state) => {
if (nullable(fellowshipStore) || state.status !== 'running') {
return null;
}
Expand Down
6 changes: 3 additions & 3 deletions src/renderer/features/fellowship-members/model/identity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ import { combine, sample } from 'effector';
import { attachToFeatureInput } from '@/shared/feature';
import { identityDomain } from '@/domains/identity';

import { fellowshipMembersFeature } from './feature';
import { membersModel } from './members';
import { membersFeatureStatus } from './status';

const membersUpdate = attachToFeatureInput(membersFeatureStatus, membersModel.$list);
const membersUpdate = attachToFeatureInput(fellowshipMembersFeature, membersModel.$list);

const $identity = combine(identityDomain.identity.$list, membersFeatureStatus.state, (list, state) => {
const $identity = combine(identityDomain.identity.$list, fellowshipMembersFeature.state, (list, state) => {
if (state.status !== 'running') return {};

return list[state.data.chainId] ?? {};
Expand Down
8 changes: 4 additions & 4 deletions src/renderer/features/fellowship-members/model/members.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { and, or } from 'patronum';

import { members, membersService } from '@/domains/collectives';

import { fellowshipMembersFeature } from './feature';
import { fellowshipModel } from './fellowship';
import { membersFeatureStatus } from './status';

const $list = fellowshipModel.$store.map(store => store?.members?.filter(membersService.isCoreMember) ?? []);

Expand All @@ -14,17 +14,17 @@ const $pendingMembers = and(
);

sample({
clock: membersFeatureStatus.running,
clock: fellowshipMembersFeature.running,
target: members.subscribe,
});

sample({
clock: membersFeatureStatus.stopped,
clock: fellowshipMembersFeature.stopped,
target: members.unsubscribe,
});

export const membersModel = {
$list,
$pending: or($pendingMembers, membersFeatureStatus.isStarting),
$pending: or($pendingMembers, fellowshipMembersFeature.isStarting),
$fulfilled: members.fulfilled,
};
Loading

0 comments on commit 2248735

Please sign in to comment.