Skip to content

Commit

Permalink
refactor: replace inline array map with useList; replace inline api c…
Browse files Browse the repository at this point in the history
…alls with attach; add named chain routes
  • Loading branch information
merely04 committed Jan 31, 2024
1 parent 7893dfa commit 7393af1
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 105 deletions.
13 changes: 11 additions & 2 deletions src/pages/discussion/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import {currentRoute} from './model';
import {RouteInstance, RouteParams} from 'atomic-router';
import {createRouteView} from 'atomic-router-react';

import {PageLoader} from '~/widgets/page-loader';

import {currentRoute, dataLoadedRoute} from './model';
import {DiscussionPage} from './page';

export const DiscussionRoute = {
view: DiscussionPage,
view: createRouteView({
route: dataLoadedRoute as unknown as RouteInstance<RouteParams>,
view: DiscussionPage,
otherwise: PageLoader,
}),
route: currentRoute,
};
52 changes: 30 additions & 22 deletions src/pages/discussion/model.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
import * as typed from 'typed-contracts';
import {chainRoute} from 'atomic-router';
import {createStore, sample} from 'effector';

import {apiV1CommentsGet, apiV1DiscussionsDiscussionIdGet} from '~/shared/api';
import {attach} from 'effector/compat';

import {
apiV1CommentsGet,
apiV1CommentsGetOk,
apiV1DiscussionsDiscussionIdGet,
apiV1DiscussionsDiscussionIdGetOk,
} from '~/shared/api';
import {routes} from '~/shared/routes';

const getDiscussionFx = attach({effect: apiV1DiscussionsDiscussionIdGet});
const getCommentsFx = attach({effect: apiV1CommentsGet});

export const currentRoute = routes.discussion;

