From 8eb341bb205c8b4b699b509e73e7ef6c10d24428 Mon Sep 17 00:00:00 2001 From: HoroshkoMykhailo Date: Wed, 4 Sep 2024 09:07:45 +0300 Subject: [PATCH 01/17] feat: add delete query gf-146 --- apps/backend/src/modules/users/user.repository.ts | 11 +++++++++-- package-lock.json | 10 ++++------ 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/apps/backend/src/modules/users/user.repository.ts b/apps/backend/src/modules/users/user.repository.ts index 4f284653b..e0eee6414 100644 --- a/apps/backend/src/modules/users/user.repository.ts +++ b/apps/backend/src/modules/users/user.repository.ts @@ -27,8 +27,15 @@ class UserRepository implements Repository { return UserEntity.initialize(user); } - public delete(): ReturnType { - return Promise.resolve(true); + public async delete(id: number): Promise { + const NO_ROWS_DELETED = 0; + + const numberDeletedRows = await this.userModel + .query() + .deleteById(id) + .execute(); + + return numberDeletedRows > NO_ROWS_DELETED; } public async find(id: number): Promise { diff --git a/package-lock.json b/package-lock.json index 724a2ac7f..cf6dc2bb3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,9 +11,6 @@ "apps/*", "packages/*" ], - "dependencies": { - "debounce": "2.1.0" - }, "devDependencies": { "@commitlint/cli": "19.4.0", "@commitlint/config-conventional": "19.2.2", @@ -55,7 +52,7 @@ }, "apps/backend": { "name": "@git-fit/backend", - "version": "1.0.1", + "version": "1.4.0", "dependencies": { "@fastify/static": "7.0.4", "@fastify/swagger": "8.15.0", @@ -133,7 +130,7 @@ }, "apps/frontend": { "name": "@git-fit/frontend", - "version": "1.2.0", + "version": "1.6.2", "dependencies": { "@git-fit/shared": "*", "@hookform/resolvers": "3.9.0", @@ -13301,10 +13298,11 @@ }, "packages/shared": { "name": "@git-fit/shared", - "version": "1.0.0", + "version": "1.4.0", "dependencies": { "change-case": "5.4.4", "date-fns": "3.6.0", + "debounce": "2.1.0", "zod": "3.23.8" }, "engines": { From 26a6e3aefc3396c4aeaebd63cbdab7a0f73baf68 Mon Sep 17 00:00:00 2001 From: HoroshkoMykhailo Date: Wed, 4 Sep 2024 09:12:56 +0300 Subject: [PATCH 02/17] feat: add service delete gf-146 --- apps/backend/src/modules/users/user.service.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/apps/backend/src/modules/users/user.service.ts b/apps/backend/src/modules/users/user.service.ts index bbd2d1b21..6ecf8b91f 100644 --- a/apps/backend/src/modules/users/user.service.ts +++ b/apps/backend/src/modules/users/user.service.ts @@ -51,8 +51,17 @@ class UserService implements Service { return item.toObject(); } - public delete(): ReturnType { - return Promise.resolve(true); + public async delete(id: number): Promise { + const isDeleted = await this.userRepository.delete(id); + + if (!isDeleted) { + throw new UserError({ + message: ExceptionMessage.USER_NOT_FOUND, + status: HTTPCode.NOT_FOUND, + }); + } + + return isDeleted; } public async find(id: number): Promise { From fe7f7597b7b121beeb5508025a2bd3666809cb68 Mon Sep 17 00:00:00 2001 From: HoroshkoMykhailo Date: Wed, 4 Sep 2024 09:45:27 +0300 Subject: [PATCH 03/17] feat: add delete route gf-146 --- apps/backend/src/libs/constants/constants.ts | 1 + .../nothing-deleted-count.constant.ts | 3 ++ .../src/modules/users/user.controller.ts | 42 +++++++++++++++++++ .../src/modules/users/user.repository.ts | 5 +-- .../http/libs/types/http-method.type.ts | 2 +- 5 files changed, 49 insertions(+), 4 deletions(-) create mode 100644 apps/backend/src/libs/constants/constants.ts create mode 100644 apps/backend/src/libs/constants/nothing-deleted-count.constant.ts diff --git a/apps/backend/src/libs/constants/constants.ts b/apps/backend/src/libs/constants/constants.ts new file mode 100644 index 000000000..eced967cc --- /dev/null +++ b/apps/backend/src/libs/constants/constants.ts @@ -0,0 +1 @@ +export { NOTHING_DELETED_COUNT } from "./nothing-deleted-count.constant.js"; diff --git a/apps/backend/src/libs/constants/nothing-deleted-count.constant.ts b/apps/backend/src/libs/constants/nothing-deleted-count.constant.ts new file mode 100644 index 000000000..363288766 --- /dev/null +++ b/apps/backend/src/libs/constants/nothing-deleted-count.constant.ts @@ -0,0 +1,3 @@ +const NOTHING_DELETED_COUNT = 0; + +export { NOTHING_DELETED_COUNT }; diff --git a/apps/backend/src/modules/users/user.controller.ts b/apps/backend/src/modules/users/user.controller.ts index e0bc73a20..57fc978d7 100644 --- a/apps/backend/src/modules/users/user.controller.ts +++ b/apps/backend/src/modules/users/user.controller.ts @@ -59,6 +59,48 @@ class UserController extends BaseController { body: userPatchValidationSchema, }, }); + + this.addRoute({ + handler: (options) => + this.delete( + options as APIHandlerOptions<{ + params: { id: string }; + }>, + ), + method: "DELETE", + path: UsersApiPath.$ID, + }); + } + + /** + * @swagger + * /users/{id}: + * delete: + * tags: + * - Users + * description: Deletes a user + * parameters: + * - in: path + * name: id + * description: ID of the user to delete + * required: true + * schema: + * type: string + * responses: + * 200: + * description: User deleted successfully + * 404: + * description: User not found + */ + private async delete( + options: APIHandlerOptions<{ + params: { id: string }; + }>, + ): Promise { + return { + payload: await this.userService.delete(Number(options.params.id)), + status: HTTPCode.OK, + }; } /** diff --git a/apps/backend/src/modules/users/user.repository.ts b/apps/backend/src/modules/users/user.repository.ts index e0eee6414..8d99ff0d1 100644 --- a/apps/backend/src/modules/users/user.repository.ts +++ b/apps/backend/src/modules/users/user.repository.ts @@ -1,3 +1,4 @@ +import { NOTHING_DELETED_COUNT } from "~/libs/constants/constants.js"; import { type Repository } from "~/libs/types/types.js"; import { UserEntity } from "~/modules/users/user.entity.js"; import { type UserModel } from "~/modules/users/user.model.js"; @@ -28,14 +29,12 @@ class UserRepository implements Repository { } public async delete(id: number): Promise { - const NO_ROWS_DELETED = 0; - const numberDeletedRows = await this.userModel .query() .deleteById(id) .execute(); - return numberDeletedRows > NO_ROWS_DELETED; + return numberDeletedRows > NOTHING_DELETED_COUNT; } public async find(id: number): Promise { diff --git a/packages/shared/src/libs/modules/http/libs/types/http-method.type.ts b/packages/shared/src/libs/modules/http/libs/types/http-method.type.ts index 1a04861a3..c11dea198 100644 --- a/packages/shared/src/libs/modules/http/libs/types/http-method.type.ts +++ b/packages/shared/src/libs/modules/http/libs/types/http-method.type.ts @@ -1,3 +1,3 @@ -type HTTPMethod = "GET" | "PATCH" | "POST"; +type HTTPMethod = "DELETE" | "GET" | "PATCH" | "POST"; export { type HTTPMethod }; From d2343a5bfe8b41c1b24f1d2a665b4cbbb02d97c3 Mon Sep 17 00:00:00 2001 From: HoroshkoMykhailo Date: Wed, 4 Sep 2024 11:59:13 +0300 Subject: [PATCH 04/17] feat: add soft delete gf-146 --- .../20240904065949_add_deleted_at_to_users.ts | 21 +++++++++++++++++++ apps/backend/src/modules/users/user.entity.ts | 9 ++++++++ apps/backend/src/modules/users/user.model.ts | 2 ++ .../src/modules/users/user.repository.ts | 9 +++++--- readme.md | 1 + 5 files changed, 39 insertions(+), 3 deletions(-) create mode 100644 apps/backend/src/db/migrations/20240904065949_add_deleted_at_to_users.ts diff --git a/apps/backend/src/db/migrations/20240904065949_add_deleted_at_to_users.ts b/apps/backend/src/db/migrations/20240904065949_add_deleted_at_to_users.ts new file mode 100644 index 000000000..29e13e276 --- /dev/null +++ b/apps/backend/src/db/migrations/20240904065949_add_deleted_at_to_users.ts @@ -0,0 +1,21 @@ +import { type Knex } from "knex"; + +const TABLE_NAME = "users"; + +const ColumnName = { + DELETED_AT: "deleted_at", +} as const; + +function up(knex: Knex): Promise { + return knex.schema.alterTable(TABLE_NAME, (table) => { + table.dateTime(ColumnName.DELETED_AT).nullable(); + }); +} + +function down(knex: Knex): Promise { + return knex.schema.alterTable(TABLE_NAME, (table) => { + table.dropColumn(ColumnName.DELETED_AT); + }); +} + +export { down, up }; diff --git a/apps/backend/src/modules/users/user.entity.ts b/apps/backend/src/modules/users/user.entity.ts index 5dde53c5e..ff0858de0 100644 --- a/apps/backend/src/modules/users/user.entity.ts +++ b/apps/backend/src/modules/users/user.entity.ts @@ -5,6 +5,8 @@ import { type UserAuthResponseDto } from "./libs/types/types.js"; class UserEntity implements Entity { private createdAt: null | string; + private deletedAt: null | string; + private email: string; private id: null | number; @@ -17,6 +19,7 @@ class UserEntity implements Entity { private constructor({ createdAt, + deletedAt, email, id, name, @@ -24,6 +27,7 @@ class UserEntity implements Entity { passwordSalt, }: { createdAt: null | string; + deletedAt: null | string; email: string; id: null | number; name: string; @@ -36,10 +40,12 @@ class UserEntity implements Entity { this.passwordHash = passwordHash; this.passwordSalt = passwordSalt; this.createdAt = createdAt; + this.deletedAt = deletedAt; } public static initialize({ createdAt, + deletedAt, email, id, name, @@ -47,6 +53,7 @@ class UserEntity implements Entity { passwordSalt, }: { createdAt: string; + deletedAt: null | string; email: string; id: number; name: string; @@ -55,6 +62,7 @@ class UserEntity implements Entity { }): UserEntity { return new UserEntity({ createdAt, + deletedAt, email, id, name, @@ -76,6 +84,7 @@ class UserEntity implements Entity { }): UserEntity { return new UserEntity({ createdAt: null, + deletedAt: null, email, id: null, name, diff --git a/apps/backend/src/modules/users/user.model.ts b/apps/backend/src/modules/users/user.model.ts index 34589e81b..86b278f0e 100644 --- a/apps/backend/src/modules/users/user.model.ts +++ b/apps/backend/src/modules/users/user.model.ts @@ -4,6 +4,8 @@ import { } from "~/libs/modules/database/database.js"; class UserModel extends AbstractModel { + public deletedAt!: null | string; + public email!: string; public name!: string; diff --git a/apps/backend/src/modules/users/user.repository.ts b/apps/backend/src/modules/users/user.repository.ts index 8d99ff0d1..dc632e1e1 100644 --- a/apps/backend/src/modules/users/user.repository.ts +++ b/apps/backend/src/modules/users/user.repository.ts @@ -31,7 +31,9 @@ class UserRepository implements Repository { public async delete(id: number): Promise { const numberDeletedRows = await this.userModel .query() - .deleteById(id) + .patch({ deletedAt: new Date().toISOString() }) + .where({ id }) + .whereNull("deletedAt") .execute(); return numberDeletedRows > NOTHING_DELETED_COUNT; @@ -41,6 +43,7 @@ class UserRepository implements Repository { const user = await this.userModel .query() .findById(id) + .whereNull("deletedAt") .returning("*") .execute(); @@ -48,13 +51,13 @@ class UserRepository implements Repository { } public async findAll(): Promise { - const users = await this.userModel.query().execute(); + const users = await this.userModel.query().whereNull("deletedAt").execute(); return users.map((user) => UserEntity.initialize(user)); } public async findByEmail(email: string): Promise { - const user = await this.userModel.query().findOne({ email }); + const user = await this.userModel.query().findOne({ email }).execute(); return user ? UserEntity.initialize(user) : null; } diff --git a/readme.md b/readme.md index 8bc3d887f..b32973bf0 100644 --- a/readme.md +++ b/readme.md @@ -27,6 +27,7 @@ erDiagram int id PK dateTime created_at dateTime updated_at + dateTime deleted_at citext email text password_hash text password_salt From 3deecb37568fd604e9c3f886cc4b0c209d0c650b Mon Sep 17 00:00:00 2001 From: HoroshkoMykhailo Date: Wed, 4 Sep 2024 13:10:18 +0300 Subject: [PATCH 05/17] feat: add delete account styles gf-146 --- .../pages/profile/components/components.ts | 1 + .../delete-account/delete-account.tsx | 20 +++++++++++ .../delete-account/styles.module.css | 20 +++++++++++ apps/frontend/src/pages/profile/profile.tsx | 11 +++--- .../src/pages/profile/styles.module.css | 34 +++++++++++++------ 5 files changed, 72 insertions(+), 14 deletions(-) create mode 100644 apps/frontend/src/pages/profile/components/delete-account/delete-account.tsx create mode 100644 apps/frontend/src/pages/profile/components/delete-account/styles.module.css diff --git a/apps/frontend/src/pages/profile/components/components.ts b/apps/frontend/src/pages/profile/components/components.ts index f51eb1ba2..d25dc2ff3 100644 --- a/apps/frontend/src/pages/profile/components/components.ts +++ b/apps/frontend/src/pages/profile/components/components.ts @@ -1 +1,2 @@ +export { DeleteAccount } from "./delete-account/delete-account.js"; export { EditUserForm } from "./edit-user-form/edit-user-form.js"; diff --git a/apps/frontend/src/pages/profile/components/delete-account/delete-account.tsx b/apps/frontend/src/pages/profile/components/delete-account/delete-account.tsx new file mode 100644 index 000000000..ed1cbd8e1 --- /dev/null +++ b/apps/frontend/src/pages/profile/components/delete-account/delete-account.tsx @@ -0,0 +1,20 @@ +import { Button } from "~/libs/components/components.js"; +import { type UserAuthResponseDto } from "~/modules/users/users.js"; + +import styles from "./styles.module.css"; + +type Properties = { + user: UserAuthResponseDto; +}; + +const DeleteAccount = ({ user }: Properties): JSX.Element => { + return ( +
+

Delete account {user.name}

+

This action cannot be undone.

+
+ ); +}; + +export { DeleteAccount }; diff --git a/apps/frontend/src/pages/profile/components/delete-account/styles.module.css b/apps/frontend/src/pages/profile/components/delete-account/styles.module.css new file mode 100644 index 000000000..1f89a0aaf --- /dev/null +++ b/apps/frontend/src/pages/profile/components/delete-account/styles.module.css @@ -0,0 +1,20 @@ +.profile-delete { + display: flex; + flex-direction: column; + gap: 24px; + align-items: flex-start; + padding: 0; +} + +.delete-title { + margin: 0; + font-size: 24px; + line-height: 120%; + color: var(--color-danger); +} + +.delete-text { + margin: 0; + font-size: 16px; + line-height: 150%; +} diff --git a/apps/frontend/src/pages/profile/profile.tsx b/apps/frontend/src/pages/profile/profile.tsx index 525c3056f..5b7745d9d 100644 --- a/apps/frontend/src/pages/profile/profile.tsx +++ b/apps/frontend/src/pages/profile/profile.tsx @@ -2,7 +2,7 @@ import { PageLayout } from "~/libs/components/components.js"; import { useAppSelector } from "~/libs/hooks/hooks.js"; import { type UserAuthResponseDto } from "~/modules/users/users.js"; -import { EditUserForm } from "./components/components.js"; +import { DeleteAccount, EditUserForm } from "./components/components.js"; import styles from "./styles.module.css"; const Profile = (): JSX.Element => { @@ -11,9 +11,12 @@ const Profile = (): JSX.Element => { return (
-

Profile

- - +
+

Profile

+ +
+
+
); diff --git a/apps/frontend/src/pages/profile/styles.module.css b/apps/frontend/src/pages/profile/styles.module.css index b2df78300..4732dc28f 100644 --- a/apps/frontend/src/pages/profile/styles.module.css +++ b/apps/frontend/src/pages/profile/styles.module.css @@ -1,16 +1,30 @@ -.title { - margin-top: 0; - margin-bottom: 24px; +.profile-content { + display: flex; + flex-direction: column; + gap: 32px; + align-items: flex-start; + width: 100%; + max-width: 800px; + padding: 0; + margin: 0 auto; } -.profile-loader { +.profile-update { display: flex; - flex: 1; - align-items: center; + flex-direction: column; + gap: 24px; + align-items: flex-start; + padding: 0; } -.profile-content { - width: 100%; - max-width: 800px; - margin: 0 auto; +.title { + margin: 0; + font-size: 30px; + line-height: 120%; +} + +.divider { + width: 800px; + height: 1px; + background: var(--color-border-primary); } From ced66a8272433da7562c4cc32e2755f904ae6297 Mon Sep 17 00:00:00 2001 From: HoroshkoMykhailo Date: Wed, 4 Sep 2024 13:37:16 +0300 Subject: [PATCH 06/17] feat: add confirmation modal gf-146 --- .../src/libs/components/components.ts | 1 + .../confirmation-modal/confirmation-modal.tsx | 49 +++++++++++++++++++ .../confirmation-modal/styles.module.css | 13 +++++ .../delete-account/delete-account.tsx | 27 +++++++++- 4 files changed, 88 insertions(+), 2 deletions(-) create mode 100644 apps/frontend/src/libs/components/confirmation-modal/confirmation-modal.tsx create mode 100644 apps/frontend/src/libs/components/confirmation-modal/styles.module.css diff --git a/apps/frontend/src/libs/components/components.ts b/apps/frontend/src/libs/components/components.ts index 1f5947afe..4f1fe2eb5 100644 --- a/apps/frontend/src/libs/components/components.ts +++ b/apps/frontend/src/libs/components/components.ts @@ -2,6 +2,7 @@ export { App } from "./app/app.js"; export { Avatar } from "./avatar/avatar.js"; export { Breadcrumbs } from "./breadcrumbs/breadcrumbs.js"; export { Button } from "./button/button.js"; +export { ConfirmationModal } from "./confirmation-modal/confirmation-modal.js"; export { Header } from "./header/header.js"; export { Icon } from "./icon/icon.js"; export { IconButton } from "./icon-button/icon-button.js"; diff --git a/apps/frontend/src/libs/components/confirmation-modal/confirmation-modal.tsx b/apps/frontend/src/libs/components/confirmation-modal/confirmation-modal.tsx new file mode 100644 index 000000000..f45385c52 --- /dev/null +++ b/apps/frontend/src/libs/components/confirmation-modal/confirmation-modal.tsx @@ -0,0 +1,49 @@ +import { Button, Modal } from "~/libs/components/components.js"; +import { useCallback } from "~/libs/hooks/hooks.js"; + +import styles from "./styles.module.css"; + +type ConfirmationModalProperties = { + cancelLabel?: string; + confirmationText: string; + confirmLabel?: string; + isModalOpened: boolean; + onConfirm: () => void; + onModalClose: () => void; + title: string; +}; + +const ConfirmationModal = ({ + cancelLabel = "Cancel", + confirmationText, + confirmLabel = "Confirm", + isModalOpened, + onConfirm, + onModalClose, + title, +}: ConfirmationModalProperties): JSX.Element => { + const handleConfirmClick = useCallback(() => { + onConfirm(); + onModalClose(); + }, [onConfirm, onModalClose]); + + return ( + +

{confirmationText}

+
+
+
+ ); +}; + +export { ConfirmationModal }; diff --git a/apps/frontend/src/libs/components/confirmation-modal/styles.module.css b/apps/frontend/src/libs/components/confirmation-modal/styles.module.css new file mode 100644 index 000000000..62d618cfb --- /dev/null +++ b/apps/frontend/src/libs/components/confirmation-modal/styles.module.css @@ -0,0 +1,13 @@ +.confirmation-text { + padding: 24px 0; + margin: 0; + font-size: 16px; + font-weight: 400; + line-height: 1.5; +} + +.confirmation-buttons { + display: flex; + gap: 10px; + justify-content: flex-end; +} diff --git a/apps/frontend/src/pages/profile/components/delete-account/delete-account.tsx b/apps/frontend/src/pages/profile/components/delete-account/delete-account.tsx index ed1cbd8e1..e74fe873e 100644 --- a/apps/frontend/src/pages/profile/components/delete-account/delete-account.tsx +++ b/apps/frontend/src/pages/profile/components/delete-account/delete-account.tsx @@ -1,4 +1,5 @@ -import { Button } from "~/libs/components/components.js"; +import { Button, ConfirmationModal } from "~/libs/components/components.js"; +import { useCallback, useModal } from "~/libs/hooks/hooks.js"; import { type UserAuthResponseDto } from "~/modules/users/users.js"; import styles from "./styles.module.css"; @@ -8,11 +9,33 @@ type Properties = { }; const DeleteAccount = ({ user }: Properties): JSX.Element => { + const { isModalOpened, onModalClose, onModalOpen } = useModal(); + + const handleDeleteClick = useCallback((): void => { + onModalOpen(); + }, [onModalOpen]); + + const handleDeleteConfirm = useCallback(() => { + onModalClose(); + }, [onModalClose]); + return (

Delete account {user.name}

This action cannot be undone.

-
); }; From c1cf63cab0bcb45e4a442710a2ee447b2172f789 Mon Sep 17 00:00:00 2001 From: HoroshkoMykhailo Date: Wed, 4 Sep 2024 15:20:08 +0300 Subject: [PATCH 07/17] feat: add deletion user after confirmation gf-146 --- .../src/modules/users/user.controller.ts | 2 -- .../src/modules/users/user.repository.ts | 10 ++++++++ .../backend/src/modules/users/user.service.ts | 4 ++-- .../libs/enums/notification-message.enum.ts | 1 + apps/frontend/src/libs/hooks/hooks.ts | 7 +++++- .../src/modules/users/slices/actions.ts | 14 ++++++++++- .../src/modules/users/slices/users.slice.ts | 8 ++++++- .../src/modules/users/slices/users.ts | 3 ++- apps/frontend/src/modules/users/users-api.ts | 10 ++++++++ .../delete-account/delete-account.tsx | 24 +++++++++++++------ apps/frontend/src/pages/profile/profile.tsx | 4 +++- 11 files changed, 71 insertions(+), 16 deletions(-) diff --git a/apps/backend/src/modules/users/user.controller.ts b/apps/backend/src/modules/users/user.controller.ts index 57fc978d7..51fe55ca9 100644 --- a/apps/backend/src/modules/users/user.controller.ts +++ b/apps/backend/src/modules/users/user.controller.ts @@ -89,8 +89,6 @@ class UserController extends BaseController { * responses: * 200: * description: User deleted successfully - * 404: - * description: User not found */ private async delete( options: APIHandlerOptions<{ diff --git a/apps/backend/src/modules/users/user.repository.ts b/apps/backend/src/modules/users/user.repository.ts index dc632e1e1..58eb08cc7 100644 --- a/apps/backend/src/modules/users/user.repository.ts +++ b/apps/backend/src/modules/users/user.repository.ts @@ -57,6 +57,16 @@ class UserRepository implements Repository { } public async findByEmail(email: string): Promise { + const user = await this.userModel + .query() + .findOne({ email }) + .whereNull("deletedAt") + .execute(); + + return user ? UserEntity.initialize(user) : null; + } + + public async findByEmailCreate(email: string): Promise { const user = await this.userModel.query().findOne({ email }).execute(); return user ? UserEntity.initialize(user) : null; diff --git a/apps/backend/src/modules/users/user.service.ts b/apps/backend/src/modules/users/user.service.ts index 6ecf8b91f..27f6096c8 100644 --- a/apps/backend/src/modules/users/user.service.ts +++ b/apps/backend/src/modules/users/user.service.ts @@ -27,7 +27,7 @@ class UserService implements Service { payload: UserSignUpRequestDto, ): Promise { const { email, name, password } = payload; - const existingUser = await this.userRepository.findByEmail(email); + const existingUser = await this.userRepository.findByEmailCreate(email); if (existingUser) { throw new UserError({ @@ -90,7 +90,7 @@ class UserService implements Service { if (!item) { throw new UserError({ - message: ExceptionMessage.USER_NOT_FOUND, + message: ExceptionMessage.INVALID_CREDENTIALS, status: HTTPCode.NOT_FOUND, }); } diff --git a/apps/frontend/src/libs/enums/notification-message.enum.ts b/apps/frontend/src/libs/enums/notification-message.enum.ts index d54486c2b..7f95cae3d 100644 --- a/apps/frontend/src/libs/enums/notification-message.enum.ts +++ b/apps/frontend/src/libs/enums/notification-message.enum.ts @@ -1,6 +1,7 @@ const NotificationMessage = { PROJECT_CREATE_SUCCESS: "Project was successfully created", SUCCESS_PROFILE_UPDATE: "Successfully updated profile information.", + SUCCESS_USER_DELETE: "User deleted successfully.", } as const; export { NotificationMessage }; diff --git a/apps/frontend/src/libs/hooks/hooks.ts b/apps/frontend/src/libs/hooks/hooks.ts index 80598cd58..a8c1a5e70 100644 --- a/apps/frontend/src/libs/hooks/hooks.ts +++ b/apps/frontend/src/libs/hooks/hooks.ts @@ -9,4 +9,9 @@ export { useController as useFormController, useWatch as useFormWatch, } from "react-hook-form"; -export { useLocation, useParams, useSearchParams } from "react-router-dom"; +export { + useLocation, + useNavigate, + useParams, + useSearchParams, +} from "react-router-dom"; diff --git a/apps/frontend/src/modules/users/slices/actions.ts b/apps/frontend/src/modules/users/slices/actions.ts index 6fa6cdf47..c2dfcd26b 100644 --- a/apps/frontend/src/modules/users/slices/actions.ts +++ b/apps/frontend/src/modules/users/slices/actions.ts @@ -11,6 +11,18 @@ import { import { name as sliceName } from "./users.slice.js"; +const deleteById = createAsyncThunk( + `${sliceName}/delete`, + async (userId, { extra }) => { + const { toastNotifier, userApi } = extra; + + await userApi.delete(userId); + toastNotifier.showSuccess(NotificationMessage.SUCCESS_USER_DELETE); + + return userId; + }, +); + const loadAll = createAsyncThunk< UserGetAllResponseDto, undefined, @@ -36,4 +48,4 @@ const updateProfile = createAsyncThunk< return user; }); -export { loadAll, updateProfile }; +export { deleteById, loadAll, updateProfile }; diff --git a/apps/frontend/src/modules/users/slices/users.slice.ts b/apps/frontend/src/modules/users/slices/users.slice.ts index f58fdc219..a62c73ff8 100644 --- a/apps/frontend/src/modules/users/slices/users.slice.ts +++ b/apps/frontend/src/modules/users/slices/users.slice.ts @@ -4,16 +4,18 @@ import { DataStatus } from "~/libs/enums/enums.js"; import { type ValueOf } from "~/libs/types/types.js"; import { type UserGetAllItemResponseDto } from "~/modules/users/users.js"; -import { loadAll, updateProfile } from "./actions.js"; +import { deleteById, loadAll, updateProfile } from "./actions.js"; type State = { dataStatus: ValueOf; + deleteStatus: ValueOf; updateProfileStatus: ValueOf; users: UserGetAllItemResponseDto[]; }; const initialState: State = { dataStatus: DataStatus.IDLE, + deleteStatus: DataStatus.IDLE, updateProfileStatus: DataStatus.IDLE, users: [], }; @@ -40,6 +42,10 @@ const { actions, name, reducer } = createSlice({ builder.addCase(updateProfile.rejected, (state) => { state.updateProfileStatus = DataStatus.REJECTED; }); + builder.addCase(deleteById.fulfilled, (state, action) => { + state.deleteStatus = DataStatus.FULFILLED; + state.users = state.users.filter((user) => user.id !== action.payload); + }); }, initialState, name: "users", diff --git a/apps/frontend/src/modules/users/slices/users.ts b/apps/frontend/src/modules/users/slices/users.ts index a65c869e5..1b540ba91 100644 --- a/apps/frontend/src/modules/users/slices/users.ts +++ b/apps/frontend/src/modules/users/slices/users.ts @@ -1,8 +1,9 @@ -import { loadAll, updateProfile } from "./actions.js"; +import { deleteById, loadAll, updateProfile } from "./actions.js"; import { actions } from "./users.slice.js"; const allActions = { ...actions, + deleteById, loadAll, updateProfile, }; diff --git a/apps/frontend/src/modules/users/users-api.ts b/apps/frontend/src/modules/users/users-api.ts index 9ce24ba56..4943f8694 100644 --- a/apps/frontend/src/modules/users/users-api.ts +++ b/apps/frontend/src/modules/users/users-api.ts @@ -21,6 +21,16 @@ class UserApi extends BaseHTTPApi { super({ baseUrl, http, path: APIPath.USERS, storage }); } + public async delete(id: number): Promise { + await this.load( + this.getFullEndpoint(UsersApiPath.$ID, { id: String(id) }), + { + hasAuth: true, + method: "DELETE", + }, + ); + } + public async getAll(): Promise { const response = await this.load( this.getFullEndpoint(UsersApiPath.ROOT, {}), diff --git a/apps/frontend/src/pages/profile/components/delete-account/delete-account.tsx b/apps/frontend/src/pages/profile/components/delete-account/delete-account.tsx index e74fe873e..25bb838d4 100644 --- a/apps/frontend/src/pages/profile/components/delete-account/delete-account.tsx +++ b/apps/frontend/src/pages/profile/components/delete-account/delete-account.tsx @@ -1,14 +1,23 @@ import { Button, ConfirmationModal } from "~/libs/components/components.js"; -import { useCallback, useModal } from "~/libs/hooks/hooks.js"; -import { type UserAuthResponseDto } from "~/modules/users/users.js"; +import { AppRoute } from "~/libs/enums/enums.js"; +import { + useAppDispatch, + useCallback, + useModal, + useNavigate, +} from "~/libs/hooks/hooks.js"; +import { actions as userActions } from "~/modules/users/users.js"; import styles from "./styles.module.css"; type Properties = { - user: UserAuthResponseDto; + userId: number; }; -const DeleteAccount = ({ user }: Properties): JSX.Element => { +const DeleteAccount = ({ userId }: Properties): JSX.Element => { + const dispatch = useAppDispatch(); + const navigate = useNavigate(); + const { isModalOpened, onModalClose, onModalOpen } = useModal(); const handleDeleteClick = useCallback((): void => { @@ -16,12 +25,13 @@ const DeleteAccount = ({ user }: Properties): JSX.Element => { }, [onModalOpen]); const handleDeleteConfirm = useCallback(() => { - onModalClose(); - }, [onModalClose]); + void dispatch(userActions.deleteById(userId)); + navigate(AppRoute.SIGN_IN); + }, [dispatch, navigate, userId]); return (
-

Delete account {user.name}

+

Delete account

This action cannot be undone.

- + {authenticatedUser?.id && ( + + )}
); From c0eea80989c56797cf2278b9b14f89e59ee5cc61 Mon Sep 17 00:00:00 2001 From: HoroshkoMykhailo Date: Wed, 4 Sep 2024 16:31:25 +0300 Subject: [PATCH 08/17] feat: fix redirection to sign-in page gf-146 --- .../src/libs/components/header/header.tsx | 2 +- .../components/user-popover/user-popover.tsx | 5 ++++- apps/frontend/src/libs/components/link/link.tsx | 2 +- .../toast-container/toast-container.tsx | 2 +- .../src/libs/modules/api/base-http-api.ts | 2 +- .../components/delete-account/delete-account.tsx | 16 +++++----------- .../components/project-card/project-card.tsx | 2 +- package-lock.json | 6 +++--- 8 files changed, 17 insertions(+), 20 deletions(-) diff --git a/apps/frontend/src/libs/components/header/header.tsx b/apps/frontend/src/libs/components/header/header.tsx index fa7d9bc94..5a67e8402 100644 --- a/apps/frontend/src/libs/components/header/header.tsx +++ b/apps/frontend/src/libs/components/header/header.tsx @@ -19,7 +19,7 @@ const Header = (): JSX.Element => { return (
- +
GitFit logo Logo diff --git a/apps/frontend/src/libs/components/header/libs/components/user-popover/user-popover.tsx b/apps/frontend/src/libs/components/header/libs/components/user-popover/user-popover.tsx index cae9d3583..c864e26ce 100644 --- a/apps/frontend/src/libs/components/header/libs/components/user-popover/user-popover.tsx +++ b/apps/frontend/src/libs/components/header/libs/components/user-popover/user-popover.tsx @@ -29,7 +29,10 @@ const UserPopover = ({ children, email, name }: Properties): JSX.Element => {

{email}

- + Profile
From 3a1919900848c125074787d972500b05c2ad0c94 Mon Sep 17 00:00:00 2001 From: HoroshkoMykhailo Date: Wed, 4 Sep 2024 19:41:46 +0300 Subject: [PATCH 10/17] fix: suggested fixes gf-146 --- .../libs/components/confirmation-modal/confirmation-modal.tsx | 4 ++-- apps/frontend/src/libs/enums/notification-message.enum.ts | 4 ++-- apps/frontend/src/modules/users/slices/actions.ts | 4 ++-- apps/frontend/src/pages/profile/styles.module.css | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/frontend/src/libs/components/confirmation-modal/confirmation-modal.tsx b/apps/frontend/src/libs/components/confirmation-modal/confirmation-modal.tsx index d48b8f321..e9fbd57e2 100644 --- a/apps/frontend/src/libs/components/confirmation-modal/confirmation-modal.tsx +++ b/apps/frontend/src/libs/components/confirmation-modal/confirmation-modal.tsx @@ -3,7 +3,7 @@ import { useCallback } from "~/libs/hooks/hooks.js"; import styles from "./styles.module.css"; -type ConfirmationModalProperties = { +type Properties = { cancelLabel?: string; confirmationText: string; confirmLabel?: string; @@ -21,7 +21,7 @@ const ConfirmationModal = ({ onConfirm, onModalClose, title, -}: ConfirmationModalProperties): JSX.Element => { +}: Properties): JSX.Element => { const handleConfirmClick = useCallback(() => { onConfirm(); onModalClose(); diff --git a/apps/frontend/src/libs/enums/notification-message.enum.ts b/apps/frontend/src/libs/enums/notification-message.enum.ts index 948abd3d2..38b86129f 100644 --- a/apps/frontend/src/libs/enums/notification-message.enum.ts +++ b/apps/frontend/src/libs/enums/notification-message.enum.ts @@ -1,8 +1,8 @@ const NotificationMessage = { + PROFILE_UPDATE_SUCCESS: "Successfully updated profile information.", PROJECT_CREATE_SUCCESS: "Project was successfully created", PROJECT_UPDATE_SUCCESS: "Project was successfully updated.", - SUCCESS_PROFILE_UPDATE: "Successfully updated profile information.", - SUCCESS_USER_DELETE: "User deleted successfully.", + USER_DELETE_SUCCESS: "User deleted successfully.", } as const; export { NotificationMessage }; diff --git a/apps/frontend/src/modules/users/slices/actions.ts b/apps/frontend/src/modules/users/slices/actions.ts index 437495328..f9b50a14a 100644 --- a/apps/frontend/src/modules/users/slices/actions.ts +++ b/apps/frontend/src/modules/users/slices/actions.ts @@ -20,7 +20,7 @@ const deleteById = createAsyncThunk( const { toastNotifier, userApi } = extra; await userApi.delete(userId); - toastNotifier.showSuccess(NotificationMessage.SUCCESS_USER_DELETE); + toastNotifier.showSuccess(NotificationMessage.USER_DELETE_SUCCESS); return userId; }, @@ -46,7 +46,7 @@ const updateProfile = createAsyncThunk< const user = await userApi.patch(id, payload); void dispatch(authActions.getAuthenticatedUser()); - toastNotifier.showSuccess(NotificationMessage.SUCCESS_PROFILE_UPDATE); + toastNotifier.showSuccess(NotificationMessage.PROFILE_UPDATE_SUCCESS); return user; }); diff --git a/apps/frontend/src/pages/profile/styles.module.css b/apps/frontend/src/pages/profile/styles.module.css index 4732dc28f..4f009699b 100644 --- a/apps/frontend/src/pages/profile/styles.module.css +++ b/apps/frontend/src/pages/profile/styles.module.css @@ -24,7 +24,7 @@ } .divider { - width: 800px; + min-width: 100%; height: 1px; background: var(--color-border-primary); } From 0de15beaf632935f491c12320d42ee54b3f71ede Mon Sep 17 00:00:00 2001 From: HoroshkoMykhailo Date: Wed, 4 Sep 2024 20:26:17 +0300 Subject: [PATCH 11/17] fix: confirmation modal design gf-146 --- .../components/confirmation-modal/styles.module.css | 5 ++++- apps/frontend/src/libs/components/modal/modal.tsx | 12 ++++++------ .../src/libs/components/modal/styles.module.css | 12 ++---------- 3 files changed, 12 insertions(+), 17 deletions(-) diff --git a/apps/frontend/src/libs/components/confirmation-modal/styles.module.css b/apps/frontend/src/libs/components/confirmation-modal/styles.module.css index 62d618cfb..597f16614 100644 --- a/apps/frontend/src/libs/components/confirmation-modal/styles.module.css +++ b/apps/frontend/src/libs/components/confirmation-modal/styles.module.css @@ -1,5 +1,4 @@ .confirmation-text { - padding: 24px 0; margin: 0; font-size: 16px; font-weight: 400; @@ -11,3 +10,7 @@ gap: 10px; justify-content: flex-end; } + +.confirmation-buttons button { + min-width: 150px; +} diff --git a/apps/frontend/src/libs/components/modal/modal.tsx b/apps/frontend/src/libs/components/modal/modal.tsx index 523ffc301..9688d7d71 100644 --- a/apps/frontend/src/libs/components/modal/modal.tsx +++ b/apps/frontend/src/libs/components/modal/modal.tsx @@ -34,13 +34,13 @@ const Modal = ({ ref={dialogReference} >
-
-

{title}

-
- -
+
+ +
+
+

{title}

+ {children}
-
{children}
diff --git a/apps/frontend/src/libs/components/modal/styles.module.css b/apps/frontend/src/libs/components/modal/styles.module.css index 1c0147cd3..2eca29169 100644 --- a/apps/frontend/src/libs/components/modal/styles.module.css +++ b/apps/frontend/src/libs/components/modal/styles.module.css @@ -26,25 +26,17 @@ transform: translate(-50%, -50%); } -.modal-header { - display: flex; - flex-direction: column; - gap: 24px; - width: 100%; -} - .modal-header-title { - font-family: Inter, sans-serif; + margin: 0; font-size: 20px; font-weight: 600; - line-height: 1.3; color: var(--color-text-primary); } .modal-body { display: flex; flex-direction: column; - gap: 8px; + gap: 24px; width: 100%; font-family: Inter, sans-serif; font-size: 16px; From 4d56796bf00094b7d52bf38e4f83c1f6306ceba4 Mon Sep 17 00:00:00 2001 From: HoroshkoMykhailo Date: Thu, 5 Sep 2024 14:55:58 +0300 Subject: [PATCH 12/17] fix: remove nothing_deleted constant gf-146 --- apps/backend/src/libs/constants/constants.ts | 1 - .../src/libs/constants/nothing-deleted-count.constant.ts | 3 --- apps/backend/src/modules/users/user.repository.ts | 5 ++--- 3 files changed, 2 insertions(+), 7 deletions(-) delete mode 100644 apps/backend/src/libs/constants/nothing-deleted-count.constant.ts diff --git a/apps/backend/src/libs/constants/constants.ts b/apps/backend/src/libs/constants/constants.ts index 2b19d932e..004b01e8a 100644 --- a/apps/backend/src/libs/constants/constants.ts +++ b/apps/backend/src/libs/constants/constants.ts @@ -1,2 +1 @@ -export { NOTHING_DELETED_COUNT } from "./nothing-deleted-count.constant.js"; export { PAGE_INDEX_OFFSET } from "./page-index-offset.constant.js"; diff --git a/apps/backend/src/libs/constants/nothing-deleted-count.constant.ts b/apps/backend/src/libs/constants/nothing-deleted-count.constant.ts deleted file mode 100644 index 363288766..000000000 --- a/apps/backend/src/libs/constants/nothing-deleted-count.constant.ts +++ /dev/null @@ -1,3 +0,0 @@ -const NOTHING_DELETED_COUNT = 0; - -export { NOTHING_DELETED_COUNT }; diff --git a/apps/backend/src/modules/users/user.repository.ts b/apps/backend/src/modules/users/user.repository.ts index faf76a9ae..eccafe186 100644 --- a/apps/backend/src/modules/users/user.repository.ts +++ b/apps/backend/src/modules/users/user.repository.ts @@ -1,4 +1,3 @@ -import { NOTHING_DELETED_COUNT } from "~/libs/constants/constants.js"; import { type PaginationQueryParameters, type PaginationResponseDto, @@ -33,14 +32,14 @@ class UserRepository implements Repository { } public async delete(id: number): Promise { - const numberDeletedRows = await this.userModel + const deletedRowsCount = await this.userModel .query() .patch({ deletedAt: new Date().toISOString() }) .where({ id }) .whereNull("deletedAt") .execute(); - return numberDeletedRows > NOTHING_DELETED_COUNT; + return Boolean(deletedRowsCount); } public async find(id: number): Promise { From 8acbecfb364a067cbca69002a56f9230393de9e2 Mon Sep 17 00:00:00 2001 From: HoroshkoMykhailo Date: Thu, 5 Sep 2024 15:53:39 +0300 Subject: [PATCH 13/17] refactor: change delete success status code gf-146 --- apps/backend/src/modules/users/user.controller.ts | 4 ++-- .../shared/src/libs/modules/http/libs/enums/http-code.enum.ts | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/apps/backend/src/modules/users/user.controller.ts b/apps/backend/src/modules/users/user.controller.ts index 885eab9e1..33a04148f 100644 --- a/apps/backend/src/modules/users/user.controller.ts +++ b/apps/backend/src/modules/users/user.controller.ts @@ -93,7 +93,7 @@ class UserController extends BaseController { * schema: * type: string * responses: - * 200: + * 204: * description: User deleted successfully */ private async delete( @@ -103,7 +103,7 @@ class UserController extends BaseController { ): Promise { return { payload: await this.userService.delete(Number(options.params.id)), - status: HTTPCode.OK, + status: HTTPCode.NO_CONTENT, }; } diff --git a/packages/shared/src/libs/modules/http/libs/enums/http-code.enum.ts b/packages/shared/src/libs/modules/http/libs/enums/http-code.enum.ts index 98b580050..8adcfb1ed 100644 --- a/packages/shared/src/libs/modules/http/libs/enums/http-code.enum.ts +++ b/packages/shared/src/libs/modules/http/libs/enums/http-code.enum.ts @@ -2,6 +2,7 @@ const HTTPCode = { CONFLICT: 409, CREATED: 201, INTERNAL_SERVER_ERROR: 500, + NO_CONTENT: 204, NOT_FOUND: 404, OK: 200, UNAUTHORIZED: 401, From d678943b7bdb66fc344bed5944ed25e0fad2034c Mon Sep 17 00:00:00 2001 From: HoroshkoMykhailo Date: Thu, 5 Sep 2024 17:38:21 +0300 Subject: [PATCH 14/17] fix: delete two findByEmail gf-146 --- .../src/modules/users/user.controller.ts | 2 +- .../src/modules/users/user.repository.ts | 19 +++++++++---------- .../backend/src/modules/users/user.service.ts | 2 +- apps/frontend/src/pages/profile/profile.tsx | 2 +- .../src/pages/profile/styles.module.css | 2 +- .../modules/http/libs/enums/http-code.enum.ts | 1 - 6 files changed, 13 insertions(+), 15 deletions(-) diff --git a/apps/backend/src/modules/users/user.controller.ts b/apps/backend/src/modules/users/user.controller.ts index 33a04148f..ca58b898a 100644 --- a/apps/backend/src/modules/users/user.controller.ts +++ b/apps/backend/src/modules/users/user.controller.ts @@ -103,7 +103,7 @@ class UserController extends BaseController { ): Promise { return { payload: await this.userService.delete(Number(options.params.id)), - status: HTTPCode.NO_CONTENT, + status: HTTPCode.OK, }; } diff --git a/apps/backend/src/modules/users/user.repository.ts b/apps/backend/src/modules/users/user.repository.ts index eccafe186..18eb17f13 100644 --- a/apps/backend/src/modules/users/user.repository.ts +++ b/apps/backend/src/modules/users/user.repository.ts @@ -68,18 +68,17 @@ class UserRepository implements Repository { }; } - public async findByEmail(email: string): Promise { - const user = await this.userModel - .query() - .findOne({ email }) - .whereNull("deletedAt") - .execute(); + public async findByEmail( + email: string, + includeDeleted = false, + ): Promise { + const query = this.userModel.query().findOne({ email }); - return user ? UserEntity.initialize(user) : null; - } + if (!includeDeleted) { + query.whereNull("deletedAt"); + } - public async findByEmailCreate(email: string): Promise { - const user = await this.userModel.query().findOne({ email }).execute(); + const user = await query.execute(); return user ? UserEntity.initialize(user) : null; } diff --git a/apps/backend/src/modules/users/user.service.ts b/apps/backend/src/modules/users/user.service.ts index 822f8225b..1b72141c9 100644 --- a/apps/backend/src/modules/users/user.service.ts +++ b/apps/backend/src/modules/users/user.service.ts @@ -31,7 +31,7 @@ class UserService implements Service { payload: UserSignUpRequestDto, ): Promise { const { email, name, password } = payload; - const existingUser = await this.userRepository.findByEmailCreate(email); + const existingUser = await this.userRepository.findByEmail(email, true); if (existingUser) { throw new UserError({ diff --git a/apps/frontend/src/pages/profile/profile.tsx b/apps/frontend/src/pages/profile/profile.tsx index fee2a550d..abd011d89 100644 --- a/apps/frontend/src/pages/profile/profile.tsx +++ b/apps/frontend/src/pages/profile/profile.tsx @@ -11,7 +11,7 @@ const Profile = (): JSX.Element => { return (
-
+

Profile

diff --git a/apps/frontend/src/pages/profile/styles.module.css b/apps/frontend/src/pages/profile/styles.module.css index 421380660..1fc78a9cf 100644 --- a/apps/frontend/src/pages/profile/styles.module.css +++ b/apps/frontend/src/pages/profile/styles.module.css @@ -17,7 +17,7 @@ line-height: 120%; } -.profile-update { +.profile-info { display: flex; flex-direction: column; gap: 24px; diff --git a/packages/shared/src/libs/modules/http/libs/enums/http-code.enum.ts b/packages/shared/src/libs/modules/http/libs/enums/http-code.enum.ts index 8adcfb1ed..98b580050 100644 --- a/packages/shared/src/libs/modules/http/libs/enums/http-code.enum.ts +++ b/packages/shared/src/libs/modules/http/libs/enums/http-code.enum.ts @@ -2,7 +2,6 @@ const HTTPCode = { CONFLICT: 409, CREATED: 201, INTERNAL_SERVER_ERROR: 500, - NO_CONTENT: 204, NOT_FOUND: 404, OK: 200, UNAUTHORIZED: 401, From 303c5da2648665cb93159b6707787d6aebd859fa Mon Sep 17 00:00:00 2001 From: HoroshkoMykhailo Date: Thu, 5 Sep 2024 17:48:22 +0300 Subject: [PATCH 15/17] feat: small package-lock.json addition gf-146 --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0e2329b33..ac46853d7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52,7 +52,7 @@ }, "apps/backend": { "name": "@git-fit/backend", - "version": "1.5.0", + "version": "1.6.0", "dependencies": { "@fastify/static": "7.0.4", "@fastify/swagger": "8.15.0", @@ -130,7 +130,7 @@ }, "apps/frontend": { "name": "@git-fit/frontend", - "version": "1.8.0", + "version": "1.9.0", "dependencies": { "@git-fit/shared": "*", "@hookform/resolvers": "3.9.0", @@ -13298,7 +13298,7 @@ }, "packages/shared": { "name": "@git-fit/shared", - "version": "1.5.0", + "version": "1.7.0", "dependencies": { "change-case": "5.4.4", "date-fns": "3.6.0", From 1911604c4836705ecbbd20961d8ed492e58374a2 Mon Sep 17 00:00:00 2001 From: HoroshkoMykhailo Date: Thu, 5 Sep 2024 18:29:07 +0300 Subject: [PATCH 16/17] fix: add type casting in profile gf-146 --- apps/frontend/src/pages/profile/profile.tsx | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/apps/frontend/src/pages/profile/profile.tsx b/apps/frontend/src/pages/profile/profile.tsx index abd011d89..21770f5cd 100644 --- a/apps/frontend/src/pages/profile/profile.tsx +++ b/apps/frontend/src/pages/profile/profile.tsx @@ -7,18 +7,17 @@ import styles from "./styles.module.css"; const Profile = (): JSX.Element => { const { authenticatedUser } = useAppSelector(({ auth }) => auth); + const user = authenticatedUser as UserAuthResponseDto; return (

Profile

- +
- {authenticatedUser?.id && ( - - )} +
); From d98a06726652241562902963f5f838de9f0cf4a0 Mon Sep 17 00:00:00 2001 From: HoroshkoMykhailo Date: Thu, 5 Sep 2024 19:52:22 +0300 Subject: [PATCH 17/17] refactor: change include deleted gf-146 --- apps/backend/src/modules/users/user.repository.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/backend/src/modules/users/user.repository.ts b/apps/backend/src/modules/users/user.repository.ts index 18eb17f13..67b1f252f 100644 --- a/apps/backend/src/modules/users/user.repository.ts +++ b/apps/backend/src/modules/users/user.repository.ts @@ -70,11 +70,11 @@ class UserRepository implements Repository { public async findByEmail( email: string, - includeDeleted = false, + hasDeleted = false, ): Promise { const query = this.userModel.query().findOne({ email }); - if (!includeDeleted) { + if (!hasDeleted) { query.whereNull("deletedAt"); }