diff --git a/backend/src/modules/auth/auth.module.ts b/backend/src/modules/auth/auth.module.ts index ac50123f4..70a346f5e 100644 --- a/backend/src/modules/auth/auth.module.ts +++ b/backend/src/modules/auth/auth.module.ts @@ -1,5 +1,4 @@ import { userRepository } from 'src/modules/users/users.providers'; -import { UserRepository } from './../users/repository/user.repository'; import { mongooseBoardUserModule } from './../../infrastructure/database/mongoose.module'; import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; diff --git a/backend/src/modules/auth/services/register.auth.service.ts b/backend/src/modules/auth/services/register.auth.service.ts index eb358d5d6..e9fac7ac3 100644 --- a/backend/src/modules/auth/services/register.auth.service.ts +++ b/backend/src/modules/auth/services/register.auth.service.ts @@ -1,5 +1,4 @@ import { UserRepositoryInterface } from './../../users/repository/user.repository.interface'; -import { userRepository } from 'src/modules/users/users.providers'; import { GetTokenAuthService } from 'src/modules/auth/interfaces/services/get-token.auth.service.interface'; import { BOARD_USER_NOT_FOUND, INSERT_FAILED } from 'src/libs/exceptions/messages'; import { BadRequestException, Inject, Injectable } from '@nestjs/common'; @@ -55,7 +54,7 @@ export default class RegisterAuthServiceImpl implements RegisterAuthService { throw new BadRequestException(BOARD_USER_NOT_FOUND); } - const { _id, firstName, lastName } = userFound.user as User; + const { _id, firstName, lastName, isAnonymous } = userFound.user as User; return { role: userFound.role, @@ -64,7 +63,8 @@ export default class RegisterAuthServiceImpl implements RegisterAuthService { user: { _id: String(_id), firstName, - lastName + lastName, + isAnonymous } }; } diff --git a/backend/src/modules/boards/services/get.board.service.ts b/backend/src/modules/boards/services/get.board.service.ts index 2b639c9b6..223516bf7 100644 --- a/backend/src/modules/boards/services/get.board.service.ts +++ b/backend/src/modules/boards/services/get.board.service.ts @@ -152,7 +152,7 @@ export default class GetBoardServiceImpl implements GetBoardServiceInterface { select: 'user role -board', populate: { path: 'user', - select: '_id firstName email lastName' + select: '_id firstName email lastName isAnonymous' } }) .lean({ virtuals: true }) diff --git a/backend/src/modules/boards/utils/populate-board.ts b/backend/src/modules/boards/utils/populate-board.ts index 86e6f3f69..5355adf84 100644 --- a/backend/src/modules/boards/utils/populate-board.ts +++ b/backend/src/modules/boards/utils/populate-board.ts @@ -4,7 +4,7 @@ export const BoardDataPopulate: PopulateOptions[] = [ { path: 'users', select: 'user role -board votesCount', - populate: { path: 'user', select: 'firstName email lastName _id' } + populate: { path: 'user', select: 'firstName email lastName _id isAnonymous' } }, { path: 'team', @@ -49,7 +49,7 @@ export const GetBoardDataPopulate: PopulateOptions[] = [ { path: 'users', select: 'user role -board votesCount', - populate: { path: 'user', select: 'firstName email lastName _id' } + populate: { path: 'user', select: 'firstName email lastName _id isAnonymous' } }, { path: 'team', diff --git a/backend/src/modules/users/dto/guest.user.dto.ts b/backend/src/modules/users/dto/guest.user.dto.ts index bf60ad807..bbc42e467 100644 --- a/backend/src/modules/users/dto/guest.user.dto.ts +++ b/backend/src/modules/users/dto/guest.user.dto.ts @@ -1,5 +1,5 @@ import { ApiProperty } from '@nestjs/swagger'; -import { IsMongoId, IsNotEmpty, IsOptional, IsString } from 'class-validator'; +import { IsBoolean, IsMongoId, IsNotEmpty, IsOptional, IsString } from 'class-validator'; export default class GuestUserDto { @ApiProperty() @@ -18,4 +18,8 @@ export default class GuestUserDto { @IsOptional() @IsString() lastName?: string; + + @IsOptional() + @IsBoolean() + isAnonymous?: boolean; } diff --git a/frontend/src/components/Board/RegularBoard/ParticipantsList/ParticipantCard.tsx/index.tsx b/frontend/src/components/Board/RegularBoard/ParticipantsList/ParticipantCard.tsx/index.tsx index 9e6adc121..9616c77ff 100644 --- a/frontend/src/components/Board/RegularBoard/ParticipantsList/ParticipantCard.tsx/index.tsx +++ b/frontend/src/components/Board/RegularBoard/ParticipantsList/ParticipantCard.tsx/index.tsx @@ -20,11 +20,21 @@ type CardBodyProps = { isCurrentUserResponsible: boolean; isCurrentUserSAdmin: boolean; isMemberCurrentUser: boolean; + haveInvalidNumberOfResponsibles: boolean; + responsibleSignedUpUsers: BoardUser[]; isOpen?: boolean; }; const ParticipantCard = React.memo( - ({ member, isCurrentUserResponsible, isCurrentUserSAdmin, isMemberCurrentUser, isOpen }) => { + ({ + member, + isCurrentUserResponsible, + isCurrentUserSAdmin, + isMemberCurrentUser, + isOpen, + haveInvalidNumberOfResponsibles, + responsibleSignedUpUsers, + }) => { const { addAndRemoveBoardParticipants: { mutate }, } = useParticipants(); @@ -61,6 +71,14 @@ const ParticipantCard = React.memo( const handleSelectFunction = (checked: boolean) => updateIsResponsibleStatus(checked); + let memberOnlySignedUpResponsible: boolean = false; + + if (haveInvalidNumberOfResponsibles) { + memberOnlySignedUpResponsible = !!responsibleSignedUpUsers.find( + (boardUser) => boardUser.user._id === member.user._id, + ); + } + return ( @@ -100,6 +118,8 @@ const ParticipantCard = React.memo( isChecked={isMemberResponsible} text="" title="Responsible" + disabledInfo="Select another responsible for the board" + disabled={memberOnlySignedUpResponsible && !isCurrentUserSAdmin} /> )} diff --git a/frontend/src/components/Board/RegularBoard/ParticipantsList/index.tsx b/frontend/src/components/Board/RegularBoard/ParticipantsList/index.tsx index 4ceca9bc7..4b5dc04db 100644 --- a/frontend/src/components/Board/RegularBoard/ParticipantsList/index.tsx +++ b/frontend/src/components/Board/RegularBoard/ParticipantsList/index.tsx @@ -5,6 +5,7 @@ import { ScrollableContent } from '@/components/Boards/MyBoards/styles'; import { boardParticipantsState } from '@/store/board/atoms/board.atom'; import { BoardUserRoles } from '@/utils/enums/board.user.roles'; import { useSession } from 'next-auth/react'; +import { getGuestUserCookies } from '@/utils/getGuestUserCookies'; import ParticipantsLayout from './ParticipantsLayout'; import ParticipantCard from './ParticipantCard.tsx'; @@ -12,12 +13,25 @@ const ParticipantsList = () => { const boardParticipants = useRecoilValue(boardParticipantsState); const { data: session } = useSession(); + // User Id + const userId = getGuestUserCookies() ? getGuestUserCookies().user : session?.user.id; + const isResponsible = !!boardParticipants.find( - (boardUser) => - boardUser.user._id === session?.user.id && boardUser.role === BoardUserRoles.RESPONSIBLE, + (boardUser) => boardUser.user._id === userId && boardUser.role === BoardUserRoles.RESPONSIBLE, ); + const isSAdmin = !!session?.user.isSAdmin; + const responsiblesList = boardParticipants.filter( + (boardUser) => boardUser.role === BoardUserRoles.RESPONSIBLE, + ); + + const responsibleSignedUpUsers = responsiblesList.filter( + (boardUser) => !boardUser.user.isAnonymous, + ); + + const haveInvalidNumberOfResponsibles = responsibleSignedUpUsers.length < 2; + return ( @@ -31,9 +45,11 @@ const ParticipantsList = () => { ))} diff --git a/frontend/src/components/Board/RegularBoard/ReagularHeader/HeaderParticipants.tsx b/frontend/src/components/Board/RegularBoard/ReagularHeader/HeaderParticipants.tsx index 35565af57..97edfd491 100644 --- a/frontend/src/components/Board/RegularBoard/ReagularHeader/HeaderParticipants.tsx +++ b/frontend/src/components/Board/RegularBoard/ReagularHeader/HeaderParticipants.tsx @@ -44,7 +44,7 @@ const HeaderParticipants = ({ isParticipantsPage }: Props) => { - Board Creator + Responsibles { - const { data: session } = useSession(); - // Atoms const boardData = useRecoilValue(boardInfoState); // Get Board Info - const { title, recurrent, users, team, isSubBoard, submitedAt, _id } = boardData.board; - - // Get Team users - const teamUsers = team?.users ? team.users : []; - - const isRegularBoardWithNoTeam = !team; + const { title, recurrent, isSubBoard, submitedAt, _id } = boardData.board; // Set breadcrumbs const breadcrumbItems: BreadcrumbType = isParticipantsPage @@ -101,92 +87,17 @@ const RegularBoardHeader = ({ isParticipantsPage }: Props) => { - {!isEmpty(teamUsers) && ( - - - - - - {team?.name} - - - + + {isParticipantsPage ? ( + + ) : ( + + + - {!isEmpty( - teamUsers.filter((user: TeamUser) => user.role === TeamUserRoles.ADMIN), - ) && ( - <> - - - - - Team admins - - - - - )} - {!isEmpty( - boardData.board.team?.users.filter( - (user: TeamUser) => user.role === TeamUserRoles.STAKEHOLDER, - ), - ) && ( - <> - - - - - Stakeholders - - - - - )} - - - )} - - {isRegularBoardWithNoTeam && ( - - {isParticipantsPage ? ( - - ) : ( - - - - - - )} - - )} + + )} + diff --git a/frontend/src/components/Board/Settings/partials/ConfigurationSettings/ConfigurationSwitch.tsx b/frontend/src/components/Board/Settings/partials/ConfigurationSettings/ConfigurationSwitch.tsx index 2a002881b..cfd1bde51 100644 --- a/frontend/src/components/Board/Settings/partials/ConfigurationSettings/ConfigurationSwitch.tsx +++ b/frontend/src/components/Board/Settings/partials/ConfigurationSettings/ConfigurationSwitch.tsx @@ -25,7 +25,7 @@ const ConfigurationSwitchSettings = ({ disabledInfo, }: Props) => ( - {disabledInfo ? ( + {disabledInfo && disabled ? ( ) : ( - + )} diff --git a/frontend/src/components/Teams/CreateTeam/ListMembersDialog/index.tsx b/frontend/src/components/Teams/CreateTeam/ListMembersDialog/index.tsx index 5742372fd..bf38d8374 100644 --- a/frontend/src/components/Teams/CreateTeam/ListMembersDialog/index.tsx +++ b/frontend/src/components/Teams/CreateTeam/ListMembersDialog/index.tsx @@ -20,7 +20,7 @@ type ListMembersDialogProps = { const ListMembersDialog = React.memo( ({ usersList, isOpen, setIsOpen, saveUsers, title, btnTitle }) => { - const { data: session } = useSession({ required: true }); + const { data: session } = useSession({ required: false }); const [searchMember, setSearchMember] = useState(''); const [usersChecked, setUsersChecked] = useState(usersList); diff --git a/frontend/src/pages/boards/[boardId]/participants.tsx b/frontend/src/pages/boards/[boardId]/participants.tsx index b5b072632..b5644aa70 100644 --- a/frontend/src/pages/boards/[boardId]/participants.tsx +++ b/frontend/src/pages/boards/[boardId]/participants.tsx @@ -16,7 +16,6 @@ import { BoardUserRoles } from '@/utils/enums/board.user.roles'; import { ToastStateEnum } from '@/utils/enums/toast-types'; import { QueryClient, dehydrate, useQuery } from '@tanstack/react-query'; import { GetServerSideProps } from 'next'; -import { useSession } from 'next-auth/react'; import React, { Suspense, useCallback, useEffect } from 'react'; import { SetterOrUpdater, useRecoilState, useSetRecoilState } from 'recoil'; @@ -41,10 +40,9 @@ export const sortParticipantsList = ( }; const BoardParticipants = () => { - const { data: session } = useSession({ required: false }); const setToastState = useSetRecoilState(toastState); const [boardParticipants, setBoardParticipants] = useRecoilState(boardParticipantsState); - const setRecoilBoard = useSetRecoilState(boardInfoState); + const [recoilBoard, setRecoilBoard] = useRecoilState(boardInfoState); // Hooks const { @@ -93,8 +91,7 @@ const BoardParticipants = () => { handleMembersList(); }, [handleMembersList]); - if (!session) return null; - return ( + return recoilBoard ? ( }> @@ -107,6 +104,8 @@ const BoardParticipants = () => { + ) : ( + ); }; diff --git a/frontend/src/types/user/user.ts b/frontend/src/types/user/user.ts index 08eb2978e..2aa434bb3 100644 --- a/frontend/src/types/user/user.ts +++ b/frontend/src/types/user/user.ts @@ -17,6 +17,7 @@ export interface User { isSAdmin: boolean; joinedAt: string; providerAccountCreatedAt?: string; + isAnonymous?: boolean; } export interface UseUserType {