From 602358416075026b75be66ccb45d8f3afaa87d22 Mon Sep 17 00:00:00 2001
From: Siddhesh Bhupendra Kuakde
Date: Thu, 23 Nov 2023 09:02:04 +0530
Subject: [PATCH] Feature request: Adding advertisement screen (#994)
* Add/ test for OrgPost.tsx
* fix: org post back to default
* Added Dialog 2
* Updated Dialog UI
* Removed Extra code
* Updated Plugin store
* fix: warnings and solves #951 & #948
* fix: warnings and solves #951 & #948
* fix: warnings and solves #951 & #948
* Fix: UI Redesign
* fix: merge
* fix
* Update AddOnStore.tsx
* Fixed Merge Errors
* Add test: for OrgEntry
* Test 3
* fix test 4
* chores: version changes
* Add: Initial Websocket setup on talawa mobile web
* Add: plugin logic
* Add: plugin logic
* removed extra
* removed extra
* Added: Tests
* fix
* Added WEBSOCKET_URL in .env.example
* Advertisement Management Screen
* Feature: Create and Delete advertisement
* Only current OrgIDs are visible to admin
* Showing advertisements in the User end app
* Message: fix
* formatting
* update test
* Fix # 1071
* Added test for entry file
* Added test for entry file2
* Added test for entry file2
---
.env.example | 5 +-
public/locales/en.json | 20 +
public/locales/fr.json | 8 +
public/locales/hi.json | 8 +
public/locales/sp.json | 8 +
public/locales/zh.json | 8 +
schema.graphql | 1152 +++++++++++++++++
src/App.tsx | 2 +
src/GraphQl/Mutations/mutations.ts | 29 +-
src/GraphQl/Queries/Queries.ts | 14 +-
.../AddOn/core/AddOnStore/AddOnStore.tsx | 2 +-
.../Advertisements/Advertisement.module.css | 31 +
.../Advertisements/Advertisement.test.tsx | 95 ++
.../Advertisements/Advertisements.tsx | 197 +++
.../AdvertisementEntry.module.css | 20 +
.../AdvertisementEntry.test.tsx | 60 +
.../AdvertisementEntry/AdvertisementEntry.tsx | 103 ++
.../AdvertisementRegister.module.css | 9 +
.../AdvertisementRegister.tsx | 207 +++
.../IconComponent/IconComponent.tsx | 2 +
.../OrganizationScreen/OrganizationScreen.tsx | 1 -
.../PromotedPost/PromotedPost.module.css | 56 +
.../UserPortal/PromotedPost/PromotedPost.tsx | 32 +
src/screens/UserPortal/Home/Home.tsx | 37 +-
src/state/reducers/routesReducer.test.ts | 19 +
src/state/reducers/routesReducer.ts | 2 +
26 files changed, 2120 insertions(+), 7 deletions(-)
create mode 100644 schema.graphql
create mode 100644 src/components/Advertisements/Advertisement.module.css
create mode 100644 src/components/Advertisements/Advertisement.test.tsx
create mode 100644 src/components/Advertisements/Advertisements.tsx
create mode 100644 src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.module.css
create mode 100644 src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.test.tsx
create mode 100644 src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.tsx
create mode 100644 src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.module.css
create mode 100644 src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.tsx
create mode 100644 src/components/UserPortal/PromotedPost/PromotedPost.module.css
create mode 100644 src/components/UserPortal/PromotedPost/PromotedPost.tsx
diff --git a/.env.example b/.env.example
index d7e32ef01d..bd9529ea79 100644
--- a/.env.example
+++ b/.env.example
@@ -17,4 +17,7 @@ REACT_APP_USE_RECAPTCHA=
# from here for reCAPTCHA v2 and "I'm not a robot" Checkbox, and paste the key here.
# Note: In domains, fill localhost
-REACT_APP_RECAPTCHA_SITE_KEY=
\ No newline at end of file
+REACT_APP_RECAPTCHA_SITE_KEY=
+
+# has to be inserted in the env file to use plugins and other websocket based features.
+REACT_APP_BACKEND_WEBSOCKET_URL=ws://localhost:4000/graphql
\ No newline at end of file
diff --git a/public/locales/en.json b/public/locales/en.json
index fb5d78bc2f..50945e8dde 100644
--- a/public/locales/en.json
+++ b/public/locales/en.json
@@ -65,6 +65,7 @@
"Block/Unblock": "Block/Unblock",
"Plugins": "Plugins",
"Plugin Store": "Plugin Store",
+ "Advertisement": "Advertisements",
"allOrganizations": "All Organizations",
"yourOrganization": "Your Organization",
"notification": "Notification",
@@ -656,6 +657,25 @@
"event": "Event",
"organization": "Organization"
},
+ "advertisement": {
+ "title": "Advertisements",
+ "pHeading": "Manage Ads",
+ "activeAds": "Active Campaigns",
+ "archievedAds": "Completed Campaigns",
+ "pMessage": "Ads not present for this campaign.",
+ "delete": "Delete",
+ "Rname": "Enter name of Advertisement",
+ "Rtype": "Select type of Advertisement",
+ "Rlink": "Provide a link for content to be displayed",
+ "RstartDate": "Select Start Date",
+ "RendDate": "Select End Date",
+ "RClose": "Close the window",
+ "addNew": "Create new advertisement",
+ "EXname": "Ex. Cookie Shop",
+ "EXlink": "Ex. http://yourwebsite.com/photo",
+ "register": "Create Advertisement",
+ "close": "Close "
+ },
"userChat": {
"chat": "Chat",
"search": "Search",
diff --git a/public/locales/fr.json b/public/locales/fr.json
index 97116881e9..75522a0fed 100644
--- a/public/locales/fr.json
+++ b/public/locales/fr.json
@@ -646,6 +646,14 @@
"event": "Événement",
"organization": "Organisation"
},
+ "advertisement": {
+ "title": "Publicités",
+ "pHeading": "Gérer les publicités",
+ "activeAds": "Campagnes actives",
+ "archievedAds": "Campagnes terminées",
+ "pMessage": "Aucune publicité n'est présente pour cette campagne.",
+ "delete": "Supprimer"
+ },
"userChat": {
"chat": "Chat",
"search": "Recherche",
diff --git a/public/locales/hi.json b/public/locales/hi.json
index 490b5b5d04..d952ff7f30 100644
--- a/public/locales/hi.json
+++ b/public/locales/hi.json
@@ -646,6 +646,14 @@
"event": "आयोजन",
"organization": "संगठन"
},
+ "advertisement": {
+ "title": "विज्ञापन",
+ "pHeading": "विज्ञापन प्रबंधन",
+ "activeAds": "सक्रिय अभियान",
+ "archievedAds": "संपन्न अभियान",
+ "pMessage": "इस अभियान के लिए कोई विज्ञापन नहीं हैं।",
+ "delete": "हटाएँ"
+ },
"userChat": {
"chat": "बात",
"search": "खोज",
diff --git a/public/locales/sp.json b/public/locales/sp.json
index 33cb77ed64..9b107afd44 100644
--- a/public/locales/sp.json
+++ b/public/locales/sp.json
@@ -646,6 +646,14 @@
"event": "Evento",
"organization": "Organización"
},
+ "advertisement": {
+ "title": "Anuncios",
+ "pHeading": "Gestionar anuncios",
+ "activeAds": "Campañas activas",
+ "archievedAds": "Campañas completadas",
+ "pMessage": "No hay anuncios disponibles para esta campaña.",
+ "delete": "Eliminar"
+ },
"userChat": {
"chat": "Charlar",
"search": "Buscar",
diff --git a/public/locales/zh.json b/public/locales/zh.json
index 8de1d7c5d9..92e8c14c83 100644
--- a/public/locales/zh.json
+++ b/public/locales/zh.json
@@ -646,6 +646,14 @@
"event": "事件",
"organization": "組織"
},
+ "advertisement": {
+ "title": "广告",
+ "pHeading": "管理广告",
+ "activeAds": "活动广告",
+ "archievedAds": "已完成的广告活动",
+ "pMessage": "此广告活动没有相关广告。",
+ "delete": "删除"
+ },
"userChat": {
"chat": "聊天",
"search": "搜尋",
diff --git a/schema.graphql b/schema.graphql
new file mode 100644
index 0000000000..d200ee7349
--- /dev/null
+++ b/schema.graphql
@@ -0,0 +1,1152 @@
+directive @auth on FIELD_DEFINITION
+
+directive @role(requires: UserType) on FIELD_DEFINITION
+
+type Advertisement {
+ _id: ID
+ endDate: Date!
+ link: String!
+ name: String!
+ orgId: ID
+ startDate: Date!
+ type: String!
+}
+
+type AggregatePost {
+ count: Int!
+}
+
+type AggregateUser {
+ count: Int!
+}
+
+type AndroidFirebaseOptions {
+ apiKey: String
+ appId: String
+ messagingSenderId: String
+ projectId: String
+ storageBucket: String
+}
+
+type AuthData {
+ accessToken: String!
+ androidFirebaseOptions: AndroidFirebaseOptions!
+ iosFirebaseOptions: IOSFirebaseOptions!
+ refreshToken: String!
+ user: User!
+}
+
+type CheckIn {
+ _id: ID!
+ allotedRoom: String
+ allotedSeat: String
+ event: Event!
+ feedbackSubmitted: Boolean!
+ time: DateTime!
+ user: User!
+}
+
+input CheckInInput {
+ allotedRoom: String
+ allotedSeat: String
+ eventId: ID!
+ userId: ID!
+}
+
+type CheckInStatus {
+ _id: ID!
+ checkIn: CheckIn
+ user: User!
+}
+
+type Comment {
+ _id: ID
+ createdAt: DateTime
+ creator: User!
+ likeCount: Int
+ likedBy: [User]
+ post: Post!
+ text: String!
+}
+
+input CommentInput {
+ text: String!
+}
+
+union ConnectionError = InvalidCursor | MaximumValueError
+
+type ConnectionPageInfo {
+ endCursor: String
+ hasNextPage: Boolean!
+ hasPreviousPage: Boolean!
+ startCursor: String
+}
+
+input CreateUserTagInput {
+ name: String!
+ organizationId: ID!
+ parentTagId: ID
+}
+
+input CursorPaginationInput {
+ cursor: String
+ direction: PaginationDirection!
+ limit: PositiveInt!
+}
+
+scalar Date
+
+scalar DateTime
+
+type DeletePayload {
+ success: Boolean!
+}
+
+type DirectChat {
+ _id: ID!
+ creator: User!
+ messages: [DirectChatMessage]
+ organization: Organization!
+ users: [User!]!
+}
+
+type DirectChatMessage {
+ _id: ID!
+ createdAt: DateTime!
+ directChatMessageBelongsTo: DirectChat!
+ messageContent: String!
+ receiver: User!
+ sender: User!
+}
+
+type Donation {
+ _id: ID!
+ amount: Float!
+ nameOfOrg: String!
+ nameOfUser: String!
+ orgId: ID!
+ payPalId: String!
+ userId: ID!
+}
+
+input DonationWhereInput {
+ id: ID
+ id_contains: ID
+ id_in: [ID!]
+ id_not: ID
+ id_not_in: [ID!]
+ id_starts_with: ID
+ name_of_user: String
+ name_of_user_contains: String
+ name_of_user_in: [String!]
+ name_of_user_not: String
+ name_of_user_not_in: [String!]
+ name_of_user_starts_with: String
+}
+
+scalar EmailAddress
+
+interface Error {
+ message: String!
+}
+
+type Event {
+ _id: ID!
+ admins(adminId: ID): [User]
+ allDay: Boolean!
+ attendees: [User!]!
+ attendeesCheckInStatus: [CheckInStatus!]!
+ averageFeedbackScore: Float
+ creator: User!
+ description: String!
+ endDate: Date!
+ endTime: Time
+ feedback: [Feedback!]!
+ isPublic: Boolean!
+ isRegisterable: Boolean!
+ latitude: Latitude
+ location: String
+ longitude: Longitude
+ organization: Organization
+ projects: [EventProject]
+ recurrance: Recurrance
+ recurring: Boolean!
+ startDate: Date!
+ startTime: Time
+ status: Status!
+ title: String!
+}
+
+input EventAttendeeInput {
+ eventId: ID!
+ userId: ID!
+}
+
+input EventInput {
+ allDay: Boolean!
+ description: String!
+ endDate: Date
+ endTime: Time
+ isPublic: Boolean!
+ isRegisterable: Boolean!
+ latitude: Latitude
+ location: String
+ longitude: Longitude
+ organizationId: ID!
+ recurrance: Recurrance
+ recurring: Boolean!
+ startDate: Date!
+ startTime: Time
+ title: String!
+}
+
+enum EventOrderByInput {
+ allDay_ASC
+ allDay_DESC
+ description_ASC
+ description_DESC
+ endDate_ASC
+ endDate_DESC
+ endTime_ASC
+ endTime_DESC
+ id_ASC
+ id_DESC
+ location_ASC
+ location_DESC
+ recurrance_ASC
+ recurrance_DESC
+ startDate_ASC
+ startDate_DESC
+ startTime_ASC
+ startTime_DESC
+ title_ASC
+ title_DESC
+}
+
+type EventProject {
+ _id: ID!
+ description: String!
+ event: Event!
+ tasks: [Task]
+ title: String!
+}
+
+input EventProjectInput {
+ description: String!
+ eventId: ID!
+ title: String!
+}
+
+input EventWhereInput {
+ description: String
+ description_contains: String
+ description_in: [String!]
+ description_not: String
+ description_not_in: [String!]
+ description_starts_with: String
+ id: ID
+ id_contains: ID
+ id_in: [ID!]
+ id_not: ID
+ id_not_in: [ID!]
+ id_starts_with: ID
+ location: String
+ location_contains: String
+ location_in: [String!]
+ location_not: String
+ location_not_in: [String!]
+ location_starts_with: String
+ organization_id: ID
+ title: String
+ title_contains: String
+ title_in: [String!]
+ title_not: String
+ title_not_in: [String!]
+ title_starts_with: String
+}
+
+type ExtendSession {
+ accessToken: String!
+ refreshToken: String!
+}
+
+type Feedback {
+ _id: ID!
+ event: Event!
+ rating: Int!
+ review: String
+}
+
+input FeedbackInput {
+ eventId: ID!
+ rating: Int!
+ review: String
+}
+
+interface FieldError {
+ message: String!
+ path: [String!]!
+}
+
+input ForgotPasswordData {
+ newPassword: String!
+ otpToken: String!
+ userOtp: String!
+}
+
+type Group {
+ _id: ID
+ admins: [User]
+ createdAt: DateTime
+ description: String
+ organization: Organization!
+ title: String
+}
+
+type GroupChat {
+ _id: ID!
+ creator: User!
+ messages: [GroupChatMessage]
+ organization: Organization!
+ users: [User!]!
+}
+
+type GroupChatMessage {
+ _id: ID!
+ createdAt: DateTime!
+ groupChatMessageBelongsTo: GroupChat!
+ messageContent: String!
+ sender: User!
+}
+
+type IOSFirebaseOptions {
+ apiKey: String
+ appId: String
+ iosBundleId: String
+ iosClientId: String
+ messagingSenderId: String
+ projectId: String
+ storageBucket: String
+}
+
+type InvalidCursor implements FieldError {
+ message: String!
+ path: [String!]!
+}
+
+type Language {
+ _id: ID!
+ createdAt: String!
+ en: String!
+ translation: [LanguageModel]
+}
+
+input LanguageInput {
+ en_value: String!
+ translation_lang_code: String!
+ translation_value: String!
+}
+
+type LanguageModel {
+ _id: ID!
+ createdAt: DateTime!
+ lang_code: String!
+ value: String!
+ verified: Boolean!
+}
+
+scalar Latitude
+
+input LoginInput {
+ email: EmailAddress!
+ password: String!
+}
+
+scalar Longitude
+
+type MaximumLengthError implements FieldError {
+ message: String!
+ path: [String!]!
+}
+
+type MaximumValueError implements FieldError {
+ limit: Int!
+ message: String!
+ path: [String!]!
+}
+
+type MembershipRequest {
+ _id: ID!
+ organization: Organization!
+ user: User!
+}
+
+type Message {
+ _id: ID!
+ createdAt: DateTime
+ creator: User
+ imageUrl: URL
+ text: String
+ videoUrl: URL
+}
+
+type MessageChat {
+ _id: ID!
+ createdAt: DateTime!
+ languageBarrier: Boolean
+ message: String!
+ receiver: User!
+ sender: User!
+}
+
+input MessageChatInput {
+ message: String!
+ receiver: ID!
+}
+
+type MinimumLengthError implements FieldError {
+ limit: Int!
+ message: String!
+ path: [String!]!
+}
+
+type MinimumValueError implements FieldError {
+ message: String!
+ path: [String!]!
+}
+
+type Mutation {
+ acceptAdmin(id: ID!): Boolean!
+ acceptMembershipRequest(membershipRequestId: ID!): MembershipRequest!
+ addEventAttendee(data: EventAttendeeInput!): User!
+ addFeedback(data: FeedbackInput!): Feedback!
+ addLanguageTranslation(data: LanguageInput!): Language!
+ addOrganizationImage(file: String!, organizationId: String!): Organization!
+ addUserImage(file: String!): User!
+ addUserToGroupChat(chatId: ID!, userId: ID!): GroupChat!
+ adminRemoveEvent(eventId: ID!): Event!
+ adminRemoveGroup(groupId: ID!): GroupChat!
+ assignUserTag(input: ToggleUserTagAssignInput!): User
+ blockPluginCreationBySuperadmin(blockUser: Boolean!, userId: ID!): User!
+ blockUser(organizationId: ID!, userId: ID!): User!
+ cancelMembershipRequest(membershipRequestId: ID!): MembershipRequest!
+ checkIn(data: CheckInInput!): CheckIn!
+ createAdmin(data: UserAndOrganizationInput!): User!
+ createAdvertisement(
+ endDate: Date!
+ link: String!
+ name: String!
+ orgId: ID!
+ startDate: Date!
+ type: String!
+ ): Advertisement!
+ createComment(data: CommentInput!, postId: ID!): Comment
+ createDirectChat(data: createChatInput!): DirectChat!
+ createDonation(
+ amount: Float!
+ nameOfOrg: String!
+ nameOfUser: String!
+ orgId: ID!
+ payPalId: ID!
+ userId: ID!
+ ): Donation!
+ createEvent(data: EventInput): Event!
+ createEventProject(data: EventProjectInput!): EventProject!
+ createGroupChat(data: createGroupChatInput!): GroupChat!
+ createMember(input: UserAndOrganizationInput!): Organization!
+ createMessageChat(data: MessageChatInput!): MessageChat!
+ createOrganization(data: OrganizationInput, file: String): Organization!
+ createPlugin(
+ pluginCreatedBy: String!
+ pluginDesc: String!
+ pluginName: String!
+ uninstalledOrgs: [ID!]
+ ): Plugin!
+ createPost(data: PostInput!, file: String): Post
+ createTask(data: TaskInput!, eventProjectId: ID!): Task!
+ createUserTag(input: CreateUserTagInput!): UserTag
+ deleteAdvertisementById(id: ID!): DeletePayload!
+ deleteDonationById(id: ID!): DeletePayload!
+ forgotPassword(data: ForgotPasswordData!): Boolean!
+ joinPublicOrganization(organizationId: ID!): User!
+ leaveOrganization(organizationId: ID!): User!
+ likeComment(id: ID!): Comment
+ likePost(id: ID!): Post
+ login(data: LoginInput!): AuthData!
+ logout: Boolean!
+ otp(data: OTPInput!): OtpData!
+ recaptcha(data: RecaptchaVerification!): Boolean!
+ refreshToken(refreshToken: String!): ExtendSession!
+ registerForEvent(id: ID!): Event!
+ rejectAdmin(id: ID!): Boolean!
+ rejectMembershipRequest(membershipRequestId: ID!): MembershipRequest!
+ removeAdmin(data: UserAndOrganizationInput!): User!
+ removeAdvertisement(id: ID!): Advertisement
+ removeComment(id: ID!): Comment
+ removeDirectChat(chatId: ID!, organizationId: ID!): DirectChat!
+ removeEvent(id: ID!): Event!
+ removeEventAttendee(data: EventAttendeeInput!): User!
+ removeEventProject(id: ID!): EventProject!
+ removeGroupChat(chatId: ID!): GroupChat!
+ removeMember(data: UserAndOrganizationInput!): Organization!
+ removeOrganization(id: ID!): User!
+ removeOrganizationImage(organizationId: String!): Organization!
+ removePost(id: ID!): Post
+ removeTask(id: ID!): Task
+ removeUserFromGroupChat(chatId: ID!, userId: ID!): GroupChat!
+ removeUserImage: User!
+ removeUserTag(id: ID!): UserTag
+ revokeRefreshTokenForUser(userId: String!): Boolean!
+ saveFcmToken(token: String): Boolean!
+ sendMembershipRequest(organizationId: ID!): MembershipRequest!
+ sendMessageToDirectChat(
+ chatId: ID!
+ messageContent: String!
+ ): DirectChatMessage!
+ sendMessageToGroupChat(
+ chatId: ID!
+ messageContent: String!
+ ): GroupChatMessage!
+ setTaskVolunteers(id: ID!, volunteers: [ID]!): Task
+ signUp(data: UserInput!, file: String): AuthData!
+ togglePostPin(id: ID!): Post!
+ unassignUserTag(input: ToggleUserTagAssignInput!): User
+ unblockUser(organizationId: ID!, userId: ID!): User!
+ unlikeComment(id: ID!): Comment
+ unlikePost(id: ID!): Post
+ unregisterForEventByUser(id: ID!): Event!
+ updateEvent(data: UpdateEventInput, id: ID!): Event!
+ updateEventProject(data: UpdateEventProjectInput!, id: ID!): EventProject!
+ updateLanguage(languageCode: String!): User!
+ updateOrganization(
+ data: UpdateOrganizationInput
+ file: String
+ id: ID!
+ ): Organization!
+ updatePluginStatus(id: ID!, orgId: ID!): Plugin!
+ updatePost(data: PostUpdateInput, id: ID!): Post!
+ updateTask(data: UpdateTaskInput!, id: ID!): Task
+ updateUserPassword(data: UpdateUserPasswordInput!): User!
+ updateUserProfile(data: UpdateUserInput, file: String): User!
+ updateUserTag(input: UpdateUserTagInput!): UserTag
+ updateUserType(data: UpdateUserTypeInput!): Boolean!
+}
+
+input OTPInput {
+ email: EmailAddress!
+}
+
+type Organization {
+ _id: ID!
+ admins(adminId: ID): [User]
+ apiUrl: URL!
+ blockedUsers: [User]
+ createdAt: DateTime
+ creator: User!
+ description: String!
+ image: String
+ isPublic: Boolean!
+ location: String
+ members: [User]
+ membershipRequests: [MembershipRequest]
+ name: String!
+ pinnedPosts: [Post]
+ userTags(
+ after: String
+ before: String
+ first: PositiveInt
+ last: PositiveInt
+ ): UserTagsConnection
+ visibleInSearch: Boolean!
+}
+
+type OrganizationInfoNode {
+ _id: ID!
+ apiUrl: URL!
+ creator: User!
+ description: String!
+ image: String
+ isPublic: Boolean!
+ name: String!
+ visibleInSearch: Boolean!
+}
+
+input OrganizationInput {
+ apiUrl: URL
+ attendees: String
+ description: String!
+ image: String
+ isPublic: Boolean!
+ location: String
+ name: String!
+ visibleInSearch: Boolean!
+}
+
+enum OrganizationOrderByInput {
+ apiUrl_ASC
+ apiUrl_DESC
+ description_ASC
+ description_DESC
+ id_ASC
+ id_DESC
+ name_ASC
+ name_DESC
+}
+
+input OrganizationWhereInput {
+ apiUrl: URL
+ apiUrl_contains: URL
+ apiUrl_in: [URL!]
+ apiUrl_not: URL
+ apiUrl_not_in: [URL!]
+ apiUrl_starts_with: URL
+ description: String
+ description_contains: String
+ description_in: [String!]
+ description_not: String
+ description_not_in: [String!]
+ description_starts_with: String
+ id: ID
+ id_contains: ID
+ id_in: [ID!]
+ id_not: ID
+ id_not_in: [ID!]
+ id_starts_with: ID
+ isPublic: Boolean
+ name: String
+ name_contains: String
+ name_in: [String!]
+ name_not: String
+ name_not_in: [String!]
+ name_starts_with: String
+ visibleInSearch: Boolean
+}
+
+type OtpData {
+ otpToken: String!
+}
+
+"""
+Information about pagination in a connection.
+"""
+type PageInfo {
+ currPageNo: Int
+
+ """
+ When paginating forwards, are there more items?
+ """
+ hasNextPage: Boolean!
+
+ """
+ When paginating backwards, are there more items?
+ """
+ hasPreviousPage: Boolean!
+ nextPageNo: Int
+ prevPageNo: Int
+ totalPages: Int
+}
+
+enum PaginationDirection {
+ BACKWARD
+ FORWARD
+}
+
+scalar PhoneNumber
+
+type Plugin {
+ _id: ID!
+ pluginCreatedBy: String!
+ pluginDesc: String!
+ pluginName: String!
+ uninstalledOrgs: [ID!]!
+}
+
+type PluginField {
+ createdAt: DateTime
+ key: String!
+ status: Status!
+ value: String!
+}
+
+input PluginFieldInput {
+ key: String!
+ value: String!
+}
+
+input PluginInput {
+ fields: [PluginFieldInput]
+ orgId: ID!
+ pluginKey: String
+ pluginName: String!
+ pluginType: Type
+}
+
+scalar PositiveInt
+
+type Post {
+ _id: ID
+ commentCount: Int
+ comments: [Comment]
+ createdAt: DateTime
+ creator: User!
+ imageUrl: URL
+ likeCount: Int
+ likedBy: [User]
+ organization: Organization!
+ pinned: Boolean
+ text: String!
+ title: String
+ videoUrl: URL
+}
+
+"""
+A connection to a list of items.
+"""
+type PostConnection {
+ aggregate: AggregatePost!
+
+ """
+ A list of edges.
+ """
+ edges: [Post]!
+
+ """
+ Information to aid in pagination.
+ """
+ pageInfo: PageInfo!
+}
+
+input PostInput {
+ _id: ID
+ imageUrl: URL
+ organizationId: ID!
+ pinned: Boolean
+ text: String!
+ title: String
+ videoUrl: URL
+}
+
+enum PostOrderByInput {
+ commentCount_ASC
+ commentCount_DESC
+ createdAt_ASC
+ createdAt_DESC
+ id_ASC
+ id_DESC
+ imageUrl_ASC
+ imageUrl_DESC
+ likeCount_ASC
+ likeCount_DESC
+ text_ASC
+ text_DESC
+ title_ASC
+ title_DESC
+ videoUrl_ASC
+ videoUrl_DESC
+}
+
+input PostUpdateInput {
+ imageUrl: String
+ text: String
+ title: String
+ videoUrl: String
+}
+
+input PostWhereInput {
+ id: ID
+ id_contains: ID
+ id_in: [ID!]
+ id_not: ID
+ id_not_in: [ID!]
+ id_starts_with: ID
+ text: String
+ text_contains: String
+ text_in: [String!]
+ text_not: String
+ text_not_in: [String!]
+ text_starts_with: String
+ title: String
+ title_contains: String
+ title_in: [String!]
+ title_not: String
+ title_not_in: [String!]
+ title_starts_with: String
+}
+
+type Query {
+ adminPlugin(orgId: ID!): [Plugin]
+ checkAuth: User!
+ directChatsByUserID(id: ID!): [DirectChat]
+ directChatsMessagesByChatID(id: ID!): [DirectChatMessage]
+ event(id: ID!): Event
+ eventsByOrganization(id: ID, orderBy: EventOrderByInput): [Event]
+ eventsByOrganizationConnection(
+ first: Int
+ orderBy: EventOrderByInput
+ skip: Int
+ where: EventWhereInput
+ ): [Event!]!
+ getAdvertisements: [Advertisement]
+ getDonationById(id: ID!): Donation!
+ getDonationByOrgId(orgId: ID!): [Donation]
+ getDonationByOrgIdConnection(
+ first: Int
+ orgId: ID!
+ skip: Int
+ where: DonationWhereInput
+ ): [Donation!]!
+ getPlugins: [Plugin]
+ getlanguage(lang_code: String!): [Translation]
+ hasSubmittedFeedback(eventId: ID!, userId: ID!): Boolean
+ joinedOrganizations(id: ID): [Organization]
+ me: User!
+ myLanguage: String
+ organizations(id: ID, orderBy: OrganizationOrderByInput): [Organization]
+ organizationsConnection(
+ first: Int
+ orderBy: OrganizationOrderByInput
+ skip: Int
+ where: OrganizationWhereInput
+ ): [Organization]!
+ organizationsMemberConnection(
+ first: Int
+ orderBy: UserOrderByInput
+ orgId: ID!
+ skip: Int
+ where: UserWhereInput
+ ): UserConnection!
+ plugin(orgId: ID!): [Plugin]
+ post(id: ID!): Post
+ postsByOrganization(id: ID!, orderBy: PostOrderByInput): [Post]
+ postsByOrganizationConnection(
+ first: Int
+ id: ID!
+ orderBy: PostOrderByInput
+ skip: Int
+ where: PostWhereInput
+ ): PostConnection
+ registeredEventsByUser(id: ID, orderBy: EventOrderByInput): [Event]
+ registrantsByEvent(id: ID!): [User]
+ user(id: ID!): User!
+ userLanguage(userId: ID!): String
+ users(orderBy: UserOrderByInput, where: UserWhereInput): [User]
+ usersConnection(
+ first: Int
+ orderBy: UserOrderByInput
+ skip: Int
+ where: UserWhereInput
+ ): [User]!
+}
+
+input RecaptchaVerification {
+ recaptchaToken: String!
+}
+
+enum Recurrance {
+ DAILY
+ MONTHLY
+ ONCE
+ WEEKLY
+ YEARLY
+}
+
+enum Status {
+ ACTIVE
+ BLOCKED
+ DELETED
+}
+
+type Subscription {
+ directMessageChat: MessageChat
+ messageSentToDirectChat: DirectChatMessage
+ messageSentToGroupChat: GroupChatMessage
+ onPluginUpdate: Plugin
+}
+
+type Task {
+ _id: ID!
+ completed: Boolean
+ createdAt: DateTime!
+ creator: User!
+ deadline: DateTime
+ description: String
+ event: Event!
+ title: String!
+ volunteers: [User]
+}
+
+input TaskInput {
+ deadline: DateTime!
+ description: String!
+ title: String!
+}
+
+enum TaskOrderByInput {
+ createdAt_ASC
+ createdAt_DESC
+ deadline_ASC
+ deadline_DESC
+ description_ASC
+ description_DESC
+ id_ASC
+ id_DESC
+ title_ASC
+ title_DESC
+}
+
+scalar Time
+
+input ToggleUserTagAssignInput {
+ tagId: ID!
+ userId: ID!
+}
+
+type Translation {
+ en_value: String
+ lang_code: String
+ translation: String
+ verified: Boolean
+}
+
+enum Type {
+ PRIVATE
+ UNIVERSAL
+}
+
+scalar URL
+
+type UnauthenticatedError implements Error {
+ message: String!
+}
+
+type UnauthorizedError implements Error {
+ message: String!
+}
+
+input UpdateEventInput {
+ allDay: Boolean
+ description: String
+ endDate: Date
+ endTime: Time
+ isPublic: Boolean
+ isRegisterable: Boolean
+ latitude: Latitude
+ location: String
+ longitude: Longitude
+ recurrance: Recurrance
+ recurring: Boolean
+ startDate: Date
+ startTime: Time
+ title: String
+}
+
+input UpdateEventProjectInput {
+ description: String
+ title: String
+}
+
+input UpdateOrganizationInput {
+ description: String
+ isPublic: Boolean
+ location: String
+ name: String
+ visibleInSearch: Boolean
+}
+
+input UpdateTaskInput {
+ completed: Boolean
+ deadline: DateTime
+ description: String
+ title: String
+}
+
+input UpdateUserInput {
+ email: EmailAddress
+ firstName: String
+ lastName: String
+}
+
+input UpdateUserPasswordInput {
+ confirmNewPassword: String!
+ newPassword: String!
+ previousPassword: String!
+}
+
+input UpdateUserTagInput {
+ _id: ID!
+ name: String!
+}
+
+input UpdateUserTypeInput {
+ id: ID
+ userType: String
+}
+
+scalar Upload
+
+type User {
+ _id: ID!
+ adminApproved: Boolean
+ adminFor: [Organization]
+ appLanguageCode: String!
+ assignedTasks: [Task]
+ createdAt: DateTime
+ createdEvents: [Event]
+ createdOrganizations: [Organization]
+ email: EmailAddress!
+ eventAdmin: [Event]
+ firstName: String!
+ image: String
+ joinedOrganizations: [Organization]
+ lastName: String!
+ membershipRequests: [MembershipRequest]
+ organizationUserBelongsTo: Organization
+ organizationsBlockedBy: [Organization]
+ pluginCreationAllowed: Boolean
+ registeredEvents: [Event]
+ tagsAssignedWith(
+ after: String
+ before: String
+ first: PositiveInt
+ last: PositiveInt
+ organizationId: ID
+ ): UserTagsConnection
+ tokenVersion: Int!
+ userType: String
+}
+
+input UserAndOrganizationInput {
+ organizationId: ID!
+ userId: ID!
+}
+
+type UserConnection {
+ aggregate: AggregateUser!
+ edges: [User]!
+ pageInfo: PageInfo!
+}
+
+type UserEdge {
+ cursor: String!
+ node: User!
+}
+
+input UserInput {
+ appLanguageCode: String
+ email: EmailAddress!
+ firstName: String!
+ lastName: String!
+ organizationUserBelongsToId: ID
+ password: String!
+}
+
+enum UserOrderByInput {
+ appLanguageCode_ASC
+ appLanguageCode_DESC
+ email_ASC
+ email_DESC
+ firstName_ASC
+ firstName_DESC
+ id_ASC
+ id_DESC
+ lastName_ASC
+ lastName_DESC
+}
+
+type UserTag {
+ _id: ID!
+ childTags(input: UserTagsConnectionInput!): UserTagsConnectionResult!
+ name: String!
+ organization: Organization
+ parentTag: UserTag
+ usersAssignedTo(input: UsersConnectionInput!): UsersConnectionResult!
+}
+
+type UserTagEdge {
+ cursor: String!
+ node: UserTag!
+}
+
+type UserTagsConnection {
+ edges: [UserTagEdge!]!
+ pageInfo: ConnectionPageInfo!
+}
+
+input UserTagsConnectionInput {
+ cursor: String
+ direction: PaginationDirection!
+ limit: PositiveInt!
+}
+
+type UserTagsConnectionResult {
+ data: UserTagsConnection
+ errors: [ConnectionError!]!
+}
+
+enum UserType {
+ ADMIN
+ 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!]
+ email_not: EmailAddress
+ email_not_in: [EmailAddress!]
+ email_starts_with: EmailAddress
+ event_title_contains: String
+ firstName: String
+ firstName_contains: String
+ firstName_in: [String!]
+ firstName_not: String
+ firstName_not_in: [String!]
+ firstName_starts_with: String
+ id: ID
+ id_contains: ID
+ id_in: [ID!]
+ id_not: ID
+ id_not_in: [ID!]
+ id_starts_with: ID
+ lastName: String
+ lastName_contains: String
+ lastName_in: [String!]
+ lastName_not: String
+ lastName_not_in: [String!]
+ lastName_starts_with: String
+}
+
+type UsersConnection {
+ edges: [UserEdge!]!
+ pageInfo: ConnectionPageInfo!
+}
+
+input UsersConnectionInput {
+ cursor: String
+ direction: PaginationDirection!
+ limit: PositiveInt!
+}
+
+type UsersConnectionResult {
+ data: UsersConnection
+ errors: [ConnectionError!]!
+}
+
+input createChatInput {
+ organizationId: ID!
+ userIds: [ID!]!
+}
+
+input createGroupChatInput {
+ organizationId: ID!
+ title: String!
+ userIds: [ID!]!
+}
diff --git a/src/App.tsx b/src/App.tsx
index cf20c722e5..1c69256c32 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -32,6 +32,7 @@ import Settings from 'screens/UserPortal/Settings/Settings';
import Donate from 'screens/UserPortal/Donate/Donate';
import Events from 'screens/UserPortal/Events/Events';
import Tasks from 'screens/UserPortal/Tasks/Tasks';
+import Advertisements from 'components/Advertisements/Advertisements';
import Chat from 'screens/UserPortal/Chat/Chat';
function app(): JSX.Element {
@@ -109,6 +110,7 @@ function app(): JSX.Element {
+
diff --git a/src/GraphQl/Mutations/mutations.ts b/src/GraphQl/Mutations/mutations.ts
index dca9e713c3..34abda2b26 100644
--- a/src/GraphQl/Mutations/mutations.ts
+++ b/src/GraphQl/Mutations/mutations.ts
@@ -400,7 +400,34 @@ export const ADD_PLUGIN_MUTATION = gql`
}
}
`;
-
+export const ADD_ADVERTISEMENT_MUTATION = gql`
+ mutation (
+ $orgId: ID!
+ $name: String!
+ $link: String!
+ $type: String!
+ $startDate: Date!
+ $endDate: Date!
+ ) {
+ createAdvertisement(
+ orgId: $orgId
+ name: $name
+ link: $link
+ type: $type
+ startDate: $startDate
+ endDate: $endDate
+ ) {
+ _id
+ }
+ }
+`;
+export const DELETE_ADVERTISEMENT_BY_ID = gql`
+ mutation ($id: ID!) {
+ deleteAdvertisementById(id: $id) {
+ success
+ }
+ }
+`;
export const UPDATE_POST_MUTATION = gql`
mutation UpdatePost(
$id: ID!
diff --git a/src/GraphQl/Queries/Queries.ts b/src/GraphQl/Queries/Queries.ts
index 500dde6192..7bf99d48ee 100644
--- a/src/GraphQl/Queries/Queries.ts
+++ b/src/GraphQl/Queries/Queries.ts
@@ -704,7 +704,19 @@ export const PLUGIN_GET = gql`
}
}
`;
-
+export const ADVERTISEMENTS_GET = gql`
+ query getAdvertisement {
+ getAdvertisements {
+ _id
+ name
+ type
+ orgId
+ link
+ endDate
+ startDate
+ }
+ }
+`;
export const ORGANIZATION_EVENTS_CONNECTION = gql`
query EventsByOrganizationConnection(
$organization_id: ID!
diff --git a/src/components/AddOn/core/AddOnStore/AddOnStore.tsx b/src/components/AddOn/core/AddOnStore/AddOnStore.tsx
index 2e3e511149..d81ce6fa4c 100644
--- a/src/components/AddOn/core/AddOnStore/AddOnStore.tsx
+++ b/src/components/AddOn/core/AddOnStore/AddOnStore.tsx
@@ -160,7 +160,7 @@ function addOnStore(): JSX.Element {
Search results for {searchText}
) : null}
-
+
= new ApolloClient({
+ cache: new InMemoryCache(),
+ link: ApolloLink.from([httpLink]),
+});
+describe('Testing Advertisement Component', () => {
+ test('Temporary test for Advertisement', () => {
+ expect(true).toBe(true);
+ const { getByTestId } = render(
+
+
+
+
+ {}
+
+
+
+
+ );
+ expect(getByTestId('AdEntryStore')).toBeInTheDocument();
+ });
+
+ test('renders advertisement data', async () => {
+ const mocks = [
+ {
+ request: {
+ query: ADVERTISEMENTS_GET,
+ variables: {
+ name: 'Test',
+ },
+ },
+ result: {
+ data: {
+ getAdvertisements: [
+ {
+ _id: '1',
+ name: 'Advertisement',
+ type: 'POPUP',
+ orgId: 'org1',
+ link: 'http://example.com',
+ endDate: new Date(),
+ startDate: new Date(),
+ },
+ // Add more mock data if needed
+ ],
+ },
+ loading: false,
+ },
+ },
+ ];
+
+ const { getByTestId } = render(
+
+
+
+
+
+
+
+
+
+
+
+ );
+
+ expect(getByTestId('AdEntryStore')).toBeInTheDocument();
+ });
+});
diff --git a/src/components/Advertisements/Advertisements.tsx b/src/components/Advertisements/Advertisements.tsx
new file mode 100644
index 0000000000..2d9d936d1e
--- /dev/null
+++ b/src/components/Advertisements/Advertisements.tsx
@@ -0,0 +1,197 @@
+/* eslint-disable @typescript-eslint/no-unused-vars */
+import React, { useEffect, useState } from 'react';
+import PropTypes from 'react';
+import styles from './Advertisement.module.css';
+import { useQuery } from '@apollo/client';
+import { ADVERTISEMENTS_GET, PLUGIN_GET } from 'GraphQl/Queries/Queries'; // PLUGIN_LIST
+import { useSelector } from 'react-redux';
+import type { RootState } from '../../state/reducers';
+import { Col, Form, Row, Tab, Tabs } from 'react-bootstrap';
+import PluginHelper from 'components/AddOn/support/services/Plugin.helper';
+import { store } from 'state/store';
+import { useTranslation } from 'react-i18next';
+import Loader from 'components/Loader/Loader';
+import OrganizationScreen from 'components/OrganizationScreen/OrganizationScreen';
+import AdvertisementEntry from './core/AdvertisementEntry/AdvertisementEntry';
+import AdvertisementRegister from './core/AdvertisementRegister/AdvertisementRegister';
+import AddOnRegister from 'components/AddOn/core/AddOnRegister/AddOnRegister';
+export default function advertisements(): JSX.Element {
+ const {
+ data: data2,
+ loading: loading2,
+ error: error2,
+ } = useQuery(ADVERTISEMENTS_GET);
+ const currentOrgId = window.location.href.split('/id=')[1] + '';
+ const { t } = useTranslation('translation', { keyPrefix: 'advertisement' });
+ document.title = t('title');
+
+ const [isStore, setIsStore] = useState(true);
+ const [showEnabled, setShowEnabled] = useState(true);
+ const [searchText, setSearchText] = useState('');
+ const [dataList, setDataList] = useState([]);
+
+ const [render, setRender] = useState(true);
+ const appRoutes = useSelector((state: RootState) => state.appRoutes);
+ const { targets, configUrl } = appRoutes;
+
+ const plugins = useSelector((state: RootState) => state.plugins);
+ const { installed, addonStore } = plugins;
+ const { data, loading, error } = useQuery(PLUGIN_GET);
+ /* istanbul ignore next */
+ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
+ const getStorePlugins = async () => {
+ let plugins = await new PluginHelper().fetchStore();
+ const installIds = (await new PluginHelper().fetchInstalled()).map(
+ (plugin: any) => plugin.id
+ );
+ plugins = plugins.map((plugin: any) => {
+ plugin.installed = installIds.includes(plugin.id);
+ return plugin;
+ });
+ store.dispatch({ type: 'UPDATE_STORE', payload: plugins });
+ };
+
+ /* istanbul ignore next */
+ const getInstalledPlugins: () => any = () => {
+ setDataList(data);
+ };
+ // const getAdvertisements: () => any = ()=> {
+ // return
+ // }
+
+ /* istanbul ignore next */
+ const updateLinks = async (links: any[]): Promise => {
+ store.dispatch({ type: 'UPDATE_P_TARGETS', payload: links });
+ };
+ // /* istanbul ignore next */
+ const pluginModified = (): void => {
+ return getInstalledPlugins();
+ // .then((installedPlugins) => {
+ // getStorePlugins();
+ // return installedPlugins;
+ // });
+ };
+
+ const updateSelectedTab = (tab: any): void => {
+ setIsStore(tab === 'activeAds');
+ isStore ? getStorePlugins() : getInstalledPlugins();
+ };
+
+ const filterChange = (ev: any): void => {
+ setShowEnabled(ev.target.value === 'enabled');
+ };
+
+ /* istanbul ignore next */
+ if (loading) {
+ return (
+ <>
+
+ >
+ );
+ }
+
+ return (
+ <>
+
+
+
+
+
{t('pHeading')}
+
+
+
+
+ {data2?.getAdvertisements
+ .filter((ad: any) => ad.orgId == currentOrgId)
+ .filter((ad: any) => new Date(ad.endDate) > new Date())
+ .length == 0 ? (
+ {t('pMessage')}
// eslint-disable-line
+ ) : (
+ data2?.getAdvertisements
+ .filter((ad: any) => ad.orgId == currentOrgId)
+ .filter((ad: any) => new Date(ad.endDate) > new Date())
+ .map(
+ (
+ ad: {
+ _id: string;
+ name: string | undefined;
+ type: string | undefined;
+ orgId: string;
+ link: string;
+ endDate: Date;
+ startDate: Date;
+ },
+ i: React.Key | null | undefined
+ ): JSX.Element => (
+
+ )
+ )
+ )}
+
+
+ {data2?.getAdvertisements
+ .filter((ad: any) => ad.orgId == currentOrgId)
+ .filter((ad: any) => new Date(ad.endDate) < new Date())
+ .length == 0 ? (
+ {t('pMessage')}
// eslint-disable-line
+ ) : (
+ data2?.getAdvertisements
+ .filter((ad: any) => ad.orgId == currentOrgId)
+ .filter((ad: any) => new Date(ad.endDate) < new Date())
+ .map(
+ (
+ ad: {
+ _id: string;
+ name: string | undefined;
+ type: string | undefined;
+ orgId: string;
+ link: string;
+ endDate: Date;
+ startDate: Date;
+ },
+ i: React.Key | null | undefined
+ ): JSX.Element => (
+
+ )
+ )
+ )}
+
+
+
+
+
+
+ >
+ );
+}
+
+advertisements.defaultProps = {};
+
+advertisements.propTypes = {};
diff --git a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.module.css b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.module.css
new file mode 100644
index 0000000000..1f1ea89996
--- /dev/null
+++ b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.module.css
@@ -0,0 +1,20 @@
+.entrytoggle {
+ margin: 24px 24px 0 auto;
+ width: fit-content;
+}
+
+.entryaction {
+ margin-left: auto;
+ display: flex !important;
+ align-items: center;
+}
+
+.entryaction i {
+ margin-right: 8px;
+}
+
+.entryaction .spinner-grow {
+ height: 1rem;
+ width: 1rem;
+ margin-right: 8px;
+}
diff --git a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.test.tsx b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.test.tsx
new file mode 100644
index 0000000000..896c61e5e1
--- /dev/null
+++ b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.test.tsx
@@ -0,0 +1,60 @@
+import React from 'react';
+import { render } from '@testing-library/react';
+
+import {
+ ApolloClient,
+ ApolloProvider,
+ InMemoryCache,
+ ApolloLink,
+ HttpLink,
+} from '@apollo/client';
+
+import type { NormalizedCacheObject } from '@apollo/client';
+import { BrowserRouter } from 'react-router-dom';
+import AdvertisementEntry from './AdvertisementEntry';
+import { Provider } from 'react-redux';
+import { store } from 'state/store';
+import { BACKEND_URL } from 'Constant/constant';
+import i18nForTest from 'utils/i18nForTest';
+import { I18nextProvider } from 'react-i18next';
+
+const httpLink = new HttpLink({
+ uri: BACKEND_URL,
+ headers: {
+ authorization: 'Bearer ' + localStorage.getItem('token') || '',
+ },
+});
+
+const client: ApolloClient = new ApolloClient({
+ cache: new InMemoryCache(),
+ link: ApolloLink.from([httpLink]),
+});
+describe('Testing Advertisement Entry Component', () => {
+ test('Temporary test for Advertisement Entry', () => {
+ const { getByTestId, getAllByText } = render(
+
+
+
+
+ {
+
+ }
+
+
+
+
+ );
+ expect(getByTestId('AdEntry')).toBeInTheDocument();
+ expect(getAllByText('POPUP')[0]).toBeInTheDocument();
+ expect(getAllByText('Advert1')[0]).toBeInTheDocument();
+ });
+});
diff --git a/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.tsx b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.tsx
new file mode 100644
index 0000000000..36d99004fc
--- /dev/null
+++ b/src/components/Advertisements/core/AdvertisementEntry/AdvertisementEntry.tsx
@@ -0,0 +1,103 @@
+import React, { useState } from 'react';
+import PropTypes from 'prop-types';
+import styles from './AdvertisementEntry.module.css';
+import { Button, Card, Col, Row, Spinner } from 'react-bootstrap';
+import { DELETE_ADVERTISEMENT_BY_ID } from 'GraphQl/Mutations/mutations';
+import { useMutation } from '@apollo/client';
+import { useTranslation } from 'react-i18next';
+interface InterfaceAddOnEntryProps {
+ id: string;
+ name: string;
+ link: string;
+ type: string;
+ orgId: string;
+ startDate: Date;
+ endDate: Date;
+}
+function advertisementEntry({
+ id,
+ name,
+ type,
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ orgId,
+ link,
+ endDate,
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ startDate,
+}: InterfaceAddOnEntryProps): JSX.Element {
+ const { t } = useTranslation('translation', { keyPrefix: 'advertisement' });
+ const [buttonLoading, setButtonLoading] = useState(false);
+ const [deleteAdById] = useMutation(DELETE_ADVERTISEMENT_BY_ID);
+
+ const onDelete = async (): Promise => {
+ setButtonLoading(true);
+ await deleteAdById({
+ variables: {
+ id: id.toString(),
+ },
+ });
+ setButtonLoading(false);
+ };
+ return (
+ <>
+
+ {Array.from({ length: 4 }).map((_, idx) => (
+
+
+
+
+ {name}
+ Ends on {endDate?.toDateString()}
+
+ {type}
+
+ {link}
+
+
+
+
+ ))}
+
+
+ >
+ );
+}
+
+advertisementEntry.propTypes = {
+ name: PropTypes.string,
+ type: PropTypes.string,
+ orgId: PropTypes.string,
+ link: PropTypes.string,
+ endDate: PropTypes.instanceOf(Date),
+ startDate: PropTypes.instanceOf(Date),
+};
+
+advertisementEntry.defaultProps = {
+ name: '',
+ type: '',
+ orgId: '',
+ link: '',
+ endDate: new Date(),
+ startDate: new Date(),
+};
+export default advertisementEntry;
diff --git a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.module.css b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.module.css
new file mode 100644
index 0000000000..c122d386fa
--- /dev/null
+++ b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.module.css
@@ -0,0 +1,9 @@
+.modalbtn {
+ display: flex !important;
+ margin-left: auto;
+ align-items: center;
+}
+
+.modalbtn i {
+ margin-right: 8px;
+}
diff --git a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.tsx b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.tsx
new file mode 100644
index 0000000000..e205d50598
--- /dev/null
+++ b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.tsx
@@ -0,0 +1,207 @@
+import React, { useState } from 'react';
+import PropTypes from 'prop-types';
+import styles from './AdvertisementRegister.module.css';
+import { Button, Form, Modal } from 'react-bootstrap';
+import { useMutation } from '@apollo/client';
+import { ADD_ADVERTISEMENT_MUTATION } from 'GraphQl/Mutations/mutations';
+import { useTranslation } from 'react-i18next';
+import { toast } from 'react-toastify';
+import dayjs from 'dayjs';
+
+interface InterfaceAddOnRegisterProps {
+ id?: string; // OrgId
+ createdBy?: string; // User
+}
+interface InterfaceFormStateTypes {
+ name: string;
+ link: string;
+ type: string;
+ startDate: Date;
+ endDate: Date;
+ orgId: string;
+}
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+function advertisementRegister({
+ /* eslint-disable-next-line @typescript-eslint/no-unused-vars */
+ createdBy,
+}: InterfaceAddOnRegisterProps): JSX.Element {
+ const { t } = useTranslation('translation', { keyPrefix: 'advertisement' });
+
+ const [show, setShow] = useState(false);
+
+ const handleClose = (): void => setShow(false);
+ const handleShow = (): void => setShow(true);
+ const [create] = useMutation(ADD_ADVERTISEMENT_MUTATION);
+
+ //getting orgId from URL
+ const currentOrg = window.location.href.split('/id=')[1] + '';
+ const [formState, setFormState] = useState({
+ name: '',
+ link: '',
+ type: 'BANNER',
+ startDate: new Date(),
+ endDate: new Date(),
+ orgId: currentOrg,
+ });
+ const handleRegister = async (): Promise => {
+ try {
+ console.log('At handle register', formState);
+ const { data } = await create({
+ variables: {
+ orgId: currentOrg,
+ name: formState.name as string,
+ link: formState.link as string,
+ type: formState.type as string,
+ startDate: dayjs(formState.startDate).format('YYYY-MM-DD'),
+ endDate: dayjs(formState.endDate).format('YYYY-MM-DD'),
+ },
+ });
+
+ if (data) {
+ toast.success('Advertisement created successfully');
+ setTimeout(() => {
+ window.location.reload();
+ }, 2000);
+ }
+ } catch (error) {
+ console.log('error occured', error);
+ }
+ };
+ return (
+ <>
+
+
+
+
+ {t('RClose')}
+
+
+
+ {t('Rname')}
+ {
+ setFormState({
+ ...formState,
+ name: e.target.value,
+ });
+ }}
+ />
+
+
+ {t('Rlink')}
+ {
+ setFormState({
+ ...formState,
+ link: e.target.value,
+ });
+ }}
+ />
+
+
+ {t('Rtype')}
+ {
+ setFormState({
+ ...formState,
+ type: e.target.value,
+ });
+ console.log(e.target, e.target.value, typeof e.target.value);
+ }}
+ >
+
+
+
+
+
+
+ {t('RstartDate')}
+ {
+ setFormState({
+ ...formState,
+ startDate: new Date(e.target.value),
+ });
+ }}
+ />
+
+
+
+ {t('RendDate')}
+ {
+ setFormState({
+ ...formState,
+ endDate: new Date(e.target.value),
+ });
+ }}
+ />
+
+
+
+
+
+
+
+
+ >
+ );
+}
+
+advertisementRegister.defaultProps = {
+ name: '',
+ link: '',
+ type: 'BANNER',
+ startDate: new Date(),
+ endDate: new Date(),
+ orgId: '',
+};
+
+advertisementRegister.propTypes = {
+ name: PropTypes.string,
+ link: PropTypes.string,
+ type: PropTypes.string,
+ startDate: PropTypes.instanceOf(Date),
+ endDate: PropTypes.instanceOf(Date),
+ orgId: PropTypes.string,
+};
+
+export default advertisementRegister;
diff --git a/src/components/IconComponent/IconComponent.tsx b/src/components/IconComponent/IconComponent.tsx
index 8504b13d2a..4c490c9c94 100644
--- a/src/components/IconComponent/IconComponent.tsx
+++ b/src/components/IconComponent/IconComponent.tsx
@@ -88,6 +88,8 @@ const iconComponent = (props: InterfaceIconComponent): JSX.Element => {
stroke={props.fill}
/>
);
+ case 'Advertisement':
+ return ;
default:
return (
state.appRoutes);
const { targets, configUrl } = appRoutes;
-
return (
<>
+
+
+
+
+ {'Promoted Content'}
+
+
+
+ {props.title}
+ {props.title}
+ {props.image && (
+
+ )}
+
+
+ >
+ );
+}
diff --git a/src/screens/UserPortal/Home/Home.tsx b/src/screens/UserPortal/Home/Home.tsx
index b657fc0c02..ad02e1b26c 100644
--- a/src/screens/UserPortal/Home/Home.tsx
+++ b/src/screens/UserPortal/Home/Home.tsx
@@ -11,13 +11,17 @@ import getOrganizationId from 'utils/getOrganizationId';
import SendIcon from '@mui/icons-material/Send';
import PostCard from 'components/UserPortal/PostCard/PostCard';
import { useMutation, useQuery } from '@apollo/client';
-import { ORGANIZATION_POST_CONNECTION_LIST } from 'GraphQl/Queries/Queries';
+import {
+ ADVERTISEMENTS_GET,
+ ORGANIZATION_POST_CONNECTION_LIST,
+} from 'GraphQl/Queries/Queries';
import { CREATE_POST_MUTATION } from 'GraphQl/Mutations/mutations';
import { errorHandler } from 'utils/errorHandler';
import { useTranslation } from 'react-i18next';
import convertToBase64 from 'utils/convertToBase64';
import { toast } from 'react-toastify';
import HourglassBottomIcon from '@mui/icons-material/HourglassBottom';
+import PromotedPost from 'components/UserPortal/PromotedPost/PromotedPost';
interface InterfacePostCardProps {
id: string;
@@ -60,11 +64,19 @@ export default function home(): JSX.Element {
const [posts, setPosts] = React.useState([]);
const [postContent, setPostContent] = React.useState('');
const [postImage, setPostImage] = React.useState('');
+ const currentOrgId = window.location.href.split('/id=')[1] + '';
+ const [adContent, setAdContent] = React.useState([]);
const navbarProps = {
currentPage: 'home',
};
-
+ const {
+ data: promotedPostsData,
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ refetch: _promotedPostsRefetch,
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
+ loading: promotedPostsLoading,
+ } = useQuery(ADVERTISEMENTS_GET);
const {
data,
refetch,
@@ -116,6 +128,12 @@ export default function home(): JSX.Element {
}
}, [data]);
+ React.useEffect(() => {
+ if (promotedPostsData) {
+ setAdContent(promotedPostsData.getAdvertisements);
+ }
+ }, [data]);
+
return (
<>
@@ -184,6 +202,21 @@ export default function home(): JSX.Element {
+ {adContent
+ .filter((ad: any) => ad.orgId == currentOrgId)
+ .filter((ad: any) => new Date(ad.endDate) > new Date()).length == 0
+ ? ''
+ : adContent
+ .filter((ad: any) => ad.orgId == currentOrgId)
+ .filter((ad: any) => new Date(ad.endDate) > new Date())
+ .map((post: any) => (
+
+ ))}
{loadingPosts ? (
Loading...
diff --git a/src/state/reducers/routesReducer.test.ts b/src/state/reducers/routesReducer.test.ts
index 89743a8508..765920e6f3 100644
--- a/src/state/reducers/routesReducer.test.ts
+++ b/src/state/reducers/routesReducer.test.ts
@@ -18,6 +18,7 @@ describe('Testing Routes reducer', () => {
name: 'Block/Unblock',
url: '/blockuser/id=undefined',
},
+ { name: 'Advertisement', url: '/orgads/id=undefined' },
{
name: 'Plugins',
subTargets: [
@@ -50,6 +51,11 @@ describe('Testing Routes reducer', () => {
},
{ name: 'Posts', comp_id: 'orgpost', component: 'OrgPost' },
{ name: 'Block/Unblock', comp_id: 'blockuser', component: 'BlockUser' },
+ {
+ name: 'Advertisement',
+ comp_id: 'orgads',
+ component: 'Advertisements',
+ },
{
name: 'Plugins',
comp_id: null,
@@ -83,6 +89,7 @@ describe('Testing Routes reducer', () => {
{ name: 'Events', url: '/orgevents/id=undefined' },
{ name: 'Posts', url: '/orgpost/id=undefined' },
{ name: 'Block/Unblock', url: '/blockuser/id=undefined' },
+ { name: 'Advertisement', url: '/orgads/id=undefined' },
{
name: 'Plugins',
subTargets: [
@@ -116,6 +123,11 @@ describe('Testing Routes reducer', () => {
},
{ name: 'Posts', comp_id: 'orgpost', component: 'OrgPost' },
{ name: 'Block/Unblock', comp_id: 'blockuser', component: 'BlockUser' },
+ {
+ name: 'Advertisement',
+ comp_id: 'orgads',
+ component: 'Advertisements',
+ },
{
name: 'Plugins',
comp_id: null,
@@ -152,6 +164,7 @@ describe('Testing Routes reducer', () => {
name: 'Block/Unblock',
url: '/blockuser/id=undefined',
},
+ { name: 'Advertisement', url: '/orgads/id=undefined' },
{ name: 'Settings', url: '/orgsetting/id=undefined' },
{ name: 'All Organizations', url: '/orglist/id=undefined' },
{
@@ -185,8 +198,14 @@ describe('Testing Routes reducer', () => {
comp_id: 'orgevents',
component: 'OrganizationEvents',
},
+
{ name: 'Posts', comp_id: 'orgpost', component: 'OrgPost' },
{ name: 'Block/Unblock', comp_id: 'blockuser', component: 'BlockUser' },
+ {
+ name: 'Advertisement',
+ comp_id: 'orgads',
+ component: 'Advertisements',
+ },
{
name: 'Plugins',
comp_id: null,
diff --git a/src/state/reducers/routesReducer.ts b/src/state/reducers/routesReducer.ts
index d0d5a7ab26..4fafbd1ebb 100644
--- a/src/state/reducers/routesReducer.ts
+++ b/src/state/reducers/routesReducer.ts
@@ -68,6 +68,7 @@ const components: ComponentType[] = [
{ name: 'Events', comp_id: 'orgevents', component: 'OrganizationEvents' },
{ name: 'Posts', comp_id: 'orgpost', component: 'OrgPost' },
{ name: 'Block/Unblock', comp_id: 'blockuser', component: 'BlockUser' },
+ { name: 'Advertisement', comp_id: 'orgads', component: 'Advertisements' },
{
name: 'Plugins',
comp_id: null,
@@ -81,6 +82,7 @@ const components: ComponentType[] = [
},
],
},
+
{ name: 'Settings', comp_id: 'orgsetting', component: 'OrgSettings' },
{ name: 'All Organizations', comp_id: 'orglist', component: 'OrgList' },
{ name: '', comp_id: 'member', component: 'MemberDetail' },