diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 0e90783ce7..5c9c715dd2 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -38,7 +38,7 @@ jobs: - name: Count number of lines run: | chmod +x ./.github/workflows/countline.py - ./.github/workflows/countline.py --lines 600 --exclude_files src/screens/LoginPage/LoginPage.tsx src/GraphQl/Queries/Queries.ts + ./.github/workflows/countline.py --lines 600 --exclude_files src/screens/LoginPage/LoginPage.tsx src/GraphQl/Queries/Queries.ts src/screens/OrgList/OrgList.tsx - name: Get changed TypeScript files id: changed-files diff --git a/.husky/pre-commit b/.husky/pre-commit index c9c109cceb..94bdd644c0 100755 --- a/.husky/pre-commit +++ b/.husky/pre-commit @@ -2,7 +2,7 @@ . "$(dirname -- "$0")/_/husky.sh" # npm run format:fix -# npm run lint:fix +npm run lint:fix npm run lint-staged npm run typecheck npm run update:toc diff --git a/schema.graphql b/schema.graphql index cb95948ec3..5d22b608ac 100644 --- a/schema.graphql +++ b/schema.graphql @@ -2,14 +2,83 @@ directive @auth on FIELD_DEFINITION directive @role(requires: UserType) on FIELD_DEFINITION +type ActionItem { + _id: ID! + actionItemCategory: ActionItemCategory + assignee: User + assigner: User + assignmentDate: Date! + completionDate: Date! + createdAt: Date! + creator: User + dueDate: Date! + event: Event + isCompleted: Boolean! + postCompletionNotes: String + preCompletionNotes: String + updatedAt: Date! +} + +type ActionItemCategory { + _id: ID! + createdAt: Date! + creator: User + isDisabled: Boolean! + name: String! + organization: Organization + updatedAt: Date! +} + +type Address { + city: String + countryCode: String + dependentLocality: String + line1: String + line2: String + postalCode: String + sortingCode: String + state: String +} + +input AddressInput { + city: String + countryCode: String + dependentLocality: String + line1: String + line2: String + postalCode: String + sortingCode: String + state: String +} + type Advertisement { - _id: ID + _id: ID! + createdAt: DateTime! + creator: User endDate: Date! mediaUrl: URL! name: String! - organization: Organization + orgId: ID! startDate: Date! - type: String! + type: AdvertisementType! + updatedAt: DateTime! +} + +enum AdvertisementType { + BANNER + MENU + POPUP +} + +type AgendaCategory { + _id: ID! + createdAt: Date! + createdBy: User! + description: String + name: String! + organization: Organization! + updatedAt: Date + updatedBy: User } type AggregatePost { @@ -20,18 +89,23 @@ type AggregateUser { count: Int! } -type AndroidFirebaseOptions { - apiKey: String - appId: String - messagingSenderId: String - projectId: String - storageBucket: String +scalar Any + +type AppUserProfile { + _id: ID! + adminFor: [Organization] + appLanguageCode: String! + createdEvents: [Event] + createdOrganizations: [Organization] + eventAdmin: [Event] + isSuperAdmin: Boolean! + pluginCreationAllowed: Boolean! + userId: User! } type AuthData { accessToken: String! - androidFirebaseOptions: AndroidFirebaseOptions! - iosFirebaseOptions: IOSFirebaseOptions! + appUserProfile: AppUserProfile! refreshToken: String! user: User! } @@ -40,9 +114,11 @@ type CheckIn { _id: ID! allotedRoom: String allotedSeat: String + createdAt: DateTime! event: Event! feedbackSubmitted: Boolean! time: DateTime! + updatedAt: DateTime! user: User! } @@ -60,13 +136,14 @@ type CheckInStatus { } type Comment { - _id: ID - createdAt: DateTime - creator: User! + _id: ID! + createdAt: DateTime! + creator: User likeCount: Int likedBy: [User] post: Post! text: String! + updatedAt: DateTime! } input CommentInput { @@ -82,6 +159,21 @@ type ConnectionPageInfo { startCursor: String } +scalar CountryCode + +input CreateActionItemInput { + assigneeId: ID! + dueDate: Date + eventId: ID + preCompletionNotes: String +} + +input CreateAgendaCategoryInput { + description: String + name: String! + organizationId: ID! +} + input CreateUserTagInput { name: String! organizationId: ID! @@ -104,9 +196,11 @@ type DeletePayload { type DirectChat { _id: ID! - creator: User! + createdAt: DateTime! + creator: User messages: [DirectChatMessage] organization: Organization! + updatedAt: DateTime! users: [User!]! } @@ -117,15 +211,18 @@ type DirectChatMessage { messageContent: String! receiver: User! sender: User! + updatedAt: DateTime! } type Donation { _id: ID! amount: Float! + createdAt: DateTime! nameOfOrg: String! nameOfUser: String! orgId: ID! payPalId: String! + updatedAt: DateTime! userId: ID! } @@ -144,22 +241,49 @@ input DonationWhereInput { name_of_user_starts_with: String } +enum EducationGrade { + GRADE_1 + GRADE_2 + GRADE_3 + GRADE_4 + GRADE_5 + GRADE_6 + GRADE_7 + GRADE_8 + GRADE_9 + GRADE_10 + GRADE_11 + GRADE_12 + GRADUATE + KG + NO_GRADE + PRE_KG +} + scalar EmailAddress +enum EmploymentStatus { + FULL_TIME + PART_TIME + UNEMPLOYED +} + interface Error { message: String! } type Event { _id: ID! - admins(adminId: ID): [User] + actionItems: [ActionItem] + admins(adminId: ID): [User!] allDay: Boolean! - attendees: [User!]! + attendees: [User] attendeesCheckInStatus: [CheckInStatus!]! averageFeedbackScore: Float - creator: User! + createdAt: DateTime! + creator: User description: String! - endDate: Date! + endDate: Date endTime: Time feedback: [Feedback!]! isPublic: Boolean! @@ -174,6 +298,7 @@ type Event { startTime: Time status: Status! title: String! + updatedAt: DateTime! } input EventAttendeeInput { @@ -222,7 +347,27 @@ enum EventOrderByInput { title_DESC } +type EventVolunteer { + _id: ID! + createdAt: DateTime! + creator: User + event: Event + isAssigned: Boolean + isInvited: Boolean + response: String + updatedAt: DateTime! + user: User! +} +input EventVolunteerInput { + eventId: ID! + userId: ID! +} + +enum EventVolunteerResponse { + NO + YES +} input EventWhereInput { description: String @@ -259,9 +404,11 @@ type ExtendSession { type Feedback { _id: ID! + createdAt: DateTime! event: Event! rating: Int! review: String + updatedAt: DateTime! } input FeedbackInput { @@ -281,20 +428,36 @@ input ForgotPasswordData { userOtp: String! } +enum Frequency { + DAILY + MONTHLY + WEEKLY + YEARLY +} + +enum Gender { + FEMALE + MALE + OTHER +} + type Group { - _id: ID - admins: [User] - createdAt: DateTime + _id: ID! + admins: [User!]! + createdAt: DateTime! description: String organization: Organization! - title: String + title: String! + updatedAt: DateTime! } type GroupChat { _id: ID! - creator: User! + createdAt: DateTime! + creator: User messages: [GroupChatMessage] organization: Organization! + updatedAt: DateTime! users: [User!]! } @@ -304,16 +467,7 @@ type GroupChatMessage { groupChatMessageBelongsTo: GroupChat! messageContent: String! sender: User! -} - -type IOSFirebaseOptions { - apiKey: String - appId: String - iosBundleId: String - iosClientId: String - messagingSenderId: String - projectId: String - storageBucket: String + updatedAt: DateTime! } type InvalidCursor implements FieldError { @@ -321,6 +475,8 @@ type InvalidCursor implements FieldError { path: [String!]! } +scalar JSON + type Language { _id: ID! createdAt: String! @@ -351,6 +507,15 @@ input LoginInput { scalar Longitude +enum MaritalStatus { + DIVORCED + ENGAGED + MARRIED + SEPERATED + SINGLE + WIDOWED +} + type MaximumLengthError implements FieldError { message: String! path: [String!]! @@ -370,10 +535,11 @@ type MembershipRequest { type Message { _id: ID! - createdAt: DateTime + createdAt: DateTime! creator: User imageUrl: URL - text: String + text: String! + updatedAt: DateTime! videoUrl: URL } @@ -384,6 +550,7 @@ type MessageChat { message: String! receiver: User! sender: User! + updatedAt: DateTime! } input MessageChatInput { @@ -427,18 +594,48 @@ type Mutation { addEventAttendee(data: EventAttendeeInput!): User! addFeedback(data: FeedbackInput!): Feedback! addLanguageTranslation(data: LanguageInput!): Language! + addOrganizationCustomField( + name: String! + organizationId: ID! + type: String! + ): OrganizationCustomField! addOrganizationImage(file: String!, organizationId: String!): Organization! + addUserCustomData( + dataName: String! + dataValue: Any! + organizationId: ID! + ): UserCustomData! addUserImage(file: String!): User! addUserToGroupChat(chatId: ID!, userId: ID!): GroupChat! + addUserToUserFamily(familyId: ID!, userId: ID!): UserFamily! adminRemoveEvent(eventId: ID!): Event! adminRemoveGroup(groupId: ID!): GroupChat! assignUserTag(input: ToggleUserTagAssignInput!): User - blockPluginCreationBySuperadmin(blockUser: Boolean!, userId: ID!): User! + blockPluginCreationBySuperadmin( + blockUser: Boolean! + userId: ID! + ): AppUserProfile! blockUser(organizationId: ID!, userId: ID!): User! cancelMembershipRequest(membershipRequestId: ID!): MembershipRequest! checkIn(data: CheckInInput!): CheckIn! - createAdmin(data: UserAndOrganizationInput!): User! - createAdvertisement(input: CreateAdvertisementInput!): CreateAdvertisementPayload + createActionItem( + actionItemCategoryId: ID! + data: CreateActionItemInput! + ): ActionItem! + createActionItemCategory( + name: String! + organizationId: ID! + ): ActionItemCategory! + createAdmin(data: UserAndOrganizationInput!): AppUserProfile! + createAdvertisement( + endDate: Date! + link: String! + name: String! + orgId: ID! + startDate: Date! + type: String! + ): Advertisement! + createAgendaCategory(input: CreateAgendaCategoryInput!): AgendaCategory! createComment(data: CommentInput!, postId: ID!): Comment createDirectChat(data: createChatInput!): DirectChat! createDonation( @@ -449,7 +646,11 @@ type Mutation { payPalId: ID! userId: ID! ): Donation! - createEvent(data: EventInput): Event! + createEvent( + data: EventInput! + recurrenceRuleData: RecurrenceRuleInput + ): Event! + createEventVolunteer(data: EventVolunteerInput!): EventVolunteer! createGroupChat(data: createGroupChatInput!): GroupChat! createMember(input: UserAndOrganizationInput!): Organization! createMessageChat(data: MessageChatInput!): MessageChat! @@ -461,8 +662,14 @@ type Mutation { uninstalledOrgs: [ID!] ): Plugin! createPost(data: PostInput!, file: String): Post + createSampleOrganization: Boolean! + createUserFamily(data: createUserFamilyInput!): UserFamily! createUserTag(input: CreateUserTagInput!): UserTag +<<<<<<< HEAD deleteAdvertisement(id: ID!): DeletePayload! +======= + deleteAdvertisementById(id: ID!): DeletePayload! + deleteAgendaCategory(id: ID!): ID! deleteDonationById(id: ID!): DeletePayload! forgotPassword(data: ForgotPasswordData!): Boolean! joinPublicOrganization(organizationId: ID!): User! @@ -477,21 +684,31 @@ type Mutation { registerForEvent(id: ID!): Event! rejectAdmin(id: ID!): Boolean! rejectMembershipRequest(membershipRequestId: ID!): MembershipRequest! - removeAdmin(data: UserAndOrganizationInput!): User! + removeActionItem(id: ID!): ActionItem! + removeAdmin(data: UserAndOrganizationInput!): AppUserProfile! removeAdvertisement(id: ID!): Advertisement removeComment(id: ID!): Comment removeDirectChat(chatId: ID!, organizationId: ID!): DirectChat! removeEvent(id: ID!): Event! removeEventAttendee(data: EventAttendeeInput!): User! + removeEventVolunteer(id: ID!): EventVolunteer! removeGroupChat(chatId: ID!): GroupChat! removeMember(data: UserAndOrganizationInput!): Organization! - removeOrganization(id: ID!): User! + removeOrganization(id: ID!): UserData! + removeOrganizationCustomField( + customFieldId: ID! + organizationId: ID! + ): OrganizationCustomField! removeOrganizationImage(organizationId: String!): Organization! removePost(id: ID!): Post + removeSampleOrganization: Boolean! + removeUserCustomData(organizationId: ID!): UserCustomData! + removeUserFamily(familyId: ID!): UserFamily! removeUserFromGroupChat(chatId: ID!, userId: ID!): GroupChat! + removeUserFromUserFamily(familyId: ID!, userId: ID!): UserFamily! removeUserImage: User! removeUserTag(id: ID!): UserTag - revokeRefreshTokenForUser(userId: String!): Boolean! + revokeRefreshTokenForUser: Boolean! saveFcmToken(token: String): Boolean! sendMembershipRequest(organizationId: ID!): MembershipRequest! sendMessageToDirectChat( @@ -503,13 +720,29 @@ type Mutation { messageContent: String! ): GroupChatMessage! signUp(data: UserInput!, file: String): AuthData! - togglePostPin(id: ID!): Post! + togglePostPin(id: ID!, title: String): Post! unassignUserTag(input: ToggleUserTagAssignInput!): User unblockUser(organizationId: ID!, userId: ID!): User! unlikeComment(id: ID!): Comment unlikePost(id: ID!): Post unregisterForEventByUser(id: ID!): Event! + updateActionItem(data: UpdateActionItemInput!, id: ID!): ActionItem + updateActionItemCategory( + data: UpdateActionItemCategoryInput! + id: ID! + ): ActionItemCategory + updateAdvertisement( + input: UpdateAdvertisementInput! + ): UpdateAdvertisementPayload + updateAgendaCategory( + id: ID! + input: UpdateAgendaCategoryInput! + ): AgendaCategory updateEvent(data: UpdateEventInput, id: ID!): Event! + updateEventVolunteer( + data: UpdateEventVolunteerInput + id: ID! + ): EventVolunteer! updateLanguage(languageCode: String!): User! updateOrganization( data: UpdateOrganizationInput @@ -518,8 +751,13 @@ type Mutation { ): Organization! updatePluginStatus(id: ID!, orgId: ID!): Plugin! updatePost(data: PostUpdateInput, id: ID!): Post! - updateUserPassword(data: UpdateUserPasswordInput!): User! + updateUserPassword(data: UpdateUserPasswordInput!): UserData! updateUserProfile(data: UpdateUserInput, file: String): User! + updateUserRoleInOrganization( + organizationId: ID! + role: String! + userId: ID! + ): Organization! updateUserTag(input: UpdateUserTagInput!): UserTag updateUserType(data: UpdateUserTypeInput!): Boolean! } @@ -530,19 +768,23 @@ input OTPInput { type Organization { _id: ID! - admins(adminId: ID): [User] + actionItemCategories: [ActionItemCategory] + address: Address + admins(adminId: ID): [User!] + agendaCategories: [AgendaCategory] apiUrl: URL! blockedUsers: [User] - createdAt: DateTime - creator: User! + createdAt: DateTime! + creator: User + customFields: [OrganizationCustomField!]! description: String! image: String - userRegistrationRequired: Boolean! - location: String members: [User] membershipRequests: [MembershipRequest] name: String! pinnedPosts: [Post] + updatedAt: DateTime! + userRegistrationRequired: Boolean! userTags( after: String before: String @@ -552,26 +794,33 @@ type Organization { visibleInSearch: Boolean! } +type OrganizationCustomField { + _id: ID! + name: String! + organizationId: String! + type: String! +} + type OrganizationInfoNode { _id: ID! apiUrl: URL! - creator: User! + creator: User description: String! image: String - userRegistrationRequired: Boolean! name: String! + userRegistrationRequired: Boolean! visibleInSearch: Boolean! } input OrganizationInput { + address: AddressInput! apiUrl: URL attendees: String description: String! image: String - userRegistrationRequired: Boolean! - location: String name: String! - visibleInSearch: Boolean! + userRegistrationRequired: Boolean + visibleInSearch: Boolean } enum OrganizationOrderByInput { @@ -606,13 +855,13 @@ input OrganizationWhereInput { id_not: ID id_not_in: [ID!] id_starts_with: ID - userRegistrationRequired: Boolean name: String name_contains: String name_in: [String!] name_not: String name_not_in: [String!] name_starts_with: String + userRegistrationRequired: Boolean visibleInSearch: Boolean } @@ -652,11 +901,11 @@ type Plugin { pluginCreatedBy: String! pluginDesc: String! pluginName: String! - uninstalledOrgs: [ID!]! + uninstalledOrgs: [ID!] } type PluginField { - createdAt: DateTime + createdAt: DateTime! key: String! status: Status! value: String! @@ -681,8 +930,8 @@ type Post { _id: ID commentCount: Int comments: [Comment] - createdAt: DateTime - creator: User! + createdAt: DateTime! + creator: User imageUrl: URL likeCount: Int likedBy: [User] @@ -690,6 +939,7 @@ type Post { pinned: Boolean text: String! title: String + updatedAt: DateTime! videoUrl: URL } @@ -768,11 +1018,20 @@ input PostWhereInput { } type Query { + actionItem(id: ID!): ActionItem + actionItemCategoriesByOrganization(organizationId: ID!): [ActionItemCategory] + actionItemCategory(id: ID!): ActionItemCategory + actionItemsByEvent(eventId: ID!): [ActionItem] + actionItemsByOrganization(organizationId: ID!): [ActionItem] adminPlugin(orgId: ID!): [Plugin] + agendaCategory(id: ID!): AgendaCategory! checkAuth: User! + customDataByOrganization(organizationId: ID!): [UserCustomData!]! + customFieldsByOrganization(id: ID!): [OrganizationCustomField] directChatsByUserID(id: ID!): [DirectChat] directChatsMessagesByChatID(id: ID!): [DirectChatMessage] event(id: ID!): Event + eventVolunteersByEvent(id: ID!): [EventVolunteer] eventsByOrganization(id: ID, orderBy: EventOrderByInput): [Event] eventsByOrganizationConnection( first: Int @@ -792,8 +1051,9 @@ type Query { getPlugins: [Plugin] getlanguage(lang_code: String!): [Translation] hasSubmittedFeedback(eventId: ID!, userId: ID!): Boolean + isSampleOrganization(id: ID!): Boolean! joinedOrganizations(id: ID): [Organization] - me: User! + me: UserData! myLanguage: String organizations(id: ID, orderBy: OrganizationOrderByInput): [Organization] organizationsConnection( @@ -821,15 +1081,21 @@ type Query { ): PostConnection registeredEventsByUser(id: ID, orderBy: EventOrderByInput): [Event] registrantsByEvent(id: ID!): [User] - user(id: ID!): User! + user(id: ID!): UserData! userLanguage(userId: ID!): String - users(orderBy: UserOrderByInput, where: UserWhereInput): [User] + users( + adminApproved: Boolean + first: Int + orderBy: UserOrderByInput + skip: Int + where: UserWhereInput + ): [UserData] usersConnection( first: Int orderBy: UserOrderByInput skip: Int where: UserWhereInput - ): [User]! + ): [UserData]! } input RecaptchaVerification { @@ -844,6 +1110,12 @@ enum Recurrance { YEARLY } +input RecurrenceRuleInput { + count: Int + frequency: Frequency + weekDays: [WeekDays] +} + enum Status { ACTIVE BLOCKED @@ -886,6 +1158,38 @@ type UnauthorizedError implements Error { message: String! } +input UpdateActionItemCategoryInput { + isDisabled: Boolean + name: String +} + +input UpdateActionItemInput { + assigneeId: ID + completionDate: Date + dueDate: Date + isCompleted: Boolean + postCompletionNotes: String + preCompletionNotes: String +} + +input UpdateAdvertisementInput { + _id: ID! + endDate: Date + link: String + name: String + startDate: Date + type: AdvertisementType +} + +type UpdateAdvertisementPayload { + advertisement: Advertisement +} + +input UpdateAgendaCategoryInput { + description: String + name: String +} + input UpdateEventInput { allDay: Boolean description: String @@ -903,20 +1207,32 @@ input UpdateEventInput { title: String } +input UpdateEventVolunteerInput { + eventId: ID + isAssigned: Boolean + isInvited: Boolean + response: EventVolunteerResponse +} + input UpdateOrganizationInput { + address: AddressInput description: String - userRegistrationRequired: Boolean - location: String name: String + userRegistrationRequired: Boolean visibleInSearch: Boolean } input UpdateUserInput { - id: ID + address: AddressInput + birthDate: Date + educationGrade: EducationGrade email: EmailAddress + employmentStatus: EmploymentStatus firstName: String + gender: Gender lastName: String - applangcode: String + maritalStatus: MaritalStatus + phone: UserPhoneInput } input UpdateUserPasswordInput { @@ -939,21 +1255,24 @@ scalar Upload type User { _id: ID! + address: Address adminApproved: Boolean - adminFor: [Organization] - appLanguageCode: String! - createdAt: DateTime - createdEvents: [Event] - createdOrganizations: [Organization] + appUserProfileId: AppUserProfile + birthDate: Date + createdAt: DateTime! + educationGrade: EducationGrade email: EmailAddress! - eventAdmin: [Event] + employmentStatus: EmploymentStatus firstName: String! + gender: Gender image: String joinedOrganizations: [Organization] lastName: String! + maritalStatus: MaritalStatus membershipRequests: [MembershipRequest] organizationsBlockedBy: [Organization] - pluginCreationAllowed: Boolean + phone: UserPhone + pluginCreationAllowed: Boolean! registeredEvents: [Event] tagsAssignedWith( after: String @@ -962,8 +1281,7 @@ type User { last: PositiveInt organizationId: ID ): UserTagsConnection - tokenVersion: Int! - userType: String + updatedAt: DateTime! } input UserAndOrganizationInput { @@ -977,11 +1295,31 @@ type UserConnection { pageInfo: PageInfo! } +type UserCustomData { + _id: ID! + organizationId: ID! + userId: ID! + values: JSON! +} + +type UserData { + appUserProfile: AppUserProfile! + user: User! +} + type UserEdge { cursor: String! node: User! } +type UserFamily { + _id: ID! + admins: [User!]! + creator: User! + title: String + users: [User!]! +} + input UserInput { appLanguageCode: String email: EmailAddress! @@ -992,8 +1330,6 @@ input UserInput { } enum UserOrderByInput { - appLanguageCode_ASC - appLanguageCode_DESC email_ASC email_DESC firstName_ASC @@ -1004,6 +1340,18 @@ enum UserOrderByInput { lastName_DESC } +type UserPhone { + home: PhoneNumber + mobile: PhoneNumber + work: PhoneNumber +} + +input UserPhoneInput { + home: PhoneNumber + mobile: PhoneNumber + work: PhoneNumber +} + type UserTag { _id: ID! childTags(input: UserTagsConnectionInput!): UserTagsConnectionResult! @@ -1036,18 +1384,12 @@ type UserTagsConnectionResult { enum UserType { ADMIN + NON_USER SUPERADMIN USER } input UserWhereInput { - admin_for: ID - appLanguageCode: String - appLanguageCode_contains: String - appLanguageCode_in: [String!] - appLanguageCode_not: String - appLanguageCode_not_in: [String!] - appLanguageCode_starts_with: String email: EmailAddress email_contains: EmailAddress email_in: [EmailAddress!] @@ -1091,6 +1433,16 @@ type UsersConnectionResult { errors: [ConnectionError!]! } +enum WeekDays { + FR + MO + SA + SU + TH + TU + WE +} + input createChatInput { organizationId: ID! userIds: [ID!]! @@ -1101,3 +1453,8 @@ input createGroupChatInput { title: String! userIds: [ID!]! } + +input createUserFamilyInput { + title: String! + userIds: [ID!]! +} diff --git a/src/App.test.tsx b/src/App.test.tsx index 1d2ffabab0..8caf69b9d8 100644 --- a/src/App.test.tsx +++ b/src/App.test.tsx @@ -10,6 +10,9 @@ import { store } from 'state/store'; import { CHECK_AUTH } from 'GraphQl/Queries/Queries'; import i18nForTest from './utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem } = useLocalStorage(); // Mock the modules for PieChart rendering as they require a trasformer being used (which is not done by Jest) // These modules are used by the Feedback components @@ -52,6 +55,7 @@ async function wait(ms = 100): Promise { describe('Testing the App Component', () => { test('Component should be rendered properly and user is loggedin', async () => { + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); render( diff --git a/src/App.tsx b/src/App.tsx index cdf6b72315..900a9e4a61 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -21,7 +21,7 @@ import OrganizationFunds from 'screens/OrganizationFunds/OrganizationFunds'; import OrganizationPeople from 'screens/OrganizationPeople/OrganizationPeople'; import PageNotFound from 'screens/PageNotFound/PageNotFound'; import Users from 'screens/Users/Users'; - +import React, { useEffect } from 'react'; // User Portal Components import Donate from 'screens/UserPortal/Donate/Donate'; import Events from 'screens/UserPortal/Events/Events'; @@ -31,9 +31,14 @@ import People from 'screens/UserPortal/People/People'; import Settings from 'screens/UserPortal/Settings/Settings'; // import UserLoginPage from 'screens/UserPortal/UserLoginPage/UserLoginPage'; // import Chat from 'screens/UserPortal/Chat/Chat'; +import { useQuery } from '@apollo/client'; +import { CHECK_AUTH } from 'GraphQl/Queries/Queries'; import Advertisements from 'components/Advertisements/Advertisements'; import SecuredRouteForUser from 'components/UserPortal/SecuredRouteForUser/SecuredRouteForUser'; -import React from 'react'; + +import useLocalStorage from 'utils/useLocalstorage'; + +const { setItem } = useLocalStorage(); function app(): JSX.Element { /*const { updatePluginLinks, updateInstalled } = bindActionCreators( @@ -61,6 +66,21 @@ function app(): JSX.Element { // TODO: Fetch Installed plugin extras and store for use within MainContent and Side Panel Components. + const { data, loading } = useQuery(CHECK_AUTH); + + useEffect(() => { + if (data) { + setItem('name', `${data.checkAuth.firstName} ${data.checkAuth.lastName}`); + setItem('id', data.checkAuth._id); + setItem('email', data.checkAuth.email); + setItem('IsLoggedIn', 'TRUE'); + setItem('FirstName', data.checkAuth.firstName); + setItem('LastName', data.checkAuth.lastName); + setItem('UserImage', data.checkAuth.image); + setItem('Email', data.checkAuth.email); + } + }, [data, loading]); + const extraRoutes = Object.entries(installedPlugins).map( (plugin: any, index) => { const extraComponent = plugin[1]; diff --git a/src/GraphQl/Mutations/mutations.ts b/src/GraphQl/Mutations/mutations.ts index 9d21af1c21..ddb28e101e 100644 --- a/src/GraphQl/Mutations/mutations.ts +++ b/src/GraphQl/Mutations/mutations.ts @@ -83,16 +83,8 @@ export const ADDRESS_DETAILS_FRAGMENT = gql` // to update the details of the user export const UPDATE_USER_MUTATION = gql` - mutation UpdateUserProfile( - $firstName: String - $lastName: String - $email: EmailAddress - $file: String - ) { - updateUserProfile( - data: { firstName: $firstName, lastName: $lastName, email: $email } - file: $file - ) { + mutation Mutation($data: UpdateUserInput, $file: String) { + updateUserProfile(data: $data, file: $file) { _id } } @@ -151,12 +143,17 @@ export const LOGIN_MUTATION = gql` login(data: { email: $email, password: $password }) { user { _id - userType - adminApproved firstName lastName - email image + email + } + appUserProfile { + adminApproved + adminFor { + _id + } + isSuperAdmin } accessToken refreshToken @@ -581,32 +578,42 @@ export const REGISTER_EVENT = gql` `; // Create and Update Action Item Categories -export { CREATE_ACTION_ITEM_CATEGORY_MUTATION } from './ActionItemCategoryMutations'; -export { UPDATE_ACTION_ITEM_CATEGORY_MUTATION } from './ActionItemCategoryMutations'; +export { + CREATE_ACTION_ITEM_CATEGORY_MUTATION, + UPDATE_ACTION_ITEM_CATEGORY_MUTATION, +} from './ActionItemCategoryMutations'; // Create, Update and Delete Action Items -export { CREATE_ACTION_ITEM_MUTATION } from './ActionItemMutations'; -export { UPDATE_ACTION_ITEM_MUTATION } from './ActionItemMutations'; -export { DELETE_ACTION_ITEM_MUTATION } from './ActionItemMutations'; +export { + CREATE_ACTION_ITEM_MUTATION, + DELETE_ACTION_ITEM_MUTATION, + UPDATE_ACTION_ITEM_MUTATION, +} from './ActionItemMutations'; // Changes the role of a event in an organization and add and remove the event from the organization -export { ADD_EVENT_ATTENDEE } from './EventAttendeeMutations'; -export { REMOVE_EVENT_ATTENDEE } from './EventAttendeeMutations'; -export { MARK_CHECKIN } from './EventAttendeeMutations'; +export { + ADD_EVENT_ATTENDEE, + MARK_CHECKIN, + REMOVE_EVENT_ATTENDEE, +} from './EventAttendeeMutations'; // Create the new comment on a post and Like and Unlike the comment -export { CREATE_COMMENT_POST } from './CommentMutations'; -export { LIKE_COMMENT } from './CommentMutations'; -export { UNLIKE_COMMENT } from './CommentMutations'; +export { + CREATE_COMMENT_POST, + LIKE_COMMENT, + UNLIKE_COMMENT, +} from './CommentMutations'; // Changes the role of a user in an organization -export { UPDATE_USER_ROLE_IN_ORG_MUTATION } from './OrganizationMutations'; -export { CREATE_SAMPLE_ORGANIZATION_MUTATION } from './OrganizationMutations'; -export { REMOVE_SAMPLE_ORGANIZATION_MUTATION } from './OrganizationMutations'; -export { CREATE_DIRECT_CHAT } from './OrganizationMutations'; -export { PLUGIN_SUBSCRIPTION } from './OrganizationMutations'; -export { TOGGLE_PINNED_POST } from './OrganizationMutations'; -export { ADD_CUSTOM_FIELD } from './OrganizationMutations'; -export { REMOVE_CUSTOM_FIELD } from './OrganizationMutations'; -export { SEND_MEMBERSHIP_REQUEST } from './OrganizationMutations'; -export { JOIN_PUBLIC_ORGANIZATION } from './OrganizationMutations'; +export { + ADD_CUSTOM_FIELD, + CREATE_DIRECT_CHAT, + CREATE_SAMPLE_ORGANIZATION_MUTATION, + JOIN_PUBLIC_ORGANIZATION, + PLUGIN_SUBSCRIPTION, + REMOVE_CUSTOM_FIELD, + REMOVE_SAMPLE_ORGANIZATION_MUTATION, + SEND_MEMBERSHIP_REQUEST, + TOGGLE_PINNED_POST, + UPDATE_USER_ROLE_IN_ORG_MUTATION, +} from './OrganizationMutations'; diff --git a/src/GraphQl/Queries/OrganizationQueries.ts b/src/GraphQl/Queries/OrganizationQueries.ts index b92551bb4c..24d31d1a04 100644 --- a/src/GraphQl/Queries/OrganizationQueries.ts +++ b/src/GraphQl/Queries/OrganizationQueries.ts @@ -37,8 +37,12 @@ export const ORGANIZATION_POST_LIST = gql` } createdAt likeCount + likedBy { + _id + firstName + lastName + } commentCount - pinned } cursor @@ -124,11 +128,13 @@ export const USER_ORGANIZATION_CONNECTION = gql` export const USER_JOINED_ORGANIZATIONS = gql` query UserJoinedOrganizations($id: ID!) { users(where: { id: $id }) { - joinedOrganizations { - _id - name - description - image + user { + joinedOrganizations { + _id + name + description + image + } } } } @@ -144,11 +150,13 @@ export const USER_JOINED_ORGANIZATIONS = gql` export const USER_CREATED_ORGANIZATIONS = gql` query UserCreatedOrganizations($id: ID!) { users(where: { id: $id }) { - createdOrganizations { - _id - name - description - image + appUserProfile { + createdOrganizations { + _id + name + description + image + } } } } diff --git a/src/GraphQl/Queries/Queries.ts b/src/GraphQl/Queries/Queries.ts index bb83002f57..f06e129f37 100644 --- a/src/GraphQl/Queries/Queries.ts +++ b/src/GraphQl/Queries/Queries.ts @@ -10,7 +10,6 @@ export const CHECK_AUTH = gql` lastName image email - userType } } `; @@ -105,63 +104,81 @@ export const USER_LIST = gql` skip: $skip first: $first ) { - firstName - lastName - image - _id - email - userType - adminApproved - adminFor { + user { _id - } - createdAt - organizationsBlockedBy { - _id - name - image - address { - city - countryCode - dependentLocality - line1 - line2 - postalCode - sortingCode - state + joinedOrganizations { + _id + name + image + createdAt + address { + city + countryCode + dependentLocality + line1 + line2 + postalCode + sortingCode + state + } + creator { + _id + firstName + lastName + image + email + } } + firstName + lastName + email + image createdAt - creator { + registeredEvents { _id - firstName - lastName + } + organizationsBlockedBy { + _id + name image - email + address { + city + countryCode + dependentLocality + line1 + line2 + postalCode + sortingCode + state + } + creator { + _id + firstName + lastName + image + email + } createdAt } + membershipRequests { + _id + } } - joinedOrganizations { + appUserProfile { + adminApproved _id - name - image - address { - city - countryCode - dependentLocality - line1 - line2 - postalCode - sortingCode - state + adminFor { + _id } - createdAt - creator { + isSuperAdmin + createdOrganizations { + _id + } + createdEvents { + _id + } + eventAdmin { _id - firstName - lastName - image - email - createdAt } } } @@ -381,7 +398,6 @@ export const ORGANIZATIONS_MEMBER_CONNECTION_LIST = gql` $orgId: ID! $firstName_contains: String $lastName_contains: String - $admin_for: ID $event_title_contains: String $first: Int $skip: Int @@ -393,7 +409,6 @@ export const ORGANIZATIONS_MEMBER_CONNECTION_LIST = gql` where: { firstName_contains: $firstName_contains lastName_contains: $lastName_contains - admin_for: $admin_for event_title_contains: $event_title_contains } ) { @@ -411,17 +426,13 @@ export const ORGANIZATIONS_MEMBER_CONNECTION_LIST = gql` // To take the list of the oranization joined by a user export const USER_ORGANIZATION_LIST = gql` - query User($id: ID!) { - user(id: $id) { - firstName - lastName - image - email - userType - adminFor { - _id - name + query User($userId: ID!) { + user(id: $userId) { + user { + firstName + email image + lastName } } } @@ -431,38 +442,39 @@ export const USER_ORGANIZATION_LIST = gql` export const USER_DETAILS = gql` query User($id: ID!) { user(id: $id) { - image - firstName - lastName - email - appLanguageCode - userType - pluginCreationAllowed - adminApproved - createdAt - adminFor { - _id - } - createdOrganizations { - _id - } - joinedOrganizations { - _id - } - organizationsBlockedBy { - _id - } - createdEvents { - _id - } - registeredEvents { - _id - } - eventAdmin { + user { _id + joinedOrganizations { + _id + } + firstName + lastName + email + image + createdAt + registeredEvents { + _id + } + membershipRequests { + _id + } } - membershipRequests { + appUserProfile { _id + adminApproved + adminFor { + _id + } + isSuperAdmin + createdOrganizations { + _id + } + createdEvents { + _id + } + eventAdmin { + _id + } } } } diff --git a/src/components/AddOn/core/AddOnStore/AddOnStore.tsx b/src/components/AddOn/core/AddOnStore/AddOnStore.tsx index e79ca9c24e..9eb65f9241 100644 --- a/src/components/AddOn/core/AddOnStore/AddOnStore.tsx +++ b/src/components/AddOn/core/AddOnStore/AddOnStore.tsx @@ -135,28 +135,6 @@ function addOnStore(): JSX.Element { onSelect={updateSelectedTab} > - {console.log( - data.getPlugins.filter( - (val: { - _id: string; - pluginName: string | undefined; - pluginDesc: string | undefined; - pluginCreatedBy: string; - pluginInstallStatus: boolean | undefined; - getInstalledPlugins: () => any; - }) => { - if (searchText == '') { - return val; - } else if ( - val.pluginName - ?.toLowerCase() - .includes(searchText.toLowerCase()) - ) { - return val; - } - }, - ), - )} {data.getPlugins.filter( (val: { _id: string; diff --git a/src/components/Advertisements/Advertisements.test.tsx b/src/components/Advertisements/Advertisements.test.tsx index b771c1d37b..77a0156de7 100644 --- a/src/components/Advertisements/Advertisements.test.tsx +++ b/src/components/Advertisements/Advertisements.test.tsx @@ -341,7 +341,7 @@ describe('Testing Advertisement Component', () => { name: 'Advertisement1', type: 'POPUP', organization: { - _id: '65844efc814dd4003db811c4', + _id: 'undefined', }, mediaUrl: 'http://example1.com', endDate: '2023-01-01', @@ -352,7 +352,7 @@ describe('Testing Advertisement Component', () => { name: 'Advertisement2', type: 'BANNER', organization: { - _id: '65844efc814dd4003db811c4', + _id: 'undefined', }, mediaUrl: 'http://example2.com', endDate: tomorrow, diff --git a/src/components/LeftDrawer/LeftDrawer.test.tsx b/src/components/LeftDrawer/LeftDrawer.test.tsx index 72b22d0e0f..0d452d56a1 100644 --- a/src/components/LeftDrawer/LeftDrawer.test.tsx +++ b/src/components/LeftDrawer/LeftDrawer.test.tsx @@ -67,6 +67,10 @@ describe('Testing Left Drawer component for SUPERADMIN', () => { }); test('Component should be rendered properly', () => { setItem('UserImage', ''); + setItem('UserImage', ''); + setItem('SuperAdmin', true); + setItem('FirstName', 'John'); + setItem('LastName', 'Doe'); render( @@ -104,6 +108,10 @@ describe('Testing Left Drawer component for SUPERADMIN', () => { }); test('Testing in roles screen', () => { + setItem('UserImage', ''); + setItem('SuperAdmin', true); + setItem('FirstName', 'John'); + setItem('LastName', 'Doe'); render( diff --git a/src/components/LeftDrawer/LeftDrawer.tsx b/src/components/LeftDrawer/LeftDrawer.tsx index 3de5677113..cd95acc259 100644 --- a/src/components/LeftDrawer/LeftDrawer.tsx +++ b/src/components/LeftDrawer/LeftDrawer.tsx @@ -1,17 +1,17 @@ -import React from 'react'; -import Button from 'react-bootstrap/Button'; -import { useTranslation } from 'react-i18next'; -import { NavLink, useNavigate } from 'react-router-dom'; +import { useMutation } from '@apollo/client'; +import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; import { ReactComponent as AngleRightIcon } from 'assets/svgs/angleRight.svg'; import { ReactComponent as LogoutIcon } from 'assets/svgs/logout.svg'; import { ReactComponent as OrganizationsIcon } from 'assets/svgs/organizations.svg'; import { ReactComponent as RolesIcon } from 'assets/svgs/roles.svg'; import { ReactComponent as TalawaLogo } from 'assets/svgs/talawa.svg'; -import styles from './LeftDrawer.module.css'; -import { useMutation } from '@apollo/client'; -import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; -import useLocalStorage from 'utils/useLocalstorage'; import Avatar from 'components/Avatar/Avatar'; +import React from 'react'; +import Button from 'react-bootstrap/Button'; +import { useTranslation } from 'react-i18next'; +import { NavLink, useNavigate } from 'react-router-dom'; +import useLocalStorage from 'utils/useLocalstorage'; +import styles from './LeftDrawer.module.css'; export interface InterfaceLeftDrawerProps { hideDrawer: boolean | null; @@ -22,12 +22,12 @@ const leftDrawer = ({ hideDrawer }: InterfaceLeftDrawerProps): JSX.Element => { const { t } = useTranslation('translation', { keyPrefix: 'leftDrawer' }); const { getItem } = useLocalStorage(); - const userType = getItem('UserType'); + const superAdmin = getItem('SuperAdmin'); const firstName = getItem('FirstName'); const lastName = getItem('LastName'); const userImage = getItem('UserImage'); const navigate = useNavigate(); - + const role = superAdmin ? 'SuperAdmin' : 'Admin'; const [revokeRefreshToken] = useMutation(REVOKE_REFRESH_TOKEN); const logout = (): void => { @@ -74,7 +74,7 @@ const leftDrawer = ({ hideDrawer }: InterfaceLeftDrawerProps): JSX.Element => { )} - {userType === 'SUPERADMIN' && ( + {superAdmin && ( {({ isActive }) => ( @@ -229,17 +211,17 @@ const UsersTableItem = (props: Props): JSX.Element => { show={showJoinedOrganizations} key={`modal-joined-org-${index}`} size="xl" - data-testid={`modal-joined-org-${user._id}`} + data-testid={`modal-joined-org-${user.user._id}`} onHide={() => setShowJoinedOrganizations(false)} > - {t('orgJoinedBy')} {`${user.firstName}`} {`${user.lastName}`} ( - {user.joinedOrganizations.length}) + {t('orgJoinedBy')} {`${user.user.firstName}`}{' '} + {`${user.user.lastName}`} ({user.user.joinedOrganizations.length}) - {user.joinedOrganizations.length !== 0 && ( + {user.user.joinedOrganizations.length !== 0 && (
{
)} - {user.joinedOrganizations.length == 0 ? ( + {user.user.joinedOrganizations.length == 0 ? (

- {user.firstName} {user.lastName} {t('hasNotJoinedAnyOrg')} + {user.user.firstName} {user.user.lastName}{' '} + {t('hasNotJoinedAnyOrg')}

) : joinedOrgs.length == 0 ? ( @@ -294,7 +277,7 @@ const UsersTableItem = (props: Props): JSX.Element => { {joinedOrgs.map((org) => { // Check user is admin for this organization or not let isAdmin = false; - user.adminFor.map((item) => { + user.appUserProfile.adminFor.map((item) => { if (item._id == org._id) { isAdmin = true; } @@ -390,7 +373,7 @@ const UsersTableItem = (props: Props): JSX.Element => { @@ -402,16 +385,17 @@ const UsersTableItem = (props: Props): JSX.Element => { key={`modal-blocked-org-${index}`} size="xl" onHide={() => setShowBlockedOrganizations(false)} - data-testid={`modal-blocked-org-${user._id}`} + data-testid={`modal-blocked-org-${user.user._id}`} > - {t('orgThatBlocked')} {`${user.firstName}`} {`${user.lastName}`} ( - {user.organizationsBlockedBy.length}) + {t('orgThatBlocked')} {`${user.user.firstName}`}{' '} + {`${user.user.lastName}`} ({user.user.organizationsBlockedBy.length} + ) - {user.organizationsBlockedBy.length !== 0 && ( + {user.user.organizationsBlockedBy.length !== 0 && (
{
)} - {user.organizationsBlockedBy.length == 0 ? ( + {user.user.organizationsBlockedBy.length == 0 ? (

- {user.firstName} {user.lastName} {t('isNotBlockedByAnyOrg')} + {user.user.firstName} {user.user.lastName}{' '} + {t('isNotBlockedByAnyOrg')}

) : orgsBlockedBy.length == 0 ? ( @@ -468,7 +453,7 @@ const UsersTableItem = (props: Props): JSX.Element => { {orgsBlockedBy.map((org) => { // Check user is admin for this organization or not let isAdmin = false; - user.adminFor.map((item) => { + user.appUserProfile.adminFor.map((item) => { if (item._id == org._id) { isAdmin = true; } @@ -564,7 +549,7 @@ const UsersTableItem = (props: Props): JSX.Element => { @@ -574,7 +559,7 @@ const UsersTableItem = (props: Props): JSX.Element => { onHideRemoveUserModal()} > @@ -586,7 +571,7 @@ const UsersTableItem = (props: Props): JSX.Element => {

Are you sure you want to remove{' '} - “{user.firstName} {user.lastName}” + “{user.user.firstName} {user.user.lastName}” {' '} from organization{' '} @@ -600,14 +585,14 @@ const UsersTableItem = (props: Props): JSX.Element => { diff --git a/src/screens/LoginPage/LoginPage.test.tsx b/src/screens/LoginPage/LoginPage.test.tsx index c43f75be27..8d72785da1 100644 --- a/src/screens/LoginPage/LoginPage.test.tsx +++ b/src/screens/LoginPage/LoginPage.test.tsx @@ -33,9 +33,12 @@ const MOCKS = [ login: { user: { _id: '1', - userType: 'ADMIN', adminApproved: true, }, + appUserProfile: { + isSuperAdmin: false, + adminFor: ['123', '456'], + }, accessToken: 'accessToken', refreshToken: 'refreshToken', }, diff --git a/src/screens/LoginPage/LoginPage.tsx b/src/screens/LoginPage/LoginPage.tsx index 0f1aa6413d..0e2252bdf4 100644 --- a/src/screens/LoginPage/LoginPage.tsx +++ b/src/screens/LoginPage/LoginPage.tsx @@ -1,4 +1,5 @@ import { useMutation } from '@apollo/client'; +import { Check, Clear } from '@mui/icons-material'; import type { ChangeEvent } from 'react'; import React, { useEffect, useState } from 'react'; import { Form } from 'react-bootstrap'; @@ -9,28 +10,27 @@ import ReCAPTCHA from 'react-google-recaptcha'; import { useTranslation } from 'react-i18next'; import { Link, useNavigate } from 'react-router-dom'; import { toast } from 'react-toastify'; -import { Check, Clear } from '@mui/icons-material'; +import EmailOutlinedIcon from '@mui/icons-material/EmailOutlined'; import { + BACKEND_URL, REACT_APP_USE_RECAPTCHA, RECAPTCHA_SITE_KEY, - BACKEND_URL, } from 'Constant/constant'; import { LOGIN_MUTATION, RECAPTCHA_MUTATION, SIGNUP_MUTATION, } from 'GraphQl/Mutations/mutations'; -import { ReactComponent as TalawaLogo } from 'assets/svgs/talawa.svg'; import { ReactComponent as PalisadoesLogo } from 'assets/svgs/palisadoes.svg'; +import { ReactComponent as TalawaLogo } from 'assets/svgs/talawa.svg'; import ChangeLanguageDropDown from 'components/ChangeLanguageDropdown/ChangeLanguageDropDown'; -import LoginPortalToggle from 'components/LoginPortalToggle/LoginPortalToggle'; import Loader from 'components/Loader/Loader'; +import LoginPortalToggle from 'components/LoginPortalToggle/LoginPortalToggle'; import { errorHandler } from 'utils/errorHandler'; -import styles from './LoginPage.module.css'; -import EmailOutlinedIcon from '@mui/icons-material/EmailOutlined'; import useLocalStorage from 'utils/useLocalstorage'; import { socialMediaLinks } from '../../constants'; +import styles from './LoginPage.module.css'; const loginPage = (): JSX.Element => { const { t } = useTranslation('translation', { keyPrefix: 'loginPage' }); @@ -253,26 +253,27 @@ const loginPage = (): JSX.Element => { /* istanbul ignore next */ if (loginData) { - if (role === 'admin') { - if ( - loginData.login.user.userType === 'SUPERADMIN' || - (loginData.login.user.userType === 'ADMIN' && - loginData.login.user.adminApproved === true) - ) { - setItem('token', loginData.login.accessToken); - setItem('refreshToken', loginData.login.refreshToken); - setItem('id', loginData.login.user._id); - setItem('IsLoggedIn', 'TRUE'); - setItem('UserType', loginData.login.user.userType); - } else { - toast.warn(t('notAuthorised')); + if ( + loginData.login.appUserProfile.isSuperAdmin || + (loginData.login.appUserProfile.adminFor.length !== 0 && + loginData.login.appUserProfile.adminApproved === true) + ) { + setItem('FirstName', loginData.login.user.firstName); + setItem('LastName', loginData.login.user.lastName); + setItem('token', loginData.login.accessToken); + setItem('refreshToken', loginData.login.refreshToken); + setItem('id', loginData.login.user._id); + setItem('IsLoggedIn', 'TRUE'); + setItem('SuperAdmin', loginData.login.appUserProfile.isSuperAdmin); + setItem('AdminFor', loginData.login.appUserProfile.adminFor); + if (getItem('IsLoggedIn') == 'TRUE') { + navigate(role === 'admin' ? '/orglist' : '/user/organizations'); } } else { setItem('token', loginData.login.accessToken); setItem('refreshToken', loginData.login.refreshToken); setItem('userId', loginData.login.user._id); setItem('IsLoggedIn', 'TRUE'); - setItem('UserType', loginData.login.user.userType); } setItem( 'name', diff --git a/src/screens/MemberDetail/MemberDetail.test.tsx b/src/screens/MemberDetail/MemberDetail.test.tsx index b26300be67..2e0d906dd9 100644 --- a/src/screens/MemberDetail/MemberDetail.test.tsx +++ b/src/screens/MemberDetail/MemberDetail.test.tsx @@ -1,20 +1,16 @@ -import React from 'react'; -import { act, render, screen, waitFor } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; +import { act, render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import { BrowserRouter } from 'react-router-dom'; +import { ADD_ADMIN_MUTATION } from 'GraphQl/Mutations/mutations'; +import { USER_DETAILS } from 'GraphQl/Queries/Queries'; +import { I18nextProvider } from 'react-i18next'; import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; import { store } from 'state/store'; -import { I18nextProvider } from 'react-i18next'; -import { - ADD_ADMIN_MUTATION, - UPDATE_USERTYPE_MUTATION, -} from 'GraphQl/Mutations/mutations'; -import { USER_DETAILS } from 'GraphQl/Queries/Queries'; -import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; +import i18nForTest from 'utils/i18nForTest'; import MemberDetail, { getLanguageName, prettyDate } from './MemberDetail'; - +import React from 'react'; const MOCKS1 = [ { request: { @@ -26,25 +22,72 @@ const MOCKS1 = [ result: { data: { user: { - __typename: 'User', - image: null, - firstName: 'Rishav', - lastName: 'Jha', - email: 'ris@gmail.com', - role: 'SUPERADMIN', - appLanguageCode: 'en', - userType: 'SUPERADMIN', - pluginCreationAllowed: true, - adminApproved: true, - createdAt: '2023-02-18T09:22:27.969Z', - adminFor: [], - createdOrganizations: [], - joinedOrganizations: [], - organizationsBlockedBy: [], - createdEvents: [], - registeredEvents: [], - eventAdmin: [], - membershipRequests: [], + __typename: 'UserData', + appUserProfile: { + __typename: 'AppUserProfile', + adminFor: [ + { + __typename: 'Organization', + _id: '65e0df0906dd1228350cfd4a', + }, + { + __typename: 'Organization', + _id: '65e0e2abb92c9f3e29503d4e', + }, + ], + isSuperAdmin: true, + appLanguageCode: 'en', + createdEvents: [ + { + __typename: 'Event', + _id: '65e32a5b2a1f4288ca1f086a', + }, + ], + createdOrganizations: [ + { + __typename: 'Organization', + _id: '65e0df0906dd1228350cfd4a', + }, + { + __typename: 'Organization', + _id: '65e0e2abb92c9f3e29503d4e', + }, + ], + eventAdmin: [ + { + __typename: 'Event', + _id: '65e32a5b2a1f4288ca1f086a', + }, + ], + pluginCreationAllowed: true, + adminApproved: true, + }, + user: { + __typename: 'User', + createdAt: '2024-02-26T10:36:33.098Z', + email: 'adi790u@gmail.com', + firstName: 'Aditya', + image: null, + lastName: 'Agarwal', + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '65e0df0906dd1228350cfd4a', + }, + { + __typename: 'Organization', + _id: '65e0e2abb92c9f3e29503d4e', + }, + ], + membershipRequests: [], + organizationsBlockedBy: [], + registeredEvents: [ + { + __typename: 'Event', + _id: '65e32a5b2a1f4288ca1f086a', + }, + ], + }, }, }, }, @@ -63,20 +106,6 @@ const MOCKS1 = [ }, }, }, - { - request: { - query: UPDATE_USERTYPE_MUTATION, - variables: { - id: '123', - userType: 'Admin', - }, - }, - result: { - data: { - success: true, - }, - }, - }, ]; const MOCKS2 = [ @@ -90,25 +119,41 @@ const MOCKS2 = [ result: { data: { user: { - __typename: 'User', - image: 'https://placeholder.com/200x200', - firstName: 'Rishav', - lastName: 'Jha', - email: 'ris@gmail.com', - role: 'SUPERADMIN', - appLanguageCode: 'en', - userType: 'SUPERADMIN', - pluginCreationAllowed: false, - adminApproved: false, - createdAt: '2023-02-18T09:22:27.969Z', - adminFor: [], - createdOrganizations: [], - joinedOrganizations: [], - organizationsBlockedBy: [], - createdEvents: [], - registeredEvents: [], - eventAdmin: [], - membershipRequests: [], + user: { + __typename: 'UserData', + appUserProfile: { + __typename: 'AppUserProfile', + adminFor: [ + { + __typename: 'Organization', + _id: '65e0df0906dd1228350cfd4a', + }, + { + __typename: 'Organization', + _id: '65e0e2abb92c9f3e29503d4e', + }, + ], + isSuperAdmin: true, + appLanguageCode: 'en', + createdEvents: [], + createdOrganizations: [], + eventAdmin: [], + pluginCreationAllowed: true, + adminApproved: true, + }, + user: { + __typename: 'User', + createdAt: '2024-02-26T10:36:33.098Z', + email: 'adi790u@gmail.com', + firstName: 'Aditya', + image: null, + lastName: 'Agarwal', + joinedOrganizations: [], + membershipRequests: [], + organizationsBlockedBy: [], + registeredEvents: [], + }, + }, }, }, }, @@ -162,40 +207,34 @@ describe('MemberDetail', () => { expect(screen.queryByText('Loading data...')).not.toBeInTheDocument(); await wait(); - userEvent.click(screen.getByText(/Add Admin/i)); - - expect(screen.getByTestId('dashboardTitleBtn')).toBeInTheDocument(); - expect(screen.getByTestId('dashboardTitleBtn')).toHaveTextContent( - 'User Details', - ); - expect(screen.getAllByText(/Email/i)).toBeTruthy(); - expect(screen.getAllByText(/Main/i)).toBeTruthy(); - expect(screen.getAllByText(/First name/i)).toBeTruthy(); - expect(screen.getAllByText(/Last name/i)).toBeTruthy(); - expect(screen.getAllByText(/Language/i)).toBeTruthy(); - expect(screen.getByText(/Admin approved/i)).toBeInTheDocument(); - expect(screen.getByText(/Plugin creation allowed/i)).toBeInTheDocument(); - expect(screen.getAllByText(/Created on/i)).toBeTruthy(); - expect(screen.getAllByText(/Admin for organizations/i)).toBeTruthy(); - expect(screen.getAllByText(/Membership requests/i)).toBeTruthy(); - expect(screen.getAllByText(/Events/i)).toBeTruthy(); - expect(screen.getAllByText(/Admin for events/i)).toBeTruthy(); + waitFor(() => { + expect(screen.getByTestId('addAdminBtn')).toBeInTheDocument(); + expect(screen.getByTestId('dashboardTitleBtn')).toBeInTheDocument(); + expect(screen.getByTestId('dashboardTitleBtn')).toHaveTextContent( + 'User Details', + ); + expect(screen.getAllByText(/Email/i)).toBeTruthy(); + expect(screen.getAllByText(/Main/i)).toBeTruthy(); + expect(screen.getAllByText(/First name/i)).toBeTruthy(); + expect(screen.getAllByText(/Last name/i)).toBeTruthy(); + expect(screen.getAllByText(/Language/i)).toBeTruthy(); + expect(screen.getByText(/Admin approved/i)).toBeInTheDocument(); + expect(screen.getByText(/Plugin creation allowed/i)).toBeInTheDocument(); + expect(screen.getAllByText(/Created on/i)).toBeTruthy(); + expect(screen.getAllByText(/Admin for organizations/i)).toBeTruthy(); + expect(screen.getAllByText(/Membership requests/i)).toBeTruthy(); + expect(screen.getAllByText(/Events/i)).toBeTruthy(); + expect(screen.getAllByText(/Admin for events/i)).toBeTruthy(); - expect(screen.getAllByText(/Created On/i)).toHaveLength(2); - expect(screen.getAllByText(/User Details/i)).toHaveLength(1); - expect(screen.getAllByText(/Role/i)).toHaveLength(2); - expect(screen.getAllByText(/Created/i)).toHaveLength(4); - expect(screen.getAllByText(/Joined/i)).toHaveLength(2); - expect(screen.getByTestId('addAdminBtn')).toBeInTheDocument(); - const addAdminBtn = MOCKS1[2].request.variables.userType; - // if the button is not disabled - expect(screen.getByTestId('addAdminBtn').getAttribute('disabled')).toBe( - addAdminBtn == 'ADMIN' || addAdminBtn == 'SUPERADMIN' - ? expect.anything() - : null, - ); - expect(screen.getByTestId('stateBtn')).toBeInTheDocument(); - userEvent.click(screen.getByTestId('stateBtn')); + expect(screen.getAllByText(/Created On/i)).toHaveLength(2); + expect(screen.getAllByText(/User Details/i)).toHaveLength(2); + expect(screen.getAllByText(/Role/i)).toHaveLength(2); + expect(screen.getAllByText(/Created/i)).toHaveLength(4); + expect(screen.getAllByText(/Joined/i)).toHaveLength(2); + expect(screen.getByTestId('addAdminBtn')).toBeInTheDocument(); + expect(screen.getByTestId('stateBtn')).toBeInTheDocument(); + userEvent.click(screen.getByTestId('stateBtn')); + }); }); test('prettyDate function should work properly', () => { @@ -221,7 +260,7 @@ describe('MemberDetail', () => { id: 'rishav-jha-mech', from: 'orglist', }; - + const user = MOCKS1[0].result.data.user; render( @@ -235,11 +274,14 @@ describe('MemberDetail', () => { ); expect(screen.queryByText('Loading data...')).not.toBeInTheDocument(); - const dicebearUrl = `mocked-data-uri`; - - const userImage = await screen.findByTestId('userImageAbsent'); - expect(userImage).toBeInTheDocument(); - expect(userImage.getAttribute('src')).toBe(dicebearUrl); + waitFor(() => + expect(screen.getByTestId('userImageAbsent')).toBeInTheDocument(), + ); + waitFor(() => + expect(screen.getByTestId('userImageAbsent').getAttribute('src')).toBe( + `https://api.dicebear.com/5.x/initials/svg?seed=${user?.user?.firstName} ${user?.user?.lastName}`, + ), + ); }); test('Should display image if image is present', async () => { @@ -263,9 +305,15 @@ describe('MemberDetail', () => { expect(screen.queryByText('Loading data...')).not.toBeInTheDocument(); const user = MOCKS2[0].result.data.user; - const userImage = await screen.findByTestId('userImagePresent'); - expect(userImage).toBeInTheDocument(); - expect(userImage.getAttribute('src')).toBe(user?.image); + + waitFor(() => + expect(screen.getByTestId('userImagePresent')).toBeInTheDocument(), + ); + waitFor(() => + expect(screen.getByTestId('userImagePresent').getAttribute('src')).toBe( + user?.user.user.image, + ), + ); }); test('should call setState with 2 when button is clicked', async () => { @@ -329,18 +377,4 @@ describe('MemberDetail', () => { expect(screen.getByTestId('adminApproved')).toHaveTextContent('No'); }); }); - test('should be redirected to / if member id is undefined', async () => { - render( - - - - - - - - - , - ); - expect(window.location.pathname).toEqual('/'); - }); }); diff --git a/src/screens/MemberDetail/MemberDetail.tsx b/src/screens/MemberDetail/MemberDetail.tsx index a53f920bab..8a34b30292 100644 --- a/src/screens/MemberDetail/MemberDetail.tsx +++ b/src/screens/MemberDetail/MemberDetail.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useRef, useState } from 'react'; +import React, { useEffect, useState } from 'react'; import { useMutation, useQuery } from '@apollo/client'; import Col from 'react-bootstrap/Col'; import Row from 'react-bootstrap/Row'; @@ -9,15 +9,11 @@ import UserUpdate from 'components/UserUpdate/UserUpdate'; import { USER_DETAILS } from 'GraphQl/Queries/Queries'; import styles from './MemberDetail.module.css'; import { languages } from 'utils/languages'; -import { - ADD_ADMIN_MUTATION, - UPDATE_USERTYPE_MUTATION, -} from 'GraphQl/Mutations/mutations'; +import { ADD_ADMIN_MUTATION } from 'GraphQl/Mutations/mutations'; import { toast } from 'react-toastify'; import { errorHandler } from 'utils/errorHandler'; import Loader from 'components/Loader/Loader'; import useLocalStorage from 'utils/useLocalstorage'; -import Avatar from 'components/Avatar/Avatar'; type MemberDetailProps = { id?: string; // This is the userId @@ -32,7 +28,6 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { const [state, setState] = useState(1); const [isAdmin, setIsAdmin] = useState(false); - const isMounted = useRef(true); const { getItem } = useLocalStorage(); const currentUrl = location.state?.id || getItem('id') || id; @@ -40,14 +35,6 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { document.title = t('title'); const [adda] = useMutation(ADD_ADMIN_MUTATION); - const [updateUserType] = useMutation(UPDATE_USERTYPE_MUTATION); - - useEffect(() => { - // check component is mounted or not - return () => { - isMounted.current = false; - }; - }, []); const { data: userData, @@ -55,9 +42,18 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { error: error, refetch: refetch, } = useQuery(USER_DETAILS, { - variables: { id: currentUrl }, // For testing we are sending the id as a prop + variables: { userId: currentUrl }, // For testing we are sending the id as a prop }); + useEffect(() => { + if (userData) { + const isAdmin = + userData.user.appUserProfile.adminFor.length > 0 || + userData.user.appUserProfile.isSuperAdmin; + setIsAdmin(isAdmin); + } + }, [userData]); + /* istanbul ignore next */ const toggleStateValue = (): void => { if (state === 1) setState(2); @@ -83,36 +79,16 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { }, }); - /* istanbul ignore next */ if (data) { - try { - const { data } = await updateUserType({ - variables: { - id: location.state?.id, - userType: 'ADMIN', - }, - }); - if (data) { - toast.success(t('addedAsAdmin')); - setTimeout(() => { - window.location.reload(); - }, 2000); - } - } catch (error: any) { - errorHandler(t, error); - } + toast.success(t('addedAsAdmin')); + setTimeout(() => { + window.location.reload(); + }, 2000); } + /* istanbul ignore next */ } catch (error: any) { /* istanbul ignore next */ - if ( - userData.user.userType === 'ADMIN' || - userData.user.userType === 'SUPERADMIN' - ) { - if (isMounted.current) setIsAdmin(true); - toast.error(t('alreadyIsAdmin')); - } else { - errorHandler(t, error); - } + errorHandler(t, error); } }; @@ -161,12 +137,10 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { data-testid="userImagePresent" /> ) : ( - )} @@ -176,20 +150,27 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => {

- {userData?.user?.firstName} {userData?.user?.lastName} + {userData?.user?.user?.firstName}{' '} + {userData?.user?.user?.lastName}

{t('role')} :{' '} - {userData?.user?.userType} + + {userData.user.appUserProfile.isSuperAdmin + ? 'SuperAdmin' + : userData.user.appUserProfile.adminFor.length > 0 + ? 'Admin' + : 'User'} +

{t('email')} :{' '} - {userData?.user?.email} + {userData?.user?.user?.email}

{t('createdOn')} :{' '} - {prettyDate(userData?.user?.createdAt)} + {prettyDate(userData?.user.user?.createdAt)}

@@ -211,32 +192,43 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => {
{t('firstName')} - {userData?.user?.firstName} + {userData?.user?.user?.firstName} {t('lastName')} - {userData?.user?.lastName} + {userData?.user?.user?.lastName} {t('role')} - {userData?.user?.userType} + + {userData.user.appUserProfile.isSuperAdmin + ? 'SuperAdmin' + : userData.user.appUserProfile.adminFor.length > 0 + ? 'Admin' + : 'User'} + {t('language')} - {getLanguageName(userData?.user?.appLanguageCode)} + {getLanguageName( + userData?.user?.appUserProfile?.appLanguageCode, + )} {t('adminApproved')} - {userData?.user?.adminApproved ? 'Yes' : 'No'} + {userData?.user?.appUserProfile?.adminApproved + ? 'Yes' + : 'No'} {t('pluginCreationAllowed')} - {userData?.user?.pluginCreationAllowed + {userData?.user?.appUserProfile + ?.pluginCreationAllowed ? 'Yes' : 'No'} @@ -244,7 +236,7 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { {t('createdOn')} - {prettyDate(userData?.user?.createdAt)} + {prettyDate(userData?.user?.user?.createdAt)}
@@ -263,23 +255,28 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { {t('created')} - {userData?.user?.createdOrganizations?.length} + { + userData?.user?.appUserProfile + ?.createdOrganizations?.length + } {t('joined')} - {userData?.user?.joinedOrganizations?.length} + {userData?.user?.user?.joinedOrganizations?.length} {t('adminForOrganizations')} - {userData?.user?.adminFor?.length} + + {userData?.user?.appUserProfile?.adminFor?.length} + {t('membershipRequests')} - {userData?.user?.membershipRequests?.length} + {userData?.user?.user?.membershipRequests?.length} @@ -295,18 +292,23 @@ const MemberDetail: React.FC = ({ id }): JSX.Element => { {t('created')} - {userData?.user?.createdEvents?.length} + { + userData?.user?.appUserProfile?.createdEvents + ?.length + } {t('joined')} - {userData?.user?.registeredEvents?.length} + {userData?.user?.user?.registeredEvents?.length} {t('adminForEvents')} - {userData?.user?.eventAdmin?.length} + + {userData?.user?.appUserProfile?.eventAdmin?.length} + diff --git a/src/screens/OrgList/OrgList.test.tsx b/src/screens/OrgList/OrgList.test.tsx index 84b3ec1329..70a41cde0a 100644 --- a/src/screens/OrgList/OrgList.test.tsx +++ b/src/screens/OrgList/OrgList.test.tsx @@ -30,6 +30,7 @@ import { ToastContainer, toast } from 'react-toastify'; jest.setTimeout(30000); import useLocalStorage from 'utils/useLocalstorage'; + const { setItem } = useLocalStorage(); async function wait(ms = 100): Promise { @@ -70,6 +71,9 @@ describe('Organisations Page testing as SuperAdmin', () => { test('Testing search functionality by pressing enter', async () => { setItem('id', '123'); + setItem('SuperAdmin', true); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); + render( @@ -91,6 +95,8 @@ describe('Organisations Page testing as SuperAdmin', () => { test('Testing search functionality by Btn click', async () => { setItem('id', '123'); + setItem('SuperAdmin', true); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); render( @@ -113,6 +119,8 @@ describe('Organisations Page testing as SuperAdmin', () => { test('Should render no organisation warning alert when there are no organization', async () => { window.location.assign('/'); setItem('id', '123'); + setItem('SuperAdmin', true); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); render( @@ -135,6 +143,10 @@ describe('Organisations Page testing as SuperAdmin', () => { }); test('Testing Organization data is not present', async () => { + setItem('id', '123'); + setItem('SuperAdmin', false); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); + render( @@ -150,9 +162,11 @@ describe('Organisations Page testing as SuperAdmin', () => { test('Testing create organization modal', async () => { setItem('id', '123'); + setItem('SuperAdmin', true); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); render( - + @@ -163,15 +177,20 @@ describe('Organisations Page testing as SuperAdmin', () => { , ); - await wait(); - const createOrgBtn = screen.getByTestId(/createOrganizationBtn/i); - expect(createOrgBtn).toBeInTheDocument(); - userEvent.click(createOrgBtn); + screen.debug(); + + expect(localStorage.setItem).toHaveBeenLastCalledWith( + 'Talawa-admin_AdminFor', + JSON.stringify([{ name: 'adi', _id: '1234', image: '' }]), + ); + + expect(screen.getByTestId(/createOrganizationBtn/i)).toBeInTheDocument(); }); test('Create organization model should work properly', async () => { setItem('id', '123'); - setItem('UserType', 'SUPERADMIN'); + setItem('SuperAdmin', true); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); render( @@ -189,8 +208,8 @@ describe('Organisations Page testing as SuperAdmin', () => { await wait(500); expect(localStorage.setItem).toHaveBeenLastCalledWith( - 'Talawa-admin_UserType', - JSON.stringify('SUPERADMIN'), + 'Talawa-admin_AdminFor', + JSON.stringify([{ name: 'adi', _id: '1234', image: '' }]), ); userEvent.click(screen.getByTestId(/createOrganizationBtn/i)); @@ -271,7 +290,8 @@ describe('Organisations Page testing as SuperAdmin', () => { test('Plugin Notification model should work properly', async () => { setItem('id', '123'); - setItem('UserType', 'SUPERADMIN'); + setItem('SuperAdmin', true); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); render( @@ -289,8 +309,8 @@ describe('Organisations Page testing as SuperAdmin', () => { await wait(500); expect(localStorage.setItem).toHaveBeenLastCalledWith( - 'Talawa-admin_UserType', - JSON.stringify('SUPERADMIN'), + 'Talawa-admin_AdminFor', + JSON.stringify([{ name: 'adi', _id: '1234', image: '' }]), ); userEvent.click(screen.getByTestId(/createOrganizationBtn/i)); @@ -378,7 +398,8 @@ describe('Organisations Page testing as SuperAdmin', () => { test('Testing create sample organization working properly', async () => { setItem('id', '123'); - setItem('UserType', 'SUPERADMIN'); + setItem('SuperAdmin', true); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); render( @@ -403,7 +424,9 @@ describe('Organisations Page testing as SuperAdmin', () => { }); test('Testing error handling for CreateSampleOrg', async () => { setItem('id', '123'); - setItem('UserType', 'SUPERADMIN'); + setItem('SuperAdmin', true); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); + jest.spyOn(toast, 'error'); render( @@ -431,6 +454,9 @@ describe('Organisations Page testing as Admin', () => { test('Create organization modal should not be present in the page for Admin', async () => { setItem('id', '123'); + setItem('SuperAdmin', false); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); + render( @@ -447,6 +473,10 @@ describe('Organisations Page testing as Admin', () => { }); }); test('Testing sort latest and oldest toggle', async () => { + setItem('id', '123'); + setItem('SuperAdmin', false); + setItem('AdminFor', [{ name: 'adi', _id: '1234', image: '' }]); + await act(async () => { render( diff --git a/src/screens/OrgList/OrgList.tsx b/src/screens/OrgList/OrgList.tsx index d9c3b66304..a102b709e3 100644 --- a/src/screens/OrgList/OrgList.tsx +++ b/src/screens/OrgList/OrgList.tsx @@ -18,7 +18,7 @@ import Button from 'react-bootstrap/Button'; import Modal from 'react-bootstrap/Modal'; import { useTranslation } from 'react-i18next'; import InfiniteScroll from 'react-infinite-scroll-component'; -import { Link, useNavigate } from 'react-router-dom'; +import { Link } from 'react-router-dom'; import { toast } from 'react-toastify'; import { errorHandler } from 'utils/errorHandler'; import type { @@ -26,15 +26,15 @@ import type { InterfaceOrgConnectionType, InterfaceUserType, } from 'utils/interfaces'; +import useLocalStorage from 'utils/useLocalstorage'; import styles from './OrgList.module.css'; import OrganizationModal from './OrganizationModal'; -import useLocalStorage from 'utils/useLocalstorage'; function orgList(): JSX.Element { const { t } = useTranslation('translation', { keyPrefix: 'orgList' }); - const navigate = useNavigate(); const [dialogModalisOpen, setdialogModalIsOpen] = useState(false); const [dialogRedirectOrgId, setDialogRedirectOrgId] = useState(''); + function openDialogModal(redirectOrgId: string): void { setDialogRedirectOrgId(redirectOrgId); // console.log(redirectOrgId, dialogRedirectOrgId); @@ -42,6 +42,8 @@ function orgList(): JSX.Element { } const { getItem } = useLocalStorage(); + const superAdmin = getItem('SuperAdmin'); + const adminFor = getItem('AdminFor'); function closeDialogModal(): void { setdialogModalIsOpen(false); @@ -94,7 +96,7 @@ function orgList(): JSX.Element { loading: boolean; error?: Error | undefined; } = useQuery(USER_ORGANIZATION_LIST, { - variables: { id: getItem('id') }, + variables: { userId: getItem('id') }, context: { headers: { authorization: `Bearer ${getItem('token')}` }, }, @@ -155,13 +157,13 @@ function orgList(): JSX.Element { const isAdminForCurrentOrg = ( currentOrg: InterfaceOrgConnectionInfoType, ): boolean => { - if (userData?.user?.adminFor.length === 1) { + if (adminFor.length === 1) { // If user is admin for one org only then check if that org is current org - return userData?.user?.adminFor[0]._id === currentOrg._id; + return adminFor[0]._id === currentOrg._id; } else { // If user is admin for more than one org then check if current org is present in adminFor array return ( - userData?.user?.adminFor.some( + adminFor.some( (org: { _id: string; name: string; image: string | null }) => org._id === currentOrg._id, ) ?? false @@ -173,7 +175,7 @@ function orgList(): JSX.Element { createSampleOrganization() .then(() => { toast.success(t('sampleOrgSuccess')); - navigate(0); + window.location.reload(); }) .catch(() => { toast.error(t('sampleOrgDuplicate')); @@ -239,11 +241,9 @@ function orgList(): JSX.Element { }; /* istanbul ignore next */ - useEffect(() => { - if (errorList || errorUser) { - navigate('/'); - } - }, [errorList, errorUser]); + if (errorList || errorUser) { + window.location.assign('/'); + } /* istanbul ignore next */ const resetAllParams = (): void => { @@ -392,7 +392,7 @@ function orgList(): JSX.Element { - {userData && userData.user.userType === 'SUPERADMIN' && ( + {superAdmin && ( - - )} + {(adminFor.length > 0 || superAdmin) && ( +
+ +
+ )}
diff --git a/src/screens/OrganizationDashboard/OrganizationDashboard.test.tsx b/src/screens/OrganizationDashboard/OrganizationDashboard.test.tsx index b9deb84191..f45b37b187 100644 --- a/src/screens/OrganizationDashboard/OrganizationDashboard.test.tsx +++ b/src/screens/OrganizationDashboard/OrganizationDashboard.test.tsx @@ -135,6 +135,7 @@ describe('Organisation Dashboard Page', () => { screen.getByText(/No membership requests present/i), ).toBeInTheDocument(); expect(screen.getByText(/No upcoming events/i)).toBeInTheDocument(); + expect(screen.getByText(/No Posts Present/i)).toBeInTheDocument(); }); test('Testing error scenario', async () => { diff --git a/src/screens/OrganizationDashboard/OrganizationDashboardMocks.ts b/src/screens/OrganizationDashboard/OrganizationDashboardMocks.ts index 07df5737a0..146391e74d 100644 --- a/src/screens/OrganizationDashboard/OrganizationDashboardMocks.ts +++ b/src/screens/OrganizationDashboard/OrganizationDashboardMocks.ts @@ -210,6 +210,20 @@ export const MOCKS = [ isPublic: true, isRegisterable: true, }, + { + _id: '2', + title: 'Sample Event', + description: 'Sample Description', + startDate: '2022-10-29T00:00:00.000Z', + endDate: '2023-10-29T23:59:59.000Z', + location: 'Sample Location', + startTime: '08:00:00', + endTime: '17:00:00', + allDay: false, + recurring: false, + isPublic: true, + isRegisterable: true, + }, ], }, }, @@ -279,21 +293,24 @@ export const EMPTY_MOCKS = [ { request: { query: ORGANIZATION_POST_LIST, + variables: { first: 10 }, }, result: { data: { - organizations: { - posts: { - edges: [], - pageInfo: { - startCursor: '', - endCursor: '', - hasNextPage: false, - hasPreviousPage: false, + organizations: [ + { + posts: { + edges: [], + pageInfo: { + startCursor: '', + endCursor: '', + hasNextPage: false, + hasPreviousPage: false, + }, + totalCount: 0, }, - totalCount: 0, }, - }, + ], }, }, }, diff --git a/src/screens/OrganizationFundCampaign/OrganizationFundCampagins.tsx b/src/screens/OrganizationFundCampaign/OrganizationFundCampagins.tsx index 968e09ae0c..772d814586 100644 --- a/src/screens/OrganizationFundCampaign/OrganizationFundCampagins.tsx +++ b/src/screens/OrganizationFundCampaign/OrganizationFundCampagins.tsx @@ -104,7 +104,6 @@ const orgFundCampaign = (): JSX.Element => { ): Promise => { e.preventDefault(); try { - console.log(formState); await createCampaign({ variables: { name: formState.campaignName, diff --git a/src/screens/OrganizationFunds/OrganizationFunds.tsx b/src/screens/OrganizationFunds/OrganizationFunds.tsx index 920372d943..625e79d54b 100644 --- a/src/screens/OrganizationFunds/OrganizationFunds.tsx +++ b/src/screens/OrganizationFunds/OrganizationFunds.tsx @@ -69,7 +69,6 @@ const organizationFunds = (): JSX.Element => { id: currentUrl, }, }); - console.log(fundData); const [createFund] = useMutation(CREATE_FUND_MUTATION); const [updateFund] = useMutation(UPDATE_FUND_MUTATION); @@ -174,7 +173,6 @@ const organizationFunds = (): JSX.Element => { }; const archiveFundHandler = async (): Promise => { try { - console.log('herere'); await updateFund({ variables: { id: fund?._id, diff --git a/src/screens/OrganizationPeople/AddMember.tsx b/src/screens/OrganizationPeople/AddMember.tsx index 59edf8a2c7..f5e701ea45 100644 --- a/src/screens/OrganizationPeople/AddMember.tsx +++ b/src/screens/OrganizationPeople/AddMember.tsx @@ -1,33 +1,33 @@ import { useLazyQuery, useMutation, useQuery } from '@apollo/client'; -import type { ChangeEvent } from 'react'; -import React, { useEffect, useState } from 'react'; -import { Link, useParams } from 'react-router-dom'; -import { Button, Dropdown, Form, InputGroup, Modal } from 'react-bootstrap'; -import { - ORGANIZATIONS_LIST, - ORGANIZATIONS_MEMBER_CONNECTION_LIST, - USERS_CONNECTION_LIST, -} from 'GraphQl/Queries/Queries'; -import { useTranslation } from 'react-i18next'; -import styles from './OrganizationPeople.module.css'; -import { toast } from 'react-toastify'; import { Search } from '@mui/icons-material'; +import EmailOutlinedIcon from '@mui/icons-material/EmailOutlined'; +import Paper from '@mui/material/Paper'; import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; import TableCell, { tableCellClasses } from '@mui/material/TableCell'; import TableContainer from '@mui/material/TableContainer'; import TableHead from '@mui/material/TableHead'; import TableRow from '@mui/material/TableRow'; -import Paper from '@mui/material/Paper'; import { styled } from '@mui/material/styles'; -import Loader from 'components/Loader/Loader'; import { ADD_MEMBER_MUTATION, SIGNUP_MUTATION, } from 'GraphQl/Mutations/mutations'; +import { + ORGANIZATIONS_LIST, + ORGANIZATIONS_MEMBER_CONNECTION_LIST, + USERS_CONNECTION_LIST, +} from 'GraphQl/Queries/Queries'; +import Loader from 'components/Loader/Loader'; +import type { ChangeEvent } from 'react'; +import React, { useEffect, useState } from 'react'; +import { Button, Dropdown, Form, InputGroup, Modal } from 'react-bootstrap'; +import { useTranslation } from 'react-i18next'; +import { Link, useParams } from 'react-router-dom'; +import { toast } from 'react-toastify'; import { errorHandler } from 'utils/errorHandler'; -import EmailOutlinedIcon from '@mui/icons-material/EmailOutlined'; import type { InterfaceQueryOrganizationsListObject } from 'utils/interfaces'; +import styles from './OrganizationPeople.module.css'; const StyledTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}`]: { diff --git a/src/screens/OrganizationPeople/OrganizationPeople.tsx b/src/screens/OrganizationPeople/OrganizationPeople.tsx index b1425460c9..7462a96842 100644 --- a/src/screens/OrganizationPeople/OrganizationPeople.tsx +++ b/src/screens/OrganizationPeople/OrganizationPeople.tsx @@ -1,32 +1,32 @@ import { useLazyQuery } from '@apollo/client'; -import dayjs from 'dayjs'; -import React, { useEffect, useState } from 'react'; -import { Link, useLocation, useParams } from 'react-router-dom'; -import { Button, Dropdown, Form } from 'react-bootstrap'; -import Col from 'react-bootstrap/Col'; -import Row from 'react-bootstrap/Row'; -import { - ORGANIZATIONS_MEMBER_CONNECTION_LIST, - USER_LIST, -} from 'GraphQl/Queries/Queries'; -import NotFound from 'components/NotFound/NotFound'; -import { useTranslation } from 'react-i18next'; -import styles from './OrganizationPeople.module.css'; -import { toast } from 'react-toastify'; import { Search, Sort } from '@mui/icons-material'; +import Paper from '@mui/material/Paper'; import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; import TableCell, { tableCellClasses } from '@mui/material/TableCell'; import TableContainer from '@mui/material/TableContainer'; import TableHead from '@mui/material/TableHead'; import TableRow from '@mui/material/TableRow'; -import Paper from '@mui/material/Paper'; import { styled } from '@mui/material/styles'; +import { + ORGANIZATIONS_MEMBER_CONNECTION_LIST, + USER_LIST, +} from 'GraphQl/Queries/Queries'; import Loader from 'components/Loader/Loader'; -import UserListCard from 'components/UserListCard/UserListCard'; -import OrgPeopleListCard from 'components/OrgPeopleListCard/OrgPeopleListCard'; +import NotFound from 'components/NotFound/NotFound'; import OrgAdminListCard from 'components/OrgAdminListCard/OrgAdminListCard'; +import OrgPeopleListCard from 'components/OrgPeopleListCard/OrgPeopleListCard'; +import UserListCard from 'components/UserListCard/UserListCard'; +import dayjs from 'dayjs'; +import React, { useEffect, useState } from 'react'; +import { Button, Dropdown, Form } from 'react-bootstrap'; +import Col from 'react-bootstrap/Col'; +import Row from 'react-bootstrap/Row'; +import { useTranslation } from 'react-i18next'; +import { Link, useLocation, useParams } from 'react-router-dom'; +import { toast } from 'react-toastify'; import AddMember from './AddMember'; +import styles from './OrganizationPeople.module.css'; const StyledTableCell = styled(TableCell)(({ theme }) => ({ [`&.${tableCellClasses.head}`]: { diff --git a/src/screens/UserPortal/Home/Home.module.css b/src/screens/UserPortal/Home/Home.module.css index 7559229aab..6bd42bc34b 100644 --- a/src/screens/UserPortal/Home/Home.module.css +++ b/src/screens/UserPortal/Home/Home.module.css @@ -158,3 +158,7 @@ width: 100dvw; margin: 0 auto; } + +.imageInput { + display: none; +} diff --git a/src/screens/UserPortal/Home/Home.test.tsx b/src/screens/UserPortal/Home/Home.test.tsx index 4dc47df8db..bcda7ddfc6 100644 --- a/src/screens/UserPortal/Home/Home.test.tsx +++ b/src/screens/UserPortal/Home/Home.test.tsx @@ -1,22 +1,23 @@ import React from 'react'; +import { act, fireEvent, render, screen, within } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; -import type { RenderResult } from '@testing-library/react'; -import { act, render, screen, waitFor, within } from '@testing-library/react'; import { I18nextProvider } from 'react-i18next'; -import userEvent from '@testing-library/user-event'; + import { ADVERTISEMENTS_GET, ORGANIZATION_POST_LIST, } from 'GraphQl/Queries/Queries'; +import { BrowserRouter } from 'react-router-dom'; import { Provider } from 'react-redux'; -import { MemoryRouter, Route, Routes } from 'react-router-dom'; import { store } from 'state/store'; -import { StaticMockLink } from 'utils/StaticMockLink'; import i18nForTest from 'utils/i18nForTest'; +import { StaticMockLink } from 'utils/StaticMockLink'; import Home from './Home'; -import useLocalStorage from 'utils/useLocalstorage'; - -const { setItem } = useLocalStorage(); +import userEvent from '@testing-library/user-event'; +import * as getOrganizationId from 'utils/getOrganizationId'; +import { CREATE_POST_MUTATION } from 'GraphQl/Mutations/mutations'; +import { toast } from 'react-toastify'; +import { REACT_APP_CUSTOM_PORT } from 'Constant/constant'; jest.mock('react-toastify', () => ({ toast: { @@ -26,13 +27,29 @@ jest.mock('react-toastify', () => ({ }, })); +const EMPTY_MOCKS = [ + { + request: { + query: ADVERTISEMENTS_GET, + }, + result: { + data: { + advertisementsConnection: [], + }, + }, + }, +]; + const MOCKS = [ { request: { query: ORGANIZATION_POST_LIST, variables: { - id: 'orgId', + id: '', first: 10, + after: null, + before: null, + last: null, }, }, result: { @@ -44,16 +61,16 @@ const MOCKS = [ { node: { _id: '6411e53835d7ba2344a78e21', - title: 'post one', + title: 'postone', text: 'This is the first post', imageUrl: null, videoUrl: null, - createdAt: '2024-03-03T09:26:56.524+00:00', + createdAt: '2023-08-24T09:26:56.524+00:00', creator: { _id: '640d98d9eb6a743d75341067', - firstName: 'Glen', - lastName: 'Dsza', - email: 'glendsza@gmail.com', + firstName: 'Aditya', + lastName: 'Shelke', + email: 'adidacreator1@gmail.com', }, likeCount: 0, commentCount: 0, @@ -66,60 +83,69 @@ const MOCKS = [ { node: { _id: '6411e54835d7ba2344a78e29', - title: 'post two', - text: 'This is the post two', + title: 'posttwo', + text: 'Tis is the post two', imageUrl: null, videoUrl: null, - createdAt: '2024-03-03T09:26:56.524+00:00', + createdAt: '2023-08-24T09:26:56.524+00:00', creator: { _id: '640d98d9eb6a743d75341067', - firstName: 'Glen', - lastName: 'Dsza', - email: 'glendsza@gmail.com', + firstName: 'Aditya', + lastName: 'Shelke', + email: 'adidacreator1@gmail.com', }, - likeCount: 2, - commentCount: 1, + likeCount: 0, + commentCount: 0, pinned: false, - likedBy: [ - { - _id: '640d98d9eb6a743d75341067', - firstName: 'Glen', - lastName: 'Dsza', - }, - { - _id: '640d98d9eb6a743d75341068', - firstName: 'Glen2', - lastName: 'Dsza2', - }, - ], - comments: [ - { - _id: '6411e54835d7ba2344a78e29', - creator: { - _id: '640d98d9eb6a743d75341067', - firstName: 'Glen', - lastName: 'Dsza', - email: 'glendsza@gmail.com', - }, - likeCount: 2, - likedBy: [ - { - _id: '640d98d9eb6a743d75341067', - firstName: 'Glen', - lastName: 'Dsza', - }, - { - _id: '640d98d9eb6a743d75341068', - firstName: 'Glen2', - lastName: 'Dsza2', - }, - ], - text: 'This is the post two', - }, - ], + likedBy: [], + comments: [], }, cursor: '6411e54835d7ba2344a78e29', }, + { + node: { + _id: '6411e54835d7ba2344a78e30', + title: 'posttwo', + text: 'Tis is the post two', + imageUrl: null, + videoUrl: null, + createdAt: '2023-08-24T09:26:56.524+00:00', + creator: { + _id: '640d98d9eb6a743d75341067', + firstName: 'Aditya', + lastName: 'Shelke', + email: 'adidacreator1@gmail.com', + }, + likeCount: 0, + commentCount: 0, + pinned: true, + likedBy: [], + comments: [], + }, + cursor: '6411e54835d7ba2344a78e30', + }, + { + node: { + _id: '6411e54835d7ba2344a78e31', + title: 'posttwo', + text: 'Tis is the post two', + imageUrl: null, + videoUrl: null, + createdAt: '2023-08-24T09:26:56.524+00:00', + creator: { + _id: '640d98d9eb6a743d75341067', + firstName: 'Aditya', + lastName: 'Shelke', + email: 'adidacreator1@gmail.com', + }, + likeCount: 0, + commentCount: 0, + pinned: false, + likedBy: [], + comments: [], + }, + cursor: '6411e54835d7ba2344a78e31', + }, ], pageInfo: { startCursor: '6411e53835d7ba2344a78e21', @@ -127,13 +153,30 @@ const MOCKS = [ hasNextPage: false, hasPreviousPage: false, }, - totalCount: 2, + totalCount: 4, }, }, ], }, }, }, + { + request: { + query: CREATE_POST_MUTATION, + variables: { + title: 'Dummy Post', + text: 'This is dummy text', + organizationId: '123', + }, + result: { + data: { + createPost: { + _id: '453', + }, + }, + }, + }, + }, { request: { query: ADVERTISEMENTS_GET, @@ -180,7 +223,7 @@ const MOCKS = [ name: 'name4', type: 'Type 2', organization: { - _id: 'orgId', + _id: 'orgId1', }, mediaUrl: 'link4', startDate: '2023-01-30', @@ -193,10 +236,7 @@ const MOCKS = [ ]; const link = new StaticMockLink(MOCKS, true); - -afterEach(() => { - localStorage.clear(); -}); +const link2 = new StaticMockLink(EMPTY_MOCKS, true); async function wait(ms = 100): Promise { await act(() => { @@ -206,77 +246,186 @@ async function wait(ms = 100): Promise { }); } -const renderHomeScreen = (): RenderResult => - render( - - - - - - } /> - - - - - , - ); - -describe('Testing Home Screen: User Portal', () => { - beforeAll(() => { - Object.defineProperty(window, 'matchMedia', { - writable: true, - value: jest.fn().mockImplementation((query) => ({ - matches: false, - media: query, - onchange: null, - addListener: jest.fn(), // Deprecated - removeListener: jest.fn(), // Deprecated - addEventListener: jest.fn(), - removeEventListener: jest.fn(), - dispatchEvent: jest.fn(), - })), - }); +beforeEach(() => { + const url = `http://localhost:${REACT_APP_CUSTOM_PORT}/user/organization/id=orgId`; + Object.defineProperty(window, 'location', { + value: { + href: url, + }, + writable: true, + }); +}); + +let originalLocation: Location; + +beforeAll(() => { + originalLocation = window.location; +}); + +afterAll(() => { + window.location = originalLocation; +}); + +describe('Testing Home Screen [User Portal]', () => { + jest.mock('utils/getOrganizationId'); + + Object.defineProperty(window, 'matchMedia', { + writable: true, + value: jest.fn().mockImplementation((query) => ({ + matches: false, + media: query, + onchange: null, + addListener: jest.fn(), // Deprecated + removeListener: jest.fn(), // Deprecated + addEventListener: jest.fn(), + removeEventListener: jest.fn(), + dispatchEvent: jest.fn(), + })), + }); + + test('Screen should be rendered properly', async () => { + const getOrganizationIdSpy = jest + .spyOn(getOrganizationId, 'default') + .mockImplementation(() => { + return ''; + }); + + render( + + + + + + + + + , + ); + + await wait(); - jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: 'id=orgId' }), - })); + expect(getOrganizationIdSpy).toHaveBeenCalled(); }); - afterAll(() => { - jest.clearAllMocks(); + test('Screen should be rendered properly when user types on the Post Input', async () => { + const getOrganizationIdSpy = jest + .spyOn(getOrganizationId, 'default') + .mockImplementation(() => { + return ''; + }); + + render( + + + + + + + + + , + ); + + await wait(); + + expect(getOrganizationIdSpy).toHaveBeenCalled(); + + userEvent.click(screen.getByTestId('startPostBtn')); + + const randomPostInput = 'This is a test'; + userEvent.type(screen.getByTestId('postInput'), randomPostInput); + + expect(screen.queryByText(randomPostInput)).toBeInTheDocument(); }); - test('Check if HomeScreen renders properly', async () => { - renderHomeScreen(); + test('Error toast should be visible when user tries to create a post with an empty body', async () => { + const toastSpy = jest.spyOn(toast, 'error'); + + render( + + + + + + + + + , + ); await wait(); - const startPostBtn = await screen.findByTestId('startPostBtn'); - expect(startPostBtn).toBeInTheDocument(); + userEvent.click(screen.getByTestId('startPostBtn')); + + userEvent.click(screen.getByTestId('createPostBtn')); + + expect(toastSpy).toBeCalledWith("Can't create a post with an empty body."); }); - test('StartPostModal should render on click of StartPost btn', async () => { - renderHomeScreen(); + test('Info toast should be visible when user tries to create a post with a valid body', async () => { + render( + + + + + + + + + , + ); await wait(); - const startPostBtn = await screen.findByTestId('startPostBtn'); - expect(startPostBtn).toBeInTheDocument(); - userEvent.click(startPostBtn); - const startPostModal = screen.getByTestId('startPostModal'); - expect(startPostModal).toBeInTheDocument(); + userEvent.click(screen.getByTestId('startPostBtn')); + + const randomPostInput = 'This is a test'; + userEvent.type(screen.getByTestId('postInput'), randomPostInput); + expect(screen.queryByText(randomPostInput)).toBeInTheDocument(); + + userEvent.click(screen.getByTestId('createPostBtn')); + + expect(toast.error).not.toBeCalledWith(); + expect(toast.info).toBeCalledWith('Processing your post. Please wait.'); }); - test('StartPostModal should close on clicking the close button', async () => { - renderHomeScreen(); + test('Modal should open on clicking on start a post button', async () => { + render( + + + + + + + + + , + ); await wait(); - const startPostBtn = await screen.findByTestId('startPostBtn'); - expect(startPostBtn).toBeInTheDocument(); - userEvent.click(startPostBtn); + userEvent.click(screen.getByTestId('startPostBtn')); const startPostModal = screen.getByTestId('startPostModal'); expect(startPostModal).toBeInTheDocument(); + }); + + test('modal closes on clicking on the close button', async () => { + render( + + + + + + + + + , + ); + + await wait(); + + userEvent.click(screen.getByTestId('startPostBtn')); + const modalHeader = screen.getByTestId('startPostModal'); + expect(modalHeader).toBeInTheDocument(); userEvent.type(screen.getByTestId('postInput'), 'some content'); userEvent.upload( @@ -289,7 +438,7 @@ describe('Testing Home Screen: User Portal', () => { await screen.findByAltText('Post Image Preview'); expect(screen.getByAltText('Post Image Preview')).toBeInTheDocument(); - const closeButton = within(startPostModal).getByRole('button', { + const closeButton = within(modalHeader).getByRole('button', { name: /close/i, }); userEvent.click(closeButton); @@ -301,50 +450,51 @@ describe('Testing Home Screen: User Portal', () => { expect(screen.getByTestId('postImageInput')).toHaveValue(''); }); - test('Check whether Posts render in PostCard', async () => { - setItem('userId', '640d98d9eb6a743d75341067'); - renderHomeScreen(); - await wait(); + test('triggers file input when the icon is clicked', () => { + const clickSpy = jest.spyOn(HTMLInputElement.prototype, 'click'); - const postCardContainers = screen.findAllByTestId('postCardContainer'); - expect(postCardContainers).not.toBeNull(); + render( + + + + + + + + + , + ); + + userEvent.click(screen.getByTestId('startPostBtn')); - expect(screen.queryByText('post one')).toBeInTheDocument(); - expect(screen.queryByText('This is the first post')).toBeInTheDocument(); + // Check if the file input is hidden initially + const postImageInput = screen.getByTestId('postImageInput'); + expect(postImageInput).toHaveAttribute('type', 'file'); + expect(postImageInput).toHaveStyle({ display: 'none' }); - expect(screen.queryByText('post two')).toBeInTheDocument(); - expect(screen.queryByText('This is the post two')).toBeInTheDocument(); + // Trigger icon click event + const iconButton = screen.getByTestId('addMediaBtn'); + fireEvent.click(iconButton); + + // Check if the file input is triggered to open + expect(clickSpy).toHaveBeenCalled(); + clickSpy.mockRestore(); }); -}); -describe('HomeScreen with invalid orgId', () => { - test('Redirect to /user when organizationId is falsy', async () => { - jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: '' }), - })); + test('promoted post is not rendered if there is no ad content', () => { render( - - + + - - } /> - } - /> - + - +
, ); - // Wait for the navigation to occur - await waitFor(() => { - const homeEl = screen.getByTestId('homeEl'); - expect(homeEl).toBeInTheDocument(); - }); + expect(screen.queryByText('Ad 1')).not.toBeInTheDocument(); + expect(screen.queryByText('Ad 2')).not.toBeInTheDocument(); }); }); diff --git a/src/screens/UserPortal/Home/Home.tsx b/src/screens/UserPortal/Home/Home.tsx index da61a657cc..52fb16e2ba 100644 --- a/src/screens/UserPortal/Home/Home.tsx +++ b/src/screens/UserPortal/Home/Home.tsx @@ -1,53 +1,95 @@ -import { useQuery } from '@apollo/client'; +import React, { useEffect, useRef, useState } from 'react'; +import type { ChangeEvent } from 'react'; +import OrganizationNavbar from 'components/UserPortal/OrganizationNavbar/OrganizationNavbar'; +import styles from './Home.module.css'; +import UserSidebar from 'components/UserPortal/UserSidebar/UserSidebar'; import ChevronRightIcon from '@mui/icons-material/ChevronRight'; -import HourglassBottomIcon from '@mui/icons-material/HourglassBottom'; +import { + Button, + Form, + Col, + Container, + Image, + Row, + Modal, +} from 'react-bootstrap'; +import { Link } from 'react-router-dom'; +import getOrganizationId from 'utils/getOrganizationId'; +import PostCard from 'components/UserPortal/PostCard/PostCard'; +import { useMutation, useQuery } from '@apollo/client'; import { ADVERTISEMENTS_GET, ORGANIZATION_POST_LIST, USER_DETAILS, } from 'GraphQl/Queries/Queries'; -import OrganizationNavbar from 'components/UserPortal/OrganizationNavbar/OrganizationNavbar'; -import PostCard from 'components/UserPortal/PostCard/PostCard'; -import type { InterfacePostCard } from 'utils/interfaces'; -import PromotedPost from 'components/UserPortal/PromotedPost/PromotedPost'; -import UserSidebar from 'components/UserPortal/UserSidebar/UserSidebar'; -import StartPostModal from 'components/UserPortal/StartPostModal/StartPostModal'; -import React, { useEffect, useState } from 'react'; -import { Button, Col, Container, Image, Row } from 'react-bootstrap'; +import { CREATE_POST_MUTATION } from 'GraphQl/Mutations/mutations'; +import { errorHandler } from 'utils/errorHandler'; import { useTranslation } from 'react-i18next'; - -import { Link, Navigate, useParams } from 'react-router-dom'; -import useLocalStorage from 'utils/useLocalstorage'; +import convertToBase64 from 'utils/convertToBase64'; +import { toast } from 'react-toastify'; +import HourglassBottomIcon from '@mui/icons-material/HourglassBottom'; +import PromotedPost from 'components/UserPortal/PromotedPost/PromotedPost'; import UserDefault from '../../../assets/images/defaultImg.png'; -import { ReactComponent as MediaIcon } from 'assets/svgs/media.svg'; -import { ReactComponent as ArticleIcon } from 'assets/svgs/article.svg'; -import { ReactComponent as EventIcon } from 'assets/svgs/userEvent.svg'; -import styles from './Home.module.css'; +import useLocalStorage from 'utils/useLocalstorage'; + +interface InterfacePostCardProps { + id: string; + creator: { + firstName: string; + lastName: string; + email: string; + id: string; + }; + image: string; + video: string; + text: string; + title: string; + likeCount: number; + commentCount: number; + comments: { + creator: { + _id: string; + firstName: string; + lastName: string; + email: string; + }; + likeCount: number; + likedBy: { + id: string; + }[]; + text: string; + }[]; + likedBy: { + firstName: string; + lastName: string; + id: string; + }[]; +} interface InterfaceAdContent { _id: string; name: string; type: string; - organization: { - _id: string; - }; - link: string; + organization: { _id: string }; + mediaUrl: string; endDate: string; startDate: string; } export default function home(): JSX.Element { const { t } = useTranslation('translation', { keyPrefix: 'home' }); + const { getItem } = useLocalStorage(); - const [posts, setPosts] = useState([]); - const [adContent, setAdContent] = useState([]); + + const organizationId = getOrganizationId(window.location.href); + const [posts, setPosts] = React.useState([]); + const [postContent, setPostContent] = React.useState(''); + const [postImage, setPostImage] = React.useState(''); + const [adContent, setAdContent] = React.useState([]); const [filteredAd, setFilteredAd] = useState([]); - const [showModal, setShowModal] = useState(false); - const { orgId } = useParams(); - const organizationId = orgId?.split('=')[1] || null; - if (!organizationId) { - return ; - } + const [showStartPost, setShowStartPost] = useState(false); + const fileInputRef = useRef(null); + const currentOrgId = window.location.href.split('/id=')[1] + ''; const navbarProps = { currentPage: 'home', @@ -58,28 +100,67 @@ export default function home(): JSX.Element { refetch, loading: loadingPosts, } = useQuery(ORGANIZATION_POST_LIST, { - variables: { id: organizationId, first: 10 }, + variables: { id: organizationId }, }); + const userId: string | null = getItem('userId'); const { data: userData } = useQuery(USER_DETAILS, { variables: { id: userId }, }); - useEffect(() => { + const [create] = useMutation(CREATE_POST_MUTATION); + + const handlePost = async (): Promise => { + try { + if (!postContent) { + throw new Error("Can't create a post with an empty body."); + } + toast.info('Processing your post. Please wait.'); + + const { data } = await create({ + variables: { + title: '', + text: postContent, + organizationId: organizationId, + file: postImage, + }, + }); + /* istanbul ignore next */ + if (data) { + toast.dismiss(); + toast.success('Your post is now visible in the feed.'); + refetch(); + setPostContent(''); + setPostImage(''); + setShowStartPost(false); + } + } catch (error: any) { + /* istanbul ignore next */ + errorHandler(t, error); + } + }; + + const handlePostInput = (e: ChangeEvent): void => { + const content = e.target.value; + + setPostContent(content); + }; + + React.useEffect(() => { if (data) { setPosts(data.organizations[0].posts.edges); } }, [data]); - useEffect(() => { + React.useEffect(() => { if (promotedPostsData) { setAdContent(promotedPostsData.advertisementsConnection); } - }, [promotedPostsData]); + }, [data]); useEffect(() => { - setFilteredAd(filterAdContent(adContent, organizationId)); + setFilteredAd(filterAdContent(adContent, currentOrgId)); }, [adContent]); const filterAdContent = ( @@ -95,11 +176,21 @@ export default function home(): JSX.Element { }; const handlePostButtonClick = (): void => { - setShowModal(true); + setShowStartPost(true); + }; + + const handleIconClick = (e: React.MouseEvent): void => { + e.preventDefault(); + + if (fileInputRef.current) { + fileInputRef.current.click(); + } }; const handleModalClose = (): void => { - setShowModal(false); + setPostContent(''); + setPostImage(''); + setShowStartPost(false); }; return ( @@ -112,7 +203,9 @@ export default function home(): JSX.Element { @@ -131,25 +224,66 @@ export default function home(): JSX.Element {
- + + +
+

{t('media')}

- {/*
{eventSvg}
*/}
- + + +
+

{t('event')}

- + + +
+

{t('article')}

@@ -174,105 +308,191 @@ export default function home(): JSX.Element { - - {filteredAd.length > 0 && ( + {filteredAd.length === 0 ? ( + '' + ) : (
{filteredAd.map((post: any) => ( ))}
)} - {loadingPosts ? (
Loading...
) : ( <> - {posts.map(({ node }: any) => { - const { - // likedBy, - // comments, - creator, - _id, - imageUrl, - videoUrl, - title, - text, - likeCount, - commentCount, - } = node; + {posts.map((post: any) => { + const allLikes: any = []; + post.likedBy.forEach((value: any) => { + const singleLike = { + firstName: value.firstName, + lastName: value.lastName, + id: value._id, + }; + allLikes.push(singleLike); + }); - // const allLikes: any = - // likedBy && Array.isArray(likedBy) - // ? likedBy.map((value: any) => ({ - // firstName: value.firstName, - // lastName: value.lastName, - // id: value._id, - // })) - // : []; + const postComments: any = []; + post.comments.forEach((value: any) => { + const commentLikes: any = []; - const allLikes: any = []; + value.likedBy.forEach((commentLike: any) => { + const singleLike = { + id: commentLike._id, + }; + commentLikes.push(singleLike); + }); - // const postComments: any = - // comments && Array.isArray(comments) - // ? comments.map((value: any) => { - // const commentLikes = value.likedBy.map( - // (commentLike: any) => ({ id: commentLike._id }), - // ); - // return { - // id: value._id, - // creator: { - // firstName: value.creator.firstName, - // lastName: value.creator.lastName, - // id: value.creator._id, - // email: value.creator.email, - // }, - // likeCount: value.likeCount, - // likedBy: commentLikes, - // text: value.text, - // }; - // }) - // : []; + const singleCommnet: any = { + id: value._id, + creator: { + firstName: value.creator.firstName, + lastName: value.creator.lastName, + id: value.creator._id, + email: value.creator.email, + }, + likeCount: value.likeCount, + likedBy: commentLikes, + text: value.text, + }; - const postComments: any = []; + postComments.push(singleCommnet); + }); - const cardProps: InterfacePostCard = { - id: _id, + const cardProps: InterfacePostCardProps = { + id: post._id, creator: { - id: creator._id, - firstName: creator.firstName, - lastName: creator.lastName, - email: creator.email, + id: post.creator._id, + firstName: post.creator.firstName, + lastName: post.creator.lastName, + email: post.creator.email, }, - image: imageUrl, - video: videoUrl, - title, - text, - likeCount, - commentCount, + image: post.imageUrl, + video: post.videoUrl, + title: post.title, + text: post.text, + likeCount: post.likeCount, + commentCount: post.commentCount, comments: postComments, likedBy: allLikes, }; - return ; + return ; })} )} - + backdrop="static" + aria-labelledby="contained-modal-title-vcenter" + centered + data-testid="startPostModal" + > + + + + + + + {`${userData?.user.firstName} ${userData?.user.lastName}`} + + + +
+ + + , + ): Promise => { + const file = e.target.files && e.target.files[0]; + if (file) { + const image = await convertToBase64(file); + setPostImage(image); + } + }} + /> + {postImage && ( +
+ Post Image Preview +
+ )} +
+ +
+
+ + + +
+ ); diff --git a/src/screens/UserPortal/Organizations/Organizations.test.tsx b/src/screens/UserPortal/Organizations/Organizations.test.tsx index a142d0c37e..9d46e01825 100644 --- a/src/screens/UserPortal/Organizations/Organizations.test.tsx +++ b/src/screens/UserPortal/Organizations/Organizations.test.tsx @@ -1,22 +1,21 @@ -import React from 'react'; -import { act, render, screen } from '@testing-library/react'; import { MockedProvider } from '@apollo/react-testing'; +import { act, render, screen } from '@testing-library/react'; import { I18nextProvider } from 'react-i18next'; +import userEvent from '@testing-library/user-event'; import { USER_CREATED_ORGANIZATIONS, USER_JOINED_ORGANIZATIONS, USER_ORGANIZATION_CONNECTION, } from 'GraphQl/Queries/Queries'; -import { BrowserRouter } from 'react-router-dom'; import { Provider } from 'react-redux'; +import { BrowserRouter } from 'react-router-dom'; import { store } from 'state/store'; -import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; -import Organizations from './Organizations'; -import userEvent from '@testing-library/user-event'; +import i18nForTest from 'utils/i18nForTest'; import useLocalStorage from 'utils/useLocalstorage'; - +import Organizations from './Organizations'; +import React from 'react'; const { getItem } = useLocalStorage(); const MOCKS = [ @@ -31,15 +30,17 @@ const MOCKS = [ data: { users: [ { - createdOrganizations: [ - { - __typename: 'Organization', - _id: '6401ff65ce8e8406b8f07af2', - name: 'createdOrganization', - image: '', - description: 'New Desc', - }, - ], + appUserProfile: { + createdOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + name: 'createdOrganization', + image: '', + description: 'New Desc', + }, + ], + }, }, ], }, @@ -158,16 +159,17 @@ const MOCKS = [ data: { users: [ { - joinedOrganizations: [ - { - __typename: 'Organization', - _id: '6401ff65ce8e8406b8f07af2', - name: 'joinedOrganization', - createdAt: '1234567890', - image: '', - description: 'New Desc', - }, - ], + user: { + joinedOrganizations: [ + { + __typename: 'Organization', + _id: '6401ff65ce8e8406b8f07af2', + name: 'joinedOrganization', + image: '', + description: 'New Desc', + }, + ], + }, }, ], }, diff --git a/src/screens/UserPortal/Organizations/Organizations.tsx b/src/screens/UserPortal/Organizations/Organizations.tsx index 7660bfffa7..601e69ef16 100644 --- a/src/screens/UserPortal/Organizations/Organizations.tsx +++ b/src/screens/UserPortal/Organizations/Organizations.tsx @@ -1,23 +1,22 @@ -import React from 'react'; -import UserNavbar from 'components/UserPortal/UserNavbar/UserNavbar'; -import OrganizationCard from 'components/UserPortal/OrganizationCard/OrganizationCard'; -import UserSidebar from 'components/UserPortal/UserSidebar/UserSidebar'; -import { Button, Dropdown, Form, InputGroup } from 'react-bootstrap'; -import PaginationList from 'components/PaginationList/PaginationList'; +import { useQuery } from '@apollo/client'; +import { SearchOutlined } from '@mui/icons-material'; +import HourglassBottomIcon from '@mui/icons-material/HourglassBottom'; import { - CHECK_AUTH, USER_CREATED_ORGANIZATIONS, USER_JOINED_ORGANIZATIONS, USER_ORGANIZATION_CONNECTION, } from 'GraphQl/Queries/Queries'; -import { useQuery } from '@apollo/client'; -import { Search } from '@mui/icons-material'; -import styles from './Organizations.module.css'; +import PaginationList from 'components/PaginationList/PaginationList'; +import OrganizationCard from 'components/UserPortal/OrganizationCard/OrganizationCard'; +import UserNavbar from 'components/UserPortal/UserNavbar/UserNavbar'; +import UserSidebar from 'components/UserPortal/UserSidebar/UserSidebar'; +import React from 'react'; +import { Dropdown, Form, InputGroup } from 'react-bootstrap'; import { useTranslation } from 'react-i18next'; -import HourglassBottomIcon from '@mui/icons-material/HourglassBottom'; import useLocalStorage from 'utils/useLocalstorage'; +import styles from './Organizations.module.css'; -const { getItem, setItem } = useLocalStorage(); +const { getItem } = useLocalStorage(); interface InterfaceOrganizationCardProps { id: string; @@ -62,29 +61,19 @@ export default function organizations(): JSX.Element { const userId: string | null = getItem('userId'); const { - data: organizationsData, + data, refetch, loading: loadingOrganizations, } = useQuery(USER_ORGANIZATION_CONNECTION, { variables: { filter: filterName }, }); - const { data: joinedOrganizationsData } = useQuery( - USER_JOINED_ORGANIZATIONS, - { - variables: { id: userId }, - }, - ); - - const { data: createdOrganizationsData } = useQuery( - USER_CREATED_ORGANIZATIONS, - { - variables: { id: userId }, - }, - ); + const { data: data2 } = useQuery(USER_JOINED_ORGANIZATIONS, { + variables: { id: userId }, + }); - const { data: userData, loading } = useQuery(CHECK_AUTH, { - fetchPolicy: 'network-only', + const { data: data3 } = useQuery(USER_CREATED_ORGANIZATIONS, { + variables: { id: userId }, }); /* istanbul ignore next */ @@ -127,133 +116,60 @@ export default function organizations(): JSX.Element { /* istanbul ignore next */ React.useEffect(() => { - if (organizationsData) { - const organizations = organizationsData.organizationsConnection.map( - (organization: any) => { - let membershipRequestStatus = ''; - if ( - organization.members.find( - (member: { _id: string }) => member._id === userId, - ) - ) - membershipRequestStatus = 'accepted'; - else if ( - organization.membershipRequests.find( - (request: { user: { _id: string } }) => - request.user._id === userId, - ) - ) - membershipRequestStatus = 'pending'; - return { ...organization, membershipRequestStatus }; - }, - ); - setOrganizations(organizations); + if (data) { + setOrganizations(data.organizationsConnection); } - }, [organizationsData]); + }, [data]); /* istanbul ignore next */ React.useEffect(() => { if (mode == 0) { - if (organizationsData) { - const organizations = organizationsData.organizationsConnection.map( - (organization: any) => { - let membershipRequestStatus = ''; - if ( - organization.members.find( - (member: { _id: string }) => member._id === userId, - ) - ) - membershipRequestStatus = 'accepted'; - else if ( - organization.membershipRequests.find( - (request: { user: { _id: string } }) => - request.user._id === userId, - ) - ) - membershipRequestStatus = 'pending'; - return { ...organization, membershipRequestStatus }; - }, - ); - setOrganizations(organizations); + if (data) { + setOrganizations(data.organizationsConnection); } } else if (mode == 1) { - console.log(joinedOrganizationsData, 'joined', userId); - if (joinedOrganizationsData) { - const membershipRequestStatus = 'accepted'; - const organizations = - joinedOrganizationsData?.users[0].joinedOrganizations.map( - (organization: any) => { - return { ...organization, membershipRequestStatus }; - }, - ); - setOrganizations(organizations); + if (data2) { + setOrganizations(data2.users[0].user.joinedOrganizations); } } else if (mode == 2) { - const membershipRequestStatus = 'accepted'; - const organizations = - createdOrganizationsData?.users[0].createdOrganizations.map( - (organization: any) => { - return { ...organization, membershipRequestStatus }; - }, - ); - setOrganizations(organizations); + if (data3) { + setOrganizations(data3.users[0].appUserProfile.createdOrganizations); + } } }, [mode]); - /* istanbul ignore next */ - React.useEffect(() => { - if (userData) { - setItem( - 'name', - `${userData.checkAuth.firstName} ${userData.checkAuth.lastName}`, - ); - setItem('id', userData.checkAuth._id); - setItem('email', userData.checkAuth.email); - setItem('IsLoggedIn', 'TRUE'); - setItem('UserType', userData.checkAuth.userType); - setItem('FirstName', userData.checkAuth.firstName); - setItem('LastName', userData.checkAuth.lastName); - setItem('UserImage', userData.checkAuth.image); - setItem('Email', userData.checkAuth.email); - } - }, [userData, loading]); - return ( <>
-

{t('organizations')}

+

{t('selectOrganization')}

-
- - -
+ + + +
@@ -274,62 +190,68 @@ export default function organizations(): JSX.Element {
-
- {loadingOrganizations ? ( -
- Loading... -
- ) : ( - <> - {' '} - {organizations && organizations?.length > 0 ? ( - (rowsPerPage > 0 - ? organizations.slice( - page * rowsPerPage, - page * rowsPerPage + rowsPerPage, - ) - : /* istanbul ignore next */ - organizations - ).map((organization: any, index) => { - const cardProps: InterfaceOrganizationCardProps = { - name: organization.name, - image: organization.image, - id: organization._id, - description: organization.description, - admins: organization.admins, - members: organization.members, - address: organization.address, - membershipRequestStatus: - organization.membershipRequestStatus, - userRegistrationRequired: - organization.userRegistrationRequired, - membershipRequests: organization.membershipRequests, - }; - return ; - }) - ) : ( - {t('nothingToShow')} - )} - - )} -
- - - - - - -
+
+
+ {loadingOrganizations ? ( +
+ Loading... +
+ ) : ( + <> + {' '} + {organizations && organizations.length > 0 ? ( + (rowsPerPage > 0 + ? organizations.slice( + page * rowsPerPage, + page * rowsPerPage + rowsPerPage, + ) + : /* istanbul ignore next */ + organizations + ).map((organization: any, index) => { + const cardProps: InterfaceOrganizationCardProps = { + name: organization.name, + image: organization.image, + id: organization._id, + description: organization.description, + admins: organization.admins, + members: organization.members, + address: organization.address, + membershipRequestStatus: + organization.membershipRequestStatus, + userRegistrationRequired: + organization.userRegistrationRequired, + membershipRequests: organization.membershipRequests, + }; + return ; + }) + ) : ( + {t('nothingToShow')} + )} + + )} +
+ + + + + + +
+
diff --git a/src/screens/Users/Users.test.tsx b/src/screens/Users/Users.test.tsx index cc35298c15..b7b08c1cd9 100644 --- a/src/screens/Users/Users.test.tsx +++ b/src/screens/Users/Users.test.tsx @@ -30,7 +30,7 @@ async function wait(ms = 100): Promise { } beforeEach(() => { setItem('id', '123'); - setItem('UserType', 'SUPERADMIN'); + setItem('SuperAdmin', true); setItem('FirstName', 'John'); setItem('LastName', 'Doe'); }); diff --git a/src/screens/Users/Users.tsx b/src/screens/Users/Users.tsx index e3f6d68ac2..c836838dc2 100644 --- a/src/screens/Users/Users.tsx +++ b/src/screens/Users/Users.tsx @@ -34,7 +34,11 @@ const Users = (): JSX.Element => { const [searchByName, setSearchByName] = useState(''); const [sortingOption, setSortingOption] = useState('newest'); const [filteringOption, setFilteringOption] = useState('cancel'); - const userType = getItem('UserType'); + const userType = getItem('SuperAdmin') + ? 'SUPERADMIN' + : getItem('AdminFor') + ? 'ADMIN' + : 'USER'; const loggedInUserId = getItem('id'); const { @@ -176,8 +180,6 @@ const Users = (): JSX.Element => { }); }; - // console.log(usersData); - const handleSorting = (option: string): void => { setSortingOption(option); }; @@ -191,13 +193,15 @@ const Users = (): JSX.Element => { if (sortingOption === 'newest') { sortedUsers.sort( (a, b) => - new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(), + new Date(b.user.createdAt).getTime() - + new Date(a.user.createdAt).getTime(), ); return sortedUsers; } else { sortedUsers.sort( (a, b) => - new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime(), + new Date(a.user.createdAt).getTime() - + new Date(b.user.createdAt).getTime(), ); return sortedUsers; } @@ -217,17 +221,20 @@ const Users = (): JSX.Element => { return filteredUsers; } else if (filteringOption === 'user') { const output = filteredUsers.filter((user) => { - return user.userType === 'USER'; + return user.appUserProfile.adminApproved === false; }); return output; } else if (filteringOption === 'admin') { const output = filteredUsers.filter((user) => { - return user.userType == 'ADMIN'; + return ( + user.appUserProfile.isSuperAdmin === false && + user.appUserProfile.adminApproved === true + ); }); return output; } else { const output = filteredUsers.filter((user) => { - return user.userType == 'SUPERADMIN'; + return user.appUserProfile.isSuperAdmin === true; }); return output; } @@ -395,17 +402,21 @@ const Users = (): JSX.Element => { {usersData && - displayedUsers.map((user, index) => { - return ( - - ); - })} + displayedUsers.map( + (user: InterfaceQueryUserListItem, index: number) => { + return ( + + ); + }, + )} diff --git a/src/screens/Users/UsersMocks.ts b/src/screens/Users/UsersMocks.ts index 5c287ce446..18110da684 100644 --- a/src/screens/Users/UsersMocks.ts +++ b/src/screens/Users/UsersMocks.ts @@ -13,19 +13,10 @@ export const MOCKS = [ result: { data: { user: { - _id: 'user1', - userType: 'SUPERADMIN', firstName: 'John', lastName: 'Doe', image: '', email: 'John_Does_Palasidoes@gmail.com', - adminFor: [ - { - _id: 1, - name: 'Palisadoes', - image: '', - }, - ], }, }, }, @@ -44,138 +35,158 @@ export const MOCKS = [ data: { users: [ { - _id: 'user1', - firstName: 'John', - lastName: 'Doe', - image: null, - email: 'john@example.com', - userType: 'SUPERADMIN', - adminApproved: true, - adminFor: [ - { - _id: '123', - }, - ], - createdAt: '20/06/2022', - organizationsBlockedBy: [ - { - _id: 'xyz', - name: 'ABC', - image: null, - address: { - city: 'Kingston', - countryCode: 'JM', - dependentLocality: 'Sample Dependent Locality', - line1: '123 Jamaica Street', - line2: 'Apartment 456', - postalCode: 'JM12345', - sortingCode: 'ABC-123', - state: 'Kingston Parish', - }, - createdAt: '20/06/2022', - creator: { - _id: '123', - firstName: 'John', - lastName: 'Doe', + user: { + _id: 'user1', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + adminApproved: true, + createdAt: '20/06/2022', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'ABC', image: null, - email: 'john@example.com', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, createdAt: '20/06/2022', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '20/06/2022', + }, }, - }, - ], - joinedOrganizations: [ - { - _id: 'abc', - name: 'Joined Organization 1', - image: null, - address: { - city: 'Kingston', - countryCode: 'JM', - dependentLocality: 'Sample Dependent Locality', - line1: '123 Jamaica Street', - line2: 'Apartment 456', - postalCode: 'JM12345', - sortingCode: 'ABC-123', - state: 'Kingston Parish', - }, - createdAt: '20/06/2022', - creator: { - _id: '123', - firstName: 'John', - lastName: 'Doe', + ], + joinedOrganizations: [ + { + _id: 'abc', + name: 'Joined Organization 1', image: null, - email: 'john@example.com', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, createdAt: '20/06/2022', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '20/06/2022', + }, }, - }, - ], + ], + }, + appUserProfile: { + _id: 'user1', + adminFor: [ + { + _id: '123', + }, + ], + isSuperAdmin: true, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, }, { - _id: 'user2', - firstName: 'Jane', - lastName: 'Doe', - image: null, - email: 'john@example.com', - userType: 'SUPERADMIN', - adminApproved: true, - adminFor: [ - { - _id: '123', - }, - ], - createdAt: '20/06/2022', - organizationsBlockedBy: [ - { - _id: '456', - name: 'ABC', - image: null, - address: { - city: 'Kingston', - countryCode: 'JM', - dependentLocality: 'Sample Dependent Locality', - line1: '123 Jamaica Street', - line2: 'Apartment 456', - postalCode: 'JM12345', - sortingCode: 'ABC-123', - state: 'Kingston Parish', - }, - createdAt: '20/06/2022', - creator: { - _id: '123', - firstName: 'John', - lastName: 'Doe', + user: { + _id: 'user2', + firstName: 'Jane', + lastName: 'Doe', + image: null, + email: 'john@example.com', + adminApproved: true, + createdAt: '20/06/2022', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: '456', + name: 'ABC', image: null, - email: 'john@example.com', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, createdAt: '20/06/2022', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '20/06/2022', + }, }, - }, - ], - joinedOrganizations: [ - { - _id: '123', - name: 'Palisadoes', - image: null, - address: { - city: 'Kingston', - countryCode: 'JM', - dependentLocality: 'Sample Dependent Locality', - line1: '123 Jamaica Street', - line2: 'Apartment 456', - postalCode: 'JM12345', - sortingCode: 'ABC-123', - state: 'Kingston Parish', - }, - createdAt: '20/06/2022', - creator: { + ], + joinedOrganizations: [ + { _id: '123', - firstName: 'John', - lastName: 'Doe', + name: 'Palisadoes', image: null, - email: 'john@example.com', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, createdAt: '20/06/2022', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '20/06/2022', + }, }, - }, - ], + ], + }, + appUserProfile: { + _id: 'user2', + adminFor: [ + { + _id: '123', + }, + ], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, }, ], }, @@ -239,19 +250,10 @@ export const MOCKS2 = [ result: { data: { user: { - _id: 'user1', - userType: 'SUPERADMIN', firstName: 'John', lastName: 'Doe', image: '', email: 'John_Does_Palasidoes@gmail.com', - adminFor: [ - { - _id: 1, - name: 'Palisadoes', - image: '', - }, - ], }, }, }, @@ -270,71 +272,158 @@ export const MOCKS2 = [ data: { users: [ { - _id: 'user1', - firstName: 'John', - lastName: 'Doe', - image: null, - email: 'john@example.com', - userType: 'SUPERADMIN', - adminApproved: true, - adminFor: [ - { - _id: '123', - }, - ], - createdAt: '20/06/2022', - organizationsBlockedBy: [ - { - _id: 'xyz', - name: 'ABC', - image: null, - address: { - city: 'Kingston', - countryCode: 'JM', - dependentLocality: 'Sample Dependent Locality', - line1: '123 Jamaica Street', - line2: 'Apartment 456', - postalCode: 'JM12345', - sortingCode: 'ABC-123', - state: 'Kingston Parish', + user: { + _id: 'user1', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + adminApproved: true, + createdAt: '20/06/2022', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: 'xyz', + name: 'ABC', + image: null, + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + createdAt: '20/06/2022', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '20/06/2022', + }, }, - createdAt: '20/06/2022', - creator: { - _id: '123', - firstName: 'John', - lastName: 'Doe', + ], + joinedOrganizations: [ + { + _id: 'abc', + name: 'Joined Organization 1', image: null, - email: 'john@example.com', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, createdAt: '20/06/2022', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '20/06/2022', + }, }, - }, - ], - joinedOrganizations: [ - { - _id: 'abc', - name: 'Joined Organization 1', - image: null, - address: { - city: 'Kingston', - countryCode: 'JM', - dependentLocality: 'Sample Dependent Locality', - line1: '123 Jamaica Street', - line2: 'Apartment 456', - postalCode: 'JM12345', - sortingCode: 'ABC-123', - state: 'Kingston Parish', + ], + }, + appUserProfile: { + _id: 'user1', + adminFor: [ + { + _id: '123', }, - createdAt: '20/06/2022', - creator: { + ], + isSuperAdmin: true, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, + }, + { + user: { + _id: 'user2', + firstName: 'Jane', + lastName: 'Doe', + image: null, + email: 'john@example.com', + adminApproved: true, + createdAt: '20/06/2022', + registeredEvents: [], + membershipRequests: [], + organizationsBlockedBy: [ + { + _id: '456', + name: 'ABC', + image: null, + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, + createdAt: '20/06/2022', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '20/06/2022', + }, + }, + ], + joinedOrganizations: [ + { _id: '123', - firstName: 'John', - lastName: 'Doe', + name: 'Palisadoes', image: null, - email: 'john@example.com', + address: { + city: 'Kingston', + countryCode: 'JM', + dependentLocality: 'Sample Dependent Locality', + line1: '123 Jamaica Street', + line2: 'Apartment 456', + postalCode: 'JM12345', + sortingCode: 'ABC-123', + state: 'Kingston Parish', + }, createdAt: '20/06/2022', + creator: { + _id: '123', + firstName: 'John', + lastName: 'Doe', + image: null, + email: 'john@example.com', + createdAt: '20/06/2022', + }, }, - }, - ], + ], + }, + appUserProfile: { + _id: 'user2', + adminFor: [ + { + _id: '123', + }, + ], + isSuperAdmin: false, + createdOrganizations: [], + createdEvents: [], + eventAdmin: [], + }, }, ], }, diff --git a/src/utils/interfaces.ts b/src/utils/interfaces.ts index 158329c6ac..570722c614 100644 --- a/src/utils/interfaces.ts +++ b/src/utils/interfaces.ts @@ -4,12 +4,6 @@ export interface InterfaceUserType { lastName: string; image: string | null; email: string; - userType: string; - adminFor: { - _id: string; - name: string; - image: string | null; - }[]; }; } @@ -245,43 +239,53 @@ export interface InterfaceQueryBlockPageMemberListItem { } export interface InterfaceQueryUserListItem { - _id: string; - firstName: string; - lastName: string; - image: string | null; - email: string; - userType: string; - adminFor: { _id: string }[]; - adminApproved: boolean; - organizationsBlockedBy: { + user: { _id: string; - name: string; - address: InterfaceAddress; + firstName: string; + lastName: string; image: string | null; - createdAt: string; - creator: { + email: string; + organizationsBlockedBy: { _id: string; - firstName: string; - lastName: string; - email: string; + name: string; image: string | null; - }; - }[]; - joinedOrganizations: { - _id: string; - name: string; - address: InterfaceAddress; - image: string | null; - createdAt: string; - creator: { + address: InterfaceAddress; + creator: { + _id: string; + firstName: string; + lastName: string; + email: string; + image: string | null; + }; + createdAt: string; + }[]; + joinedOrganizations: { _id: string; - firstName: string; - lastName: string; - email: string; + name: string; + address: InterfaceAddress; image: string | null; - }; - }[]; - createdAt: string; + createdAt: string; + creator: { + _id: string; + firstName: string; + lastName: string; + email: string; + image: string | null; + }; + }[]; + createdAt: string; + registeredEvents: { _id: string }[]; + membershipRequests: { _id: string }[]; + }; + appUserProfile: { + _id: string; + adminApproved: boolean; + adminFor: { _id: string }[]; + isSuperAdmin: boolean; + createdOrganizations: { _id: string }[]; + createdEvents: { _id: string }[]; + eventAdmin: { _id: string }[]; + }; } export interface InterfaceQueryRequestListItem {