chainRoute({
export const dataLoadedRoute = chainRoute({
route: currentRoute,
beforeOpen: {
effect: apiV1DiscussionsDiscussionIdGet,
effect: getDiscussionFx,
mapParams: ({params}) => {
return {
path: {
Expand All @@ -20,34 +30,32 @@ chainRoute({
},
});

export const $discussion = createStore<any>(null);
export const $discussion = createStore<typed.Get<typeof apiV1DiscussionsDiscussionIdGetOk> | null>(
null,
);

export const $comments = createStore<typed.Get<typeof apiV1CommentsGetOk>>([]);

sample({
clock: apiV1DiscussionsDiscussionIdGet.doneData,
clock: getDiscussionFx.doneData,
fn: (x) => x.answer,
target: $discussion,
});

chainRoute({
route: currentRoute,
beforeOpen: {
effect: apiV1CommentsGet,
mapParams: ({params}) => {
return {
query: {
discussionId: params.discussionId,
size: 10,
page: 0,
},
};
sample({
clock: getDiscussionFx.doneData,
fn: ({answer}) => ({
query: {
discussionId: answer.id!,
size: 10,
page: 0,
},
},
}),
target: getCommentsFx,
});

export const $comments = createStore<any>(null);

sample({
clock: apiV1CommentsGet.doneData,
clock: getCommentsFx.doneData,
fn: (x) => x.answer,
target: $comments,
});
25 changes: 15 additions & 10 deletions src/pages/discussion/page.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
import {useUnit} from 'effector-react';
import {useList, useUnit} from 'effector-react';

import {Page, Text, TextSize} from '~/shared/ui';

import {$comments, $discussion} from './model';
import * as model from './model';

export const DiscussionPage = () => {
const discussion = useUnit($discussion);
const comments = useUnit($comments);
const [discussion] = useUnit([model.$discussion]);

const comments = useList(model.$comments, (comment) => (
<Text key={comment.id!}>{comment.content!}</Text>
));

if (!discussion) {
return null;
}

return (
<Page>
<Text>авпыщвпвщап</Text>
{discussion && (
<>
<Text size={TextSize.XL}>{discussion.title}</Text>
<Text size={TextSize.M}>{discussion.description}</Text>
</>
)}
<Text size={TextSize.XL}>{discussion.title!}</Text>
<Text size={TextSize.M}>{discussion.description!}</Text>

{comments}
</Page>
);
};
13 changes: 11 additions & 2 deletions src/pages/profile/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import {currentRoute} from './model';
import {RouteInstance, RouteParams} from 'atomic-router';
import {createRouteView} from 'atomic-router-react';

import {PageLoader} from '~/widgets/page-loader';

import {currentRoute, dataLoadedRoute} from './model';
import {ProfilePage} from './page';

export const ProfileRoute = {
view: ProfilePage,
view: createRouteView({
route: dataLoadedRoute as unknown as RouteInstance<RouteParams>,
view: ProfilePage,
otherwise: PageLoader,
}),
route: currentRoute,
};
45 changes: 25 additions & 20 deletions src/pages/profile/model.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
import * as typed from 'typed-contracts';
import {chainRoute} from 'atomic-router';
import {createStore, sample} from 'effector';

import {apiV1DiscussionsGet, apiV1UsersUserIdGet} from '~/shared/api';
import {attach, createStore, sample} from 'effector';

import {
apiV1DiscussionsGet,
apiV1DiscussionsGetOk,
apiV1UsersUserIdGet,
apiV1UsersUserIdGetOk,
} from '~/shared/api';
import {routes} from '~/shared/routes';

const getUserFx = attach({effect: apiV1UsersUserIdGet});
const getDiscussionsFx = attach({effect: apiV1DiscussionsGet});

export const currentRoute = routes.profile;

chainRoute({
export const dataLoadedRoute = chainRoute({
route: currentRoute,
beforeOpen: {
effect: apiV1UsersUserIdGet,
effect: getUserFx,
mapParams: ({params}) => {
return {
path: {
Expand All @@ -20,30 +29,26 @@ chainRoute({
},
});

export const $user = createStore<any>(null);
export const $user = createStore<typed.Get<typeof apiV1UsersUserIdGetOk> | null>(null);

export const $discussions = createStore<typed.Get<typeof apiV1DiscussionsGetOk>>([]);

sample({
clock: apiV1UsersUserIdGet.doneData,
clock: getUserFx.doneData,
fn: (x) => x.answer,
target: $user,
});

chainRoute({
route: currentRoute,
beforeOpen: {
effect: apiV1DiscussionsGet,
mapParams: ({params}) => {
return {
query: {
authorId: params.userId,
},
};
sample({
clock: getUserFx.doneData,
fn: ({answer}) => ({
query: {
authorId: answer.id!,
},
},
}),
target: getDiscussionsFx,
});

export const $discussions = createStore<any>(null);

sample({
clock: apiV1DiscussionsGet.doneData,
fn: (x) => x.answer,
Expand Down
100 changes: 51 additions & 49 deletions src/pages/profile/page.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {useUnit} from 'effector-react';
import {useList, useUnit} from 'effector-react';

import {
Avatar,
Expand All @@ -12,63 +12,65 @@ import {
TextSize,
} from '~/shared/ui';

import * as model from './model';
import ChatIcon from './assets/chat.svg';
import MoreIcon from './assets/more.svg';
import ReportIcon from './assets/report.svg';
import {$discussions, $user} from './model';
import cls from './page.module.scss';

export const ProfilePage = () => {
const user = useUnit($user);
const discussions = useUnit($discussions);
const user = useUnit(model.$user);

const discussions = useList(model.$discussions, (discussion) => (
<a href={`/d/${discussion.id}`}>
<div className={cls.discussionCard}>
<Text size={TextSize.L}>{discussion.title!}</Text>
<Text size={TextSize.M}>{discussion.description!}</Text>
</div>
</a>
));

if (!user) {
return null;
}

return (
<Page>
{user && (
<Container className={cls.head} size={ContainerSize.M}>
<Avatar
className={cls.avatar}
avatarUrl={user.avatarUrl}
username={user.username}
displayName={user.display_name}
/>
<Text className={cls.displayName} center={true} size={TextSize.XL}>
{user.username}
</Text>
<Text size={TextSize.M} Component="h1">
@{user.username}
</Text>
<Text className={cls.bio} center={true} size={TextSize.M}>
Fulltext search in Neo4j is supported by means of fulltext schema indexes. Fulltext
schema indexes are created, dropped, and updated transactionally, and are automatically
replicated throughout a cluster.
</Text>
<div className={cls.actions}>
<Button>Subscribe</Button>
<Button variant={ButtonVariant.SECONDARY} shape={ButtonShape.EQUILATERAL}>
<ChatIcon />
</Button>
<Button variant={ButtonVariant.SECONDARY} shape={ButtonShape.EQUILATERAL}>
<ReportIcon />
</Button>
<Button variant={ButtonVariant.SECONDARY} shape={ButtonShape.EQUILATERAL}>
<MoreIcon />
</Button>
</div>
</Container>
)}
{discussions && (
<Container size={ContainerSize.M} className={cls.discussions}>
{discussions.map((discussion) => (
<a href={`/d/${discussion.id}`}>
<div className={cls.discussionCard}>
<Text size={TextSize.L}>{discussion.title}</Text>
<Text size={TextSize.M}>{discussion.description}</Text>
</div>
</a>
))}
</Container>
)}
<Container className={cls.head} size={ContainerSize.M}>
<Avatar
className={cls.avatar}
avatarUrl={user.avatar_url!}
username={user.username!}
displayName={user.display_name!}
/>
<Text className={cls.displayName} center={true} size={TextSize.XL}>
{user.username!}
</Text>
<Text size={TextSize.M} Component="h1">
@{user.username!}
</Text>
<Text className={cls.bio} center={true} size={TextSize.M}>
Fulltext search in Neo4j is supported by means of fulltext schema indexes. Fulltext schema
indexes are created, dropped, and updated transactionally, and are automatically
replicated throughout a cluster.
</Text>
<div className={cls.actions}>
<Button>Subscribe</Button>
<Button variant={ButtonVariant.SECONDARY} shape={ButtonShape.EQUILATERAL}>
<ChatIcon />
</Button>
<Button variant={ButtonVariant.SECONDARY} shape={ButtonShape.EQUILATERAL}>
<ReportIcon />
</Button>
<Button variant={ButtonVariant.SECONDARY} shape={ButtonShape.EQUILATERAL}>
<MoreIcon />
</Button>
</div>
</Container>

<Container size={ContainerSize.M} className={cls.discussions}>
{discussions}
</Container>
</Page>
);
};

0 comments on commit 7393af1

Please sign in to comment.