Skip to content

Commit faca4f7

Browse files
committed
refactor: Getting rid of commands
1 parent 88e7478 commit faca4f7

20 files changed

+258
-300
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,6 @@ For more information on how to this works with other frontends/backends, head ov
2727

2828
### Architecture notes
2929

30-
- use case it is command in application/feature/commands
3130
- src/components: reusable ui components
3231

3332
## Getting started
@@ -46,6 +45,7 @@ npm run dev
4645

4746
## Todo
4847

48+
- get rid of commands
4949
- get rid of class-validator (use zod)
5050
- switch to react location
5151
- https://realworld-docs.netlify.app/docs/specs/backend-specs/endpoints

package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,21 @@
2929
"react": "^18.2.0",
3030
"react-dom": "^18.2.0",
3131
"react-hook-form": "^7.35.0",
32-
"react-router-dom": "^6.3.0",
32+
"react-router-dom": "^6.4.0",
3333
"recoil": "^0.7.5",
3434
"rsts": "^1.0.0"
3535
},
3636
"devDependencies": {
3737
"@kyleshevlin/eslint-plugin": "^1.3.0",
3838
"@testing-library/react": "^13.4.0",
39-
"@types/react": "^18.0.19",
39+
"@types/react": "^18.0.20",
4040
"@types/react-dom": "^18.0.6",
4141
"@types/react-router-dom": "^5.3.3",
4242
"@typescript-eslint/eslint-plugin": "^5.37.0",
4343
"@typescript-eslint/parser": "^5.37.0",
4444
"@vitejs/plugin-react-refresh": "^1.3.6",
4545
"@vitest/coverage-c8": "^0.23.2",
46-
"autoprefixer": "^10.4.10",
46+
"autoprefixer": "^10.4.11",
4747
"cssnano": "^5.1.13",
4848
"cssnano-preset-default": "^5.2.12",
4949
"eslint": "^8.23.1",

prettier.config.cjs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
module.exports = {
2-
printWidth: 88,
2+
printWidth: 80,
33
trailingComma: 'all',
44
tabWidth: 2,
55
semi: true,

src/application/api/user.service.ts

+28-8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import type {
77
} from '@application/user';
88
import ky from 'ky';
99
import { inject } from 'njct';
10+
import { Err, Ok, Result } from 'rsts';
1011

1112
import { AppConfig } from './types';
1213

@@ -27,14 +28,26 @@ export class UserService implements IUserService {
2728
),
2829
) {}
2930

30-
async register(user: {
31+
async register(data: {
3132
username: string;
3233
password: string;
3334
email: string;
34-
}): Promise<void> {
35+
}): Promise<Result<User>> {
3536
const url = `${this.config.apiBase}/users`;
36-
const result = await this.http.post(url, { json: { user } }).json<{ user: User }>();
37-
this.sessionService.update(result.user.token);
37+
let user: User;
38+
39+
try {
40+
user = await this.http
41+
.post(url, { json: { user: data } })
42+
.json<{ user: User }>()
43+
.then(r => r.user);
44+
} catch (cause) {
45+
return Err(new Error('UserRegistration', { cause }));
46+
}
47+
48+
this.sessionService.update(user.token);
49+
50+
return Ok(user);
3851
}
3952

4053
isLoggedIn(): boolean {
@@ -49,8 +62,12 @@ export class UserService implements IUserService {
4962
return result.user;
5063
}
5164

52-
async updateCurrentUser(user: UserSettingsInput) {
53-
return this.http
65+
async updateCurrentUser(data: UserSettingsInput): Promise<Result<User>> {
66+
if (!data.password) {
67+
delete data.password;
68+
}
69+
// eslint-disable-next-line sonarjs/prefer-immediate-return
70+
const result = await this.http
5471
.extend(this.authorization())
5572
.extend({
5673
hooks: {
@@ -65,9 +82,12 @@ export class UserService implements IUserService {
6582
],
6683
},
6784
})
68-
.put(`${this.config.apiBase}/user`, { json: { user } })
85+
.put(`${this.config.apiBase}/user`, { json: { user: data } })
6986
.json<{ user: User }>()
70-
.then(result => result.user);
87+
.then(result => Ok(result.user))
88+
.catch(cause => Err(new Error('UpdateCurrentUser', { cause })));
89+
90+
return result;
7191
}
7292

7393
async getProfile(name: string) {

src/application/profile/index.ts

-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
11
export { FollowUserCommand } from './commands/follow-user.command';
22
export { UnfollowUserCommand } from './commands/unfollow-user.command';
33
export type { Profile } from './interfaces';
4-
export { GetProfileHandler } from './queries';

src/application/profile/queries/get-profile.handler.ts

-27
This file was deleted.

src/application/profile/queries/index.ts

-1
This file was deleted.

src/application/user/commands/index.ts

-2
This file was deleted.

src/application/user/commands/user-register.command.ts

-19
This file was deleted.

src/application/user/commands/user-settings-update.command.ts

-26
This file was deleted.

src/application/user/user-service.interface.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
import { Result } from 'rsts';
12
import { ObjectType } from 'simplytyped';
23

34
import { Profile } from '../profile';
45
import { User, UserCreateInput, UserSettingsInput } from './models';
56

67
export interface UserService {
7-
register(data: ObjectType<UserCreateInput>): Promise<void>;
8+
register(data: ObjectType<UserCreateInput>): Promise<Result<User>>;
89
getCurrentUser(): Promise<User>;
9-
updateCurrentUser(data: UserSettingsInput): Promise<User>;
10+
updateCurrentUser(data: UserSettingsInput): Promise<Result<User>>;
1011
getProfile(name: string): Promise<Profile>;
1112
followUser(username: string): Promise<Profile>;
1213
unfollowUser(username: string): Promise<Profile>;

src/components/Loader/Loader.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from 'react';
22
import { useRecoilValue } from 'recoil';
33

4-
import { isLoading } from './is-loading.atom';
4+
import { isLoading } from './isLoading.atom';
55
import { Loading } from './Loading';
66

77
export function Loader() {

src/components/Loader/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
export { isLoading } from './is-loading.atom';
1+
export { isLoading } from './isLoading.atom';
22
export { Loader } from './Loader';
33
export { Loading } from './Loading';

src/pages/profile/Profile.tsx

+2-86
Original file line numberDiff line numberDiff line change
@@ -1,93 +1,9 @@
1-
import { ArticleList } from '@application';
2-
import {
3-
FollowUserCommand,
4-
GetProfileHandler,
5-
Profile as ApplicationProfile,
6-
} from '@application/profile';
7-
import { UnfollowUserCommand } from '@application/profile/commands/unfollow-user.command';
8-
import { isLoading } from '@components/Loader';
9-
import { useRequest } from 'ahooks';
10-
import React, { useCallback, useEffect, useState } from 'react';
11-
import { useParams } from 'react-router-dom';
12-
import { useSetRecoilState } from 'recoil';
13-
import { Result } from 'rsts';
1+
import React from 'react';
142

153
import { ArticlePreview } from '../article/Article';
4+
import { useProfile } from './useProfile';
165
import { UserInfo } from './UserInfo';
176

18-
async function fetchProfile(name: string) {
19-
const result = await new GetProfileHandler().execute(name);
20-
if (result.isErr()) {
21-
throw new Error('Fetch profile error');
22-
}
23-
return result.unwrap();
24-
}
25-
26-
function useProfile() {
27-
const setIsLoading = useSetRecoilState(isLoading);
28-
const { username } = useParams() as { username: string };
29-
const [serverError, setServerError] = useState('');
30-
const [{ profile, articleList, toggleFollowInProgress }, setProfile] = useState<{
31-
profile?: ApplicationProfile;
32-
articleList?: ArticleList;
33-
toggleFollowInProgress: boolean;
34-
}>({
35-
toggleFollowInProgress: false,
36-
});
37-
38-
const { run } = useRequest(fetchProfile, {
39-
manual: true,
40-
onBefore: () => {
41-
setIsLoading(true);
42-
},
43-
onSuccess: data => {
44-
setProfile({
45-
profile: data.profile,
46-
articleList: data.articleList,
47-
toggleFollowInProgress,
48-
});
49-
},
50-
onError: error => {
51-
setServerError(error.message);
52-
},
53-
onFinally: () => {
54-
setIsLoading(false);
55-
},
56-
});
57-
58-
useEffect(() => {
59-
run(username);
60-
}, [run, username]);
61-
62-
const toggleFollow = useCallback(async () => {
63-
const name = profile?.username;
64-
if (name) {
65-
setProfile({
66-
profile,
67-
articleList,
68-
toggleFollowInProgress: true,
69-
});
70-
71-
let result: Result<ApplicationProfile, Error>;
72-
if (profile.following) {
73-
const command = new UnfollowUserCommand();
74-
result = await command.execute(name);
75-
} else {
76-
const command = new FollowUserCommand();
77-
result = await command.execute(name);
78-
}
79-
80-
setProfile({
81-
profile: result.unwrap(),
82-
articleList,
83-
toggleFollowInProgress: false,
84-
});
85-
}
86-
}, [profile, articleList]);
87-
88-
return { serverError, profile, articleList, toggleFollow, toggleFollowInProgress };
89-
}
90-
917
export function Profile() {
928
const { profile, articleList, serverError, toggleFollow, toggleFollowInProgress } =
939
useProfile();

0 commit comments

Comments
 (0)