From f30baa5d2b16d6d7106c1533d2e2cb8e557f0207 Mon Sep 17 00:00:00 2001 From: Peter Harrison <16875803+palisadoes@users.noreply.github.com> Date: Sun, 5 Jan 2025 21:56:27 -0800 Subject: [PATCH] Merge the latest develop-postgres to develop for Cloud instance (#3183) * 20250105213148 Deleted all files in the develop branch in anticipation of merging develop-postgres into develop cleanly * 20250105213246 Merge develop-postgres into develop --- .eslintrc.json | 8 - .github/dependabot.yaml | 2 +- .github/workflows/auto-label.json5 | 14 +- .github/workflows/merge-conflict-check.yml | 65 + .github/workflows/pull-request.yml | 87 +- .github/workflows/push-deploy-website.yml | 6 +- .github/workflows/scripts/app_health_check.sh | 75 + .../code_coverage_disable_check.py | 0 .../{ => scripts}/compare_translations.py | 0 .github/workflows/{ => scripts}/countline.py | 0 .../{ => scripts}/eslint_disable_check.py | 0 .../talawa_admin_md_mdx_format_adjuster.py | 0 .../workflows/scripts/validate-coderabbit.sh | 38 + .github/workflows/stale.yml | 5 +- .husky/post-merge | 0 .husky/pre-commit | 0 3141 | 0 CODEOWNERS | 2 +- docs/README.md | 16 +- docs/blog/2019-05-28-first-blog-post.md | 12 - docs/blog/2019-05-29-long-blog-post.md | 44 - docs/blog/2021-08-01-mdx-blog-post.mdx | 24 - .../docusaurus-plushie-banner.jpeg | Bin 96122 -> 0 bytes docs/blog/2021-08-26-welcome/index.md | 29 - docs/blog/authors.yml | 23 - docs/blog/tags.yml | 19 - docs/docusaurus.config.ts | 193 +- docs/src/css/custom.css | 437 +++- docs/src/pages/index.tsx | 10 +- docs/static/img/icons/facebook.svg | 3 + docs/static/img/icons/favicon_palisadoes.ico | Bin 0 -> 870 bytes docs/static/img/icons/github-dark.svg | 1 + docs/static/img/icons/github.svg | 1 + docs/static/img/icons/instagram.svg | 3 + docs/static/img/icons/opportunities.svg | 6 + docs/static/img/icons/slack.svg | 3 + docs/static/img/icons/source.svg | 4 + docs/static/img/icons/team.svg | 3 + docs/static/img/icons/twitter.svg | 1 + docs/static/img/icons/youtube-white.svg | 3 + docs/static/img/icons/youtube.svg | 1 + package-lock.json | 200 +- package.json | 10 +- scripts/githooks/check-localstorage-usage.js | 4 +- src/App.tsx | 44 +- src/GraphQl/Queries/AgendaCategoryQueries.ts | 10 +- src/assets/svgs/agenda-items.svg | 2 +- .../AddOn/core/AddOnEntry/AddOnEntry.tsx | 13 +- .../core/AddOnStore/AddOnStore.module.css | 72 - .../AddOn/core/AddOnStore/AddOnStore.spec.tsx | 238 +- .../AddOn/core/AddOnStore/AddOnStore.tsx | 35 +- ...ToTag.test.tsx => AddPeopleToTag.spec.tsx} | 43 +- .../Advertisements/Advertisements.module.css | 47 - .../Advertisements/Advertisements.tsx | 27 +- .../AdvertisementRegister.module.css | 57 - .../AdvertisementRegister.tsx | 9 +- .../AgendaCategoryContainer.tsx | 6 +- .../AgendaItemsContainer.module.css | 230 -- .../AgendaItems/AgendaItemsContainer.tsx | 4 +- .../AgendaItems/AgendaItemsCreateModal.tsx | 8 +- .../AgendaItems/AgendaItemsDeleteModal.tsx | 2 +- .../AgendaItems/AgendaItemsPreviewModal.tsx | 4 +- .../AgendaItems/AgendaItemsUpdateModal.tsx | 8 +- ...test.tsx => CurrentHourIndicator.spec.tsx} | 1 + .../EventCalendar/EventCalendar.module.css | 572 ----- .../EventCalendar/EventCalendar.tsx | 6 +- src/components/EventCalendar/EventHeader.tsx | 15 +- .../YearlyEventCalender.module.css | 354 --- .../EventCalendar/YearlyEventCalender.tsx | 16 +- .../EventListCard/EventListCard.module.css | 223 -- .../EventListCard/EventListCard.tsx | 6 +- .../EventListCard/EventListCardModals.tsx | 26 +- .../EventAgendaItems.spec.tsx | 12 +- .../EventAttendance/EventAttendance.tsx | 4 +- .../EventRegistrant/EventRegistrants.tsx | 18 +- .../AddOnSpotAttendee.spec.tsx | 88 +- ...eftDrawer.test.tsx => LeftDrawer.spec.tsx} | 25 +- .../LeftDrawerOrg/LeftDrawerOrg.module.css | 362 --- .../LeftDrawerOrg/LeftDrawerOrg.tsx | 35 +- .../OrgPeopleListCard.spec.tsx | 183 +- .../OrgPeopleListCard/OrgPeopleListCard.tsx | 2 - .../OrgPostCard/DeletePostModal.spec.tsx | 77 + .../OrgPostCard/DeletePostModal.tsx | 65 + .../OrgPostCard/OrgPostCard.module.css | 278 --- src/components/OrgPostCard/OrgPostCard.tsx | 191 +- .../ActionItemCategories/CategoryModal.tsx | 2 +- .../OrgActionItemCategories.module.css | 138 -- .../OrgActionItemCategories.tsx | 14 +- .../AgendaCategoryCreateModal.tsx | 9 +- .../AgendaCategoryDeleteModal.tsx | 4 +- .../AgendaCategoryPreviewModal.tsx | 8 +- .../AgendaCategoryUpdateModal.tsx | 8 +- .../OrganizationAgendaCategory.module.css | 171 -- .../OrganizationAgendaCategory.spec.tsx | 228 +- .../OrganizationAgendaCategory.tsx | 63 +- .../OrganizationAgendaCategoryErrorMocks.ts | 14 +- .../OrganizationAgendaCategoryMocks.ts | 34 +- .../ProfileDropdown/ProfileDropdown.spec.tsx | 37 +- .../ProfileDropdown/ProfileDropdown.tsx | 6 +- ...leLoader.test.tsx => TableLoader.spec.tsx} | 3 +- src/components/TagActions/TagNode.spec.tsx | 266 +++ src/components/TagActions/TagNode.tsx | 1 + src/components/TagActions/TagNodeMocks.ts | 75 + .../UpdateSession/UpdateSession.css | 96 - .../UpdateSession/UpdateSession.spec.tsx | 288 ++- .../UpdateSession/UpdateSession.tsx | 28 +- .../UserListCard/UserListCard.module.css | 74 - src/components/UserListCard/UserListCard.tsx | 7 +- .../UserPasswordUpdate.module.css | 97 - .../UserPasswordUpdate/UserPasswordUpdate.tsx | 8 +- .../UserPortal/ChatRoom/ChatRoom.spec.tsx | 2 +- .../CommentCard/CommentCard.spec.tsx | 345 +++ .../UserPortal/CommentCard/CommentCard.tsx | 9 +- .../CreateGroupChat/CreateGroupChat.spec.tsx | 556 ++++- .../CreateGroupChat/CreateGroupChat.tsx | 2 +- .../OrganizationNavbar.spec.tsx | 95 + .../OrganizationNavbar/OrganizationNavbar.tsx | 8 +- .../OrganizationSidebar.spec.tsx | 59 + .../OrganizationSidebar.tsx | 2 - .../SecuredRouteForUser.spec.tsx | 212 +- .../StartPostModal/StartPostModal.spec.tsx | 139 +- .../StartPostModal/StartPostModal.tsx | 3 +- .../UserPortal/UserNavbar/UserNavbar.spec.tsx | 27 +- src/components/Venues/VenueModal.module.css | 53 - src/components/Venues/VenueModal.tsx | 2 +- src/screens/BlockUser/BlockUser.spec.tsx | 114 +- src/screens/BlockUser/BlockUser.tsx | 4 - ...ile.test.tsx => CommunityProfile.spec.tsx} | 14 +- .../VolunteerGroupViewModal.tsx | 2 +- .../Volunteers/VolunteerViewModal.tsx | 62 +- ...sword.test.tsx => ForgotPassword.spec.tsx} | 63 +- src/screens/ForgotPassword/ForgotPassword.tsx | 3 +- src/screens/ManageTag/ManageTag.tsx | 2 +- src/screens/OrgList/OrgList.tsx | 1 - src/screens/OrgSettings/OrgSettings.spec.tsx | 44 +- src/screens/OrgSettings/OrgSettings.tsx | 6 +- .../ItemModal.spec.tsx | 24 + .../OrganizationActionItems/ItemModal.tsx | 7 +- .../testObject.mocks.ts | 51 + ...s.test.tsx => OrganizationEvents.spec.tsx} | 42 +- .../OrganizationFunds/OrganizationFunds.tsx | 4 +- src/screens/OrganizationPeople/AddMember.tsx | 12 +- .../OrganizationPeople.spec.tsx | 740 +++++- .../OrganizationPeople/OrganizationPeople.tsx | 1 - ...ags.test.tsx => OrganizationTags.spec.tsx} | 22 +- .../OrganizationTags/OrganizationTags.tsx | 12 +- .../OrganizationTags/OrganizationTagsMocks.ts | 12 +- .../OrganizationVenues.spec.tsx | 111 + .../OrganizationVenues/OrganizationVenues.tsx | 2 - src/screens/Requests/Requests.tsx | 1 - src/screens/UserPortal/Chat/Chat.spec.tsx | 140 +- src/screens/UserPortal/Chat/Chat.tsx | 27 +- src/screens/UserPortal/Donate/Donate.spec.tsx | 563 ++++- src/screens/UserPortal/Donate/Donate.tsx | 20 +- ...on.test.tsx => LeaveOrganization.spec.tsx} | 55 +- src/screens/UserPortal/People/People.spec.tsx | 1 + src/screens/UserPortal/People/People.tsx | 72 +- ....test.tsx => VolunteerManagement.spec.tsx} | 35 +- .../Volunteer/VolunteerManagement.tsx | 5 +- ...Url.test.ts => askForTalawaApiUrl.spec.ts} | 23 +- src/style/app.module.css | 2124 +++++++++++++++-- 161 files changed, 8046 insertions(+), 4338 deletions(-) create mode 100644 .github/workflows/merge-conflict-check.yml create mode 100644 .github/workflows/scripts/app_health_check.sh rename .github/workflows/{ => scripts}/code_coverage_disable_check.py (100%) rename .github/workflows/{ => scripts}/compare_translations.py (100%) rename .github/workflows/{ => scripts}/countline.py (100%) mode change 100644 => 100755 rename .github/workflows/{ => scripts}/eslint_disable_check.py (100%) rename .github/workflows/{ => scripts}/talawa_admin_md_mdx_format_adjuster.py (100%) create mode 100644 .github/workflows/scripts/validate-coderabbit.sh mode change 100644 => 100755 .husky/post-merge mode change 100644 => 100755 .husky/pre-commit create mode 100644 3141 delete mode 100644 docs/blog/2019-05-28-first-blog-post.md delete mode 100644 docs/blog/2019-05-29-long-blog-post.md delete mode 100644 docs/blog/2021-08-01-mdx-blog-post.mdx delete mode 100644 docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg delete mode 100644 docs/blog/2021-08-26-welcome/index.md delete mode 100644 docs/blog/authors.yml delete mode 100644 docs/blog/tags.yml create mode 100644 docs/static/img/icons/facebook.svg create mode 100644 docs/static/img/icons/favicon_palisadoes.ico create mode 100644 docs/static/img/icons/github-dark.svg create mode 100644 docs/static/img/icons/github.svg create mode 100644 docs/static/img/icons/instagram.svg create mode 100644 docs/static/img/icons/opportunities.svg create mode 100644 docs/static/img/icons/slack.svg create mode 100644 docs/static/img/icons/source.svg create mode 100644 docs/static/img/icons/team.svg create mode 100644 docs/static/img/icons/twitter.svg create mode 100644 docs/static/img/icons/youtube-white.svg create mode 100644 docs/static/img/icons/youtube.svg mode change 100644 => 100755 scripts/githooks/check-localstorage-usage.js delete mode 100644 src/components/AddOn/core/AddOnStore/AddOnStore.module.css rename src/components/AddPeopleToTag/{AddPeopleToTag.test.tsx => AddPeopleToTag.spec.tsx} (86%) delete mode 100644 src/components/Advertisements/Advertisements.module.css delete mode 100644 src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.module.css delete mode 100644 src/components/AgendaItems/AgendaItemsContainer.module.css rename src/components/CurrentHourIndicator/{CurrentHourIndicator.test.tsx => CurrentHourIndicator.spec.tsx} (88%) delete mode 100644 src/components/EventCalendar/EventCalendar.module.css delete mode 100644 src/components/EventCalendar/YearlyEventCalender.module.css delete mode 100644 src/components/EventListCard/EventListCard.module.css rename src/components/LeftDrawer/{LeftDrawer.test.tsx => LeftDrawer.spec.tsx} (90%) delete mode 100644 src/components/LeftDrawerOrg/LeftDrawerOrg.module.css create mode 100644 src/components/OrgPostCard/DeletePostModal.spec.tsx create mode 100644 src/components/OrgPostCard/DeletePostModal.tsx delete mode 100644 src/components/OrgPostCard/OrgPostCard.module.css delete mode 100644 src/components/OrgSettings/ActionItemCategories/OrgActionItemCategories.module.css delete mode 100644 src/components/OrgSettings/AgendaItemCategories/OrganizationAgendaCategory.module.css rename src/components/TableLoader/{TableLoader.test.tsx => TableLoader.spec.tsx} (97%) create mode 100644 src/components/TagActions/TagNode.spec.tsx create mode 100644 src/components/TagActions/TagNodeMocks.ts delete mode 100644 src/components/UpdateSession/UpdateSession.css delete mode 100644 src/components/UserListCard/UserListCard.module.css delete mode 100644 src/components/UserPasswordUpdate/UserPasswordUpdate.module.css delete mode 100644 src/components/Venues/VenueModal.module.css rename src/screens/CommunityProfile/{CommunityProfile.test.tsx => CommunityProfile.spec.tsx} (98%) rename src/screens/ForgotPassword/{ForgotPassword.test.tsx => ForgotPassword.spec.tsx} (85%) rename src/screens/OrganizationEvents/{OrganizationEvents.test.tsx => OrganizationEvents.spec.tsx} (93%) rename src/screens/OrganizationTags/{OrganizationTags.test.tsx => OrganizationTags.spec.tsx} (96%) rename src/screens/UserPortal/LeaveOrganization/{LeaveOrganization.test.tsx => LeaveOrganization.spec.tsx} (93%) rename src/screens/UserPortal/Volunteer/{VolunteerManagement.test.tsx => VolunteerManagement.spec.tsx} (78%) rename src/setup/askForTalawaApiUrl/{askForTalawaApiUrl.test.ts => askForTalawaApiUrl.spec.ts} (63%) diff --git a/.eslintrc.json b/.eslintrc.json index 9ac9fa1c39..de93fb465f 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -153,13 +153,5 @@ "docs/sidebars.ts", "docs/src/**", "docs/blog/**" - ], - "overrides": [ - { - "files": ["*.js", "*.jsx"], - "rules": { - "@typescript-eslint/explicit-function-return-type": "off" - } - } ] } diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index 9a3e9a54e9..81d68df4bd 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -12,7 +12,7 @@ updates: labels: - "dependencies" # Specify the target branch for PRs - target-branch: "develop" + target-branch: "develop-postgres" # Customize commit message prefix commit-message: prefix: "chore(deps):" diff --git a/.github/workflows/auto-label.json5 b/.github/workflows/auto-label.json5 index 86bbddf033..37929ea97b 100644 --- a/.github/workflows/auto-label.json5 +++ b/.github/workflows/auto-label.json5 @@ -1,8 +1,8 @@ -{ - "labelsSynonyms": { - "dependencies": ["dependabot", "dependency", "dependencies"], - "security": ["security"], - "ui/ux": ["layout", "screen", "design", "figma"] - }, - "defaultLabels": ["unapproved"], +{ + "labelsSynonyms": { + "dependencies": ["dependabot", "dependency", "dependencies"], + "security": ["security"], + "ui/ux": ["layout", "screen", "design", "figma"] + }, + "defaultLabels": ["unapproved"], } \ No newline at end of file diff --git a/.github/workflows/merge-conflict-check.yml b/.github/workflows/merge-conflict-check.yml new file mode 100644 index 0000000000..5b7d939ae6 --- /dev/null +++ b/.github/workflows/merge-conflict-check.yml @@ -0,0 +1,65 @@ +name: Merge Conflict Check Workflow + +on: + pull_request: + branches: + - '**' + types: + - opened + - reopened + - synchronize + - ready_for_review + +jobs: + Merge-Conflict-Check: + name: Check for Merge Conflicts + runs-on: ubuntu-latest + steps: + - name: Checkout Code + uses: actions/checkout@v4 + + - name: Check Mergeable Status via Github API + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + PR_NUMBER=${{ github.event.pull_request.number }} + max_retries=3 + retry_delay=5 + + for ((i=1; i<=max_retries; i++)); do + echo "Attempt $i of $max_retries" + + if ! response=$(gh api "repos/${{ github.repository }}/pulls/$PR_NUMBER" --jq '.mergeable'); then + if [[ $response == *"rate limit exceeded"* ]]; then + echo "Rate limit exceeded. Waiting before retry..." + sleep 60 # Wait longer for rate limit + else + echo "Failed to call GitHub API: $response" + if [ $i -eq $max_retries ]; then + echo "Maximum retries reached. Exiting." + exit 1 + fi + sleep $retry_delay + fi + continue + fi + + case "$response" in + "true") + echo "No conflicts detected." + exit 0 + ;; + "false") + echo "Merge conflicts detected." + exit 1 + ;; + *) + echo "Mergeable status unknown: $response" + if [ $i -eq $max_retries ]; then + echo "Maximum retries reached. Exiting." + exit 1 + fi + sleep $retry_delay + ;; + esac + done diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 6891cd50af..f387698bce 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -37,8 +37,8 @@ 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 src/screens/OrgList/OrgList.tsx src/GraphQl/Mutations/mutations.ts src/components/EventListCard/EventListCardModals.tsx src/components/TagActions/TagActionsMocks.ts src/utils/interfaces.ts src/screens/MemberDetail/MemberDetail.tsx + chmod +x ./.github/workflows/scripts/countline.py + ./.github/workflows/scripts/countline.py --lines 600 --exclude_files src/screens/LoginPage/LoginPage.tsx src/GraphQl/Queries/Queries.ts src/screens/OrgList/OrgList.tsx src/GraphQl/Mutations/mutations.ts src/components/EventListCard/EventListCardModals.tsx src/components/TagActions/TagActionsMocks.ts src/utils/interfaces.ts src/screens/MemberDetail/MemberDetail.tsx - name: Get changed TypeScript files id: changed-files @@ -71,8 +71,8 @@ jobs: - name: Compare translation files run: | - chmod +x .github/workflows/compare_translations.py - python .github/workflows/compare_translations.py --directory public/locales + chmod +x .github/workflows/scripts/compare_translations.py + python .github/workflows/scripts/compare_translations.py --directory public/locales - name: Check if the source and target branches are different if: ${{ github.event.pull_request.base.ref == github.event.pull_request.head.ref }} @@ -97,6 +97,8 @@ jobs: with: files: | .env* + vitest.config.js + src/App.tsx .github/** env.example .node-version @@ -112,7 +114,6 @@ jobs: .eslintignore .prettierrc .prettierignore - .nojekyll vite.config.ts docker-compose.yaml Dockerfile @@ -134,6 +135,11 @@ jobs: *.password *.secret *.credentials + .nojekyll + yarn.lock + docs/docusaurus.config.ts + docs/sidebar* + CNAME - name: List all changed unauthorized files if: steps.changed-unauth-files.outputs.any_changed == 'true' || steps.changed-unauth-files.outputs.any_deleted == 'true' @@ -193,7 +199,7 @@ jobs: - name: Run Python script run: | - python .github/workflows/eslint_disable_check.py --files ${{ steps.changed-files.outputs.all_changed_files }} + python .github/workflows/scripts/eslint_disable_check.py --files ${{ steps.changed-files.outputs.all_changed_files }} Check-Code-Coverage-Disable: name: Check for code coverage disable @@ -213,7 +219,7 @@ jobs: - name: Run Python script run: | - python .github/workflows/code_coverage_disable_check.py --files ${{ steps.changed-files.outputs.all_changed_files }} + python .github/workflows/scripts/code_coverage_disable_check.py --files ${{ steps.changed-files.outputs.all_changed_files }} Test-Application: name: Test Application @@ -336,20 +342,8 @@ jobs: echo $! > .pidfile_prod - name: Check if Production App is running run: | - timeout=120 - echo "Starting production health check with ${timeout}s timeout" - while ! nc -z localhost 4173 && [ $timeout -gt 0 ]; do - sleep 1 - timeout=$((timeout-1)) - if [ $((timeout % 10)) -eq 0 ]; then - echo "Still waiting for production app to start... ${timeout}s remaining" - fi - done - if [ $timeout -eq 0 ]; then - echo "Timeout waiting for production application to start" - exit 1 - fi - echo "Production app started successfully" + chmod +x .github/workflows/scripts/app_health_check.sh + .github/workflows/scripts/app_health_check.sh 4173 120 - name: Stop Production App run: | if [ -f .pidfile_prod ]; then @@ -361,20 +355,8 @@ jobs: echo $! > .pidfile_dev - name: Check if Development App is running run: | - timeout=120 - echo "Starting development health check with ${timeout}s timeout" - while ! nc -z localhost 4321 && [ $timeout -gt 0 ]; do - sleep 1 - timeout=$((timeout-1)) - if [ $((timeout % 10)) -eq 0 ]; then - echo "Still waiting for development app to start... ${timeout}s remaining" - fi - done - if [ $timeout -eq 0 ]; then - echo "Timeout waiting for development application to start" - exit 1 - fi - echo "Development app started successfully" + chmod +x .github/workflows/scripts/app_health_check.sh + .github/workflows/scripts/app_health_check.sh 4321 120 - name: Stop Development App if: always() run: | @@ -410,22 +392,8 @@ jobs: echo "Docker container started successfully" - name: Check if Talawa Admin App is running run: | - timeout="${HEALTH_CHECK_TIMEOUT:-120}" - echo "Starting health check with ${timeout}s timeout" - while ! nc -z localhost 4321 && [ $timeout -gt 0 ]; do - sleep 1 - timeout=$((timeout-1)) - if [ $((timeout % 10)) -eq 0 ]; then - echo "Still waiting for app to start... ${timeout}s remaining" - fi - done - if [ $timeout -eq 0 ]; then - echo "Timeout waiting for application to start" - echo "Container logs:" - docker logs talawa-admin-app-container - exit 1 - fi - echo "Port check passed, verifying health endpoint..." + chmod +x .github/workflows/scripts/app_health_check.sh + .github/workflows/scripts/app_health_check.sh 4321 120 true - name: Stop Docker Container if: always() run: | @@ -464,3 +432,20 @@ jobs: echo "Error: Pull request target branch must be 'develop-postgres'. Please refer PR_GUIDELINES.md" echo "Error: Close this PR and try again." exit 1 + + Validate-Coderabbit: + name: Validate CodeRabbit Approval + runs-on: ubuntu-latest + if: github.actor != 'dependabot[bot]' + needs: [Test-Docusaurus-Deployment] + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + - name: Validate CodeRabbit.ai Approval + run: | + chmod +x $GITHUB_WORKSPACE/.github/workflows/scripts/validate-coderabbit.sh + $GITHUB_WORKSPACE/.github/workflows/scripts/validate-coderabbit.sh + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + GITHUB_REPOSITORY: ${{ github.repository }} diff --git a/.github/workflows/push-deploy-website.yml b/.github/workflows/push-deploy-website.yml index 959f9f8feb..e03dab9840 100644 --- a/.github/workflows/push-deploy-website.yml +++ b/.github/workflows/push-deploy-website.yml @@ -14,7 +14,7 @@ name: PUSH Workflow - Website Deployment on: push: branches: - - 'develop' + - 'develop-postgres' env: CODECOV_UNIQUE_NAME: CODECOV_UNIQUE_NAME-${{ github.run_id }}-${{ github.run_number }} @@ -23,7 +23,7 @@ jobs: Deploy-Docusaurus: name: Deploy https://docs-admin.talawa.io website runs-on: ubuntu-latest - # Run only if the develop branch and not dependabot + # Run only if the develop-postgres branch and not dependabot if: ${{ github.actor != 'dependabot[bot]' }} environment: # This "name" has to be the repos' branch that contains @@ -32,7 +32,7 @@ jobs: # "Code and automation > Environments > gigithub-pages" # menu. The branch "name" must match the branch in the # "on.push.branches" section at the top of this file - name: develop + name: develop-postgres url: https://docs-admin.talawa.io steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/scripts/app_health_check.sh b/.github/workflows/scripts/app_health_check.sh new file mode 100644 index 0000000000..8d102347a0 --- /dev/null +++ b/.github/workflows/scripts/app_health_check.sh @@ -0,0 +1,75 @@ +#!/bin/bash + +# This script performs a health check to ensure an application is running on a specified port. +# The script uses netcat (nc) to check if the port is open, with a configurable timeout. +# It also includes optional logic to fetch Docker container logs if the health check fails during a Docker-based test. + +# Variables: +# port="$1" - The port to check (passed as the first argument to the script). +# timeout="${2:-120}" - The maximum time in seconds to wait for the application to start. Defaults to 120 seconds if not provided. +# is_docker_test="${3:-false}" - A flag to indicate whether the script is being run in a Docker-based test. Defaults to false. + +# Logic: +# 1. Print a message indicating the start of the health check. +# 2. Enter a loop to repeatedly check if the port is open using `nc -z localhost "${port}"`. +# - If the port is not open and the timeout has not expired, sleep for 1 second and decrement the timeout. +# - Print a status message every 10 seconds with the remaining time. +# 3. If the timeout expires, print an error message and, if in Docker test mode, fetch Docker logs for debugging. +# 4. If the port is detected as open, print a success message and exit. + +# Script: + +port="$1" +timeout="${2:-120}" +is_docker_test="${3:-false}" + + +# Validate required port parameter +if [ -z "${port}" ] || ! [[ "${port}" =~ ^[0-9]+$ ]] || [ "${port}" -lt 1 ] || [ "${port}" -gt 65535 ]; then + echo "Error: Invalid or missing port number. Must be between 1-65535" + exit 1 +fi + +# Validate timeout parameter +if ! [[ "${timeout}" =~ ^[0-9]+$ ]] || [ "${timeout}" -lt 1 ]; then + echo "Error: Invalid timeout value. Must be a positive integer" + exit 1 +fi + +# Validate is_docker_test parameter +if [ "${is_docker_test}" != "true" ] && [ "${is_docker_test}" != "false" ]; then + echo "Error: is_docker_test must be either 'true' or 'false'" + exit 1 +fi + +echo "Starting health check with ${timeout}s timeout" +while [ "${timeout}" -gt 0 ]; do + if nc -z localhost "${port}" 2>/dev/null; then + break + elif [ $? -ne 1 ]; then + echo "Error: Failed to check port ${port} (nc command failed)" + exit 1 + fi + sleep 1 + timeout=$((timeout-1)) + if [ $((timeout % 10)) -eq 0 ]; then + echo "Waiting for app to start on port ${port}... ${timeout}s remaining" + # Try to get more information about the port status + netstat -an | grep "${port}" || true + fi +done + +if [ "${timeout}" -eq 0 ]; then + echo "Error: Timeout waiting for application to start on port ${port}" + echo "System port status:" + netstat -an | grep "${port}" || true + if [ "${is_docker_test}" = "true" ]; then + echo "Fetching Docker container logs..." + if ! docker logs talawa-admin-app-container; then + echo "Error: Failed to fetch logs from container talawa-admin-app-container" + fi + fi + exit 1 +fi +echo "App started successfully on port ${port}" + diff --git a/.github/workflows/code_coverage_disable_check.py b/.github/workflows/scripts/code_coverage_disable_check.py similarity index 100% rename from .github/workflows/code_coverage_disable_check.py rename to .github/workflows/scripts/code_coverage_disable_check.py diff --git a/.github/workflows/compare_translations.py b/.github/workflows/scripts/compare_translations.py similarity index 100% rename from .github/workflows/compare_translations.py rename to .github/workflows/scripts/compare_translations.py diff --git a/.github/workflows/countline.py b/.github/workflows/scripts/countline.py old mode 100644 new mode 100755 similarity index 100% rename from .github/workflows/countline.py rename to .github/workflows/scripts/countline.py diff --git a/.github/workflows/eslint_disable_check.py b/.github/workflows/scripts/eslint_disable_check.py similarity index 100% rename from .github/workflows/eslint_disable_check.py rename to .github/workflows/scripts/eslint_disable_check.py diff --git a/.github/workflows/talawa_admin_md_mdx_format_adjuster.py b/.github/workflows/scripts/talawa_admin_md_mdx_format_adjuster.py similarity index 100% rename from .github/workflows/talawa_admin_md_mdx_format_adjuster.py rename to .github/workflows/scripts/talawa_admin_md_mdx_format_adjuster.py diff --git a/.github/workflows/scripts/validate-coderabbit.sh b/.github/workflows/scripts/validate-coderabbit.sh new file mode 100644 index 0000000000..e94ed0d6f5 --- /dev/null +++ b/.github/workflows/scripts/validate-coderabbit.sh @@ -0,0 +1,38 @@ +#!/bin/bash + +echo "Step 1: Fetching all PR reviews..." + +response=$(curl -s -f -H "Authorization: token $GITHUB_TOKEN" \ + "https://api.github.com/repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}/reviews?per_page=1000") || { + echo "Error: Failed to fetch reviews from GitHub API" + exit 1 +} + +latest_reviews=$(echo "$response" | jq -c '[.[]] | group_by(.user.login) | map(max_by(.submitted_at))') || { + echo "Error: Failed to process reviews JSON" + exit 1 +} + +if [ "$latest_reviews" = "null" ] || [ -z "$latest_reviews" ]; then + echo "Error: Invalid reviews data" + exit 1 +fi + +echo "Step 2: Checking approval status of 'coderabbitai[bot]'..." +approval_state=$(echo "$latest_reviews" | jq -r '[.[] | select(.user.login == "coderabbitai[bot]" and .state == "APPROVED")] | length') + +if [[ "$approval_state" =~ ^[0-9]+$ ]] && [[ $approval_state -gt 0 ]]; then + echo "Success: PR approved by CodeRabbit.ai." +else + echo "" + echo "ERROR:" + echo "" + echo "1) This PR is not approved by CodeRabbit.ai." + echo "2) In the 'Add a comment' section at the bottom" + echo " of the PR web page, add a comment with the" + echo " statement below to restart a review" + echo "" + echo " @coderabbitai full review" + echo "" + exit 1 +fi diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 3430d52ec8..c78d285a91 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -13,7 +13,7 @@ name: Mark stale issues and pull requests on: schedule: - - cron: "0 0 * * *" + - cron: "0 * * * *" permissions: issues: write @@ -21,9 +21,8 @@ permissions: jobs: stale: - + name: Process Stale Issues and PRs runs-on: ubuntu-latest - steps: - uses: actions/stale@v9 with: diff --git a/.husky/post-merge b/.husky/post-merge old mode 100644 new mode 100755 diff --git a/.husky/pre-commit b/.husky/pre-commit old mode 100644 new mode 100755 diff --git a/3141 b/3141 new file mode 100644 index 0000000000..e69de29bb2 diff --git a/CODEOWNERS b/CODEOWNERS index 57dc9c6c80..5ce54cbe03 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,2 +1,2 @@ /.github/ @palisadoes -CODEOWNERS @palisadoes +# CODEOWNERS @palisadoes diff --git a/docs/README.md b/docs/README.md index 4553d05f51..cfb8c7133e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,16 +1,16 @@ -# Talawa-Admin Documentation Website +# Talawa Admin Documentation Website -[![N|Solid](static/img/markdown/misc/logo.png)](https://github.com/PalisadoesFoundation/docs-admin) +[![N|Solid](static/img/markdown/misc/logo.png)](https://github.com/PalisadoesFoundation/talawa-admin) # Installation -This document provides instructions on how to set up and start a running instance of docs-admin website on your local system. The instructions are written to be followed in sequence so make sure to go through each of them step by step without skipping any sections. +This document provides instructions on how to set up and start a running instance of the [talawa-admin documentation website](https://docs-admin.talawa.io/) on your local system. The instructions are written to be followed in sequence so make sure to go through each of them step by step without skipping any sections. # Table of Contents -- [Developer-Docs Installation](#docs-admin-installation) +- [Developer-Docs Installation](#talawa-admin-installation) - [Table of Contents](#table-of-contents) - [Prerequisites for Developers](#prerequisites-for-developers) - [Install node.js](#install-nodejs) @@ -25,7 +25,7 @@ This document provides instructions on how to set up and start a running instanc # Prerequisites for Developers -The contents of the `docs-admin` repo is used to automatically create [the Talawa-Admin Documentation website](https://docs-admin.talawa.io/). The automation uses [Docusaurus](https://docusaurus.io/docs/), a modern static website generator. +The contents of the `talawa-admin` repo is used to automatically create [the talawa-admin Documentation website](https://docs-admin.talawa.io/). The automation uses [Docusaurus](https://docusaurus.io/docs/), a modern static website generator. We recommend that you follow these steps before beginning development work in this repository. @@ -46,8 +46,8 @@ $ yarn -version **Note:** Please bear in mind that to install docusaurus in your system, a Node.js version 16.14 or above (which can be checked by running node -v) is required. Other requirements that pertains to the installation of docusaurus can be found [here](https://docusaurus.io/docs/installation) ```console -$ git clone https://github.com/PalisadoesFoundation/docs-admin.git -$ cd docs-admin +$ git clone https://github.com/PalisadoesFoundation/talawa-admin.git +$ cd talawa-admin $ yarn add docusaurus ``` @@ -173,4 +173,4 @@ If you need to generate static HTML pages (unlikely), then follow these steps. $ yarn run build ``` -This command generates static content into the `/build` directory and can be served using any static contents hosting service. \ No newline at end of file +This command generates static content into the `/build` directory and can be served using any static contents hosting service. diff --git a/docs/blog/2019-05-28-first-blog-post.md b/docs/blog/2019-05-28-first-blog-post.md deleted file mode 100644 index d3032efb35..0000000000 --- a/docs/blog/2019-05-28-first-blog-post.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -slug: first-blog-post -title: First Blog Post -authors: [slorber, yangshun] -tags: [hola, docusaurus] ---- - -Lorem ipsum dolor sit amet... - - - -...consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet diff --git a/docs/blog/2019-05-29-long-blog-post.md b/docs/blog/2019-05-29-long-blog-post.md deleted file mode 100644 index eb4435de59..0000000000 --- a/docs/blog/2019-05-29-long-blog-post.md +++ /dev/null @@ -1,44 +0,0 @@ ---- -slug: long-blog-post -title: Long Blog Post -authors: yangshun -tags: [hello, docusaurus] ---- - -This is the summary of a very long blog post, - -Use a `` comment to limit blog post size in the list view. - - - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet - -Lorem ipsum dolor sit amet, consectetur adipiscing elit. Pellentesque elementum dignissim ultricies. Fusce rhoncus ipsum tempor eros aliquam consequat. Lorem ipsum dolor sit amet diff --git a/docs/blog/2021-08-01-mdx-blog-post.mdx b/docs/blog/2021-08-01-mdx-blog-post.mdx deleted file mode 100644 index 0c4b4a48b9..0000000000 --- a/docs/blog/2021-08-01-mdx-blog-post.mdx +++ /dev/null @@ -1,24 +0,0 @@ ---- -slug: mdx-blog-post -title: MDX Blog Post -authors: [slorber] -tags: [docusaurus] ---- - -Blog posts support [Docusaurus Markdown features](https://docusaurus.io/docs/markdown-features), such as [MDX](https://mdxjs.com/). - -:::tip - -Use the power of React to create interactive blog posts. - -::: - -{/* truncate */} - -For example, use JSX to create an interactive button: - -```js - -``` - - diff --git a/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg b/docs/blog/2021-08-26-welcome/docusaurus-plushie-banner.jpeg deleted file mode 100644 index 11bda0928456b12f8e53d0ba5709212a4058d449..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 96122 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 diff --git a/docs/blog/2021-08-26-welcome/index.md b/docs/blog/2021-08-26-welcome/index.md deleted file mode 100644 index 349ea075f5..0000000000 --- a/docs/blog/2021-08-26-welcome/index.md +++ /dev/null @@ -1,29 +0,0 @@ ---- -slug: welcome -title: Welcome -authors: [slorber, yangshun] -tags: [facebook, hello, docusaurus] ---- - -[Docusaurus blogging features](https://docusaurus.io/docs/blog) are powered by the [blog plugin](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog). - -Here are a few tips you might find useful. - - - -Simply add Markdown files (or folders) to the `blog` directory. - -Regular blog authors can be added to `authors.yml`. - -The blog post date can be extracted from filenames, such as: - -- `2019-05-30-welcome.md` -- `2019-05-30-welcome/index.md` - -A blog post folder can be convenient to co-locate blog post images: - -![Docusaurus Plushie](./docusaurus-plushie-banner.jpeg) - -The blog supports tags as well! - -**And if you don't want a blog**: just delete this directory, and use `blog: false` in your Docusaurus config. diff --git a/docs/blog/authors.yml b/docs/blog/authors.yml deleted file mode 100644 index 8bfa5c7c4b..0000000000 --- a/docs/blog/authors.yml +++ /dev/null @@ -1,23 +0,0 @@ -yangshun: - name: Yangshun Tay - title: Front End Engineer @ Facebook - url: https://github.com/yangshun - image_url: https://github.com/yangshun.png - page: true - socials: - x: yangshunz - github: yangshun - -slorber: - name: Sébastien Lorber - title: Docusaurus maintainer - url: https://sebastienlorber.com - image_url: https://github.com/slorber.png - page: - # customize the url of the author page at /blog/authors/ - permalink: '/all-sebastien-lorber-articles' - socials: - x: sebastienlorber - linkedin: sebastienlorber - github: slorber - newsletter: https://thisweekinreact.com diff --git a/docs/blog/tags.yml b/docs/blog/tags.yml deleted file mode 100644 index bfaa778fbd..0000000000 --- a/docs/blog/tags.yml +++ /dev/null @@ -1,19 +0,0 @@ -facebook: - label: Facebook - permalink: /facebook - description: Facebook tag description - -hello: - label: Hello - permalink: /hello - description: Hello tag description - -docusaurus: - label: Docusaurus - permalink: /docusaurus - description: Docusaurus tag description - -hola: - label: Hola - permalink: /hola - description: Hola tag description diff --git a/docs/docusaurus.config.ts b/docs/docusaurus.config.ts index fe6e79534b..2622ca65b9 100644 --- a/docs/docusaurus.config.ts +++ b/docs/docusaurus.config.ts @@ -6,8 +6,8 @@ import type * as Preset from '@docusaurus/preset-classic'; const config: Config = { title: 'Talawa-Admin Documentation', - tagline: 'Start your open source journey here', - favicon: 'img/favicon.ico', + tagline: 'Complete guides and references for building with Talawa', + favicon: 'img/icons/favicon_palisadoes.ico', url: 'https://docs-admin.talawa.io', baseUrl: '/', @@ -45,75 +45,132 @@ const config: Config = { ], ], - themeConfig: { - // Replace with your project's social card - image: 'img/docusaurus-social-card.jpg', - navbar: { - title: 'My Site', - logo: { - alt: 'My Site Logo', - src: 'img/logo.svg', - }, - items: [ - { - type: 'docSidebar', - sidebarId: 'tutorialSidebar', - position: 'left', - label: 'Tutorial', - }, - { - href: 'https://github.com/facebook/docusaurus', - label: 'GitHub', - position: 'right', - }, - ], - }, - footer: { - style: 'dark', - links: [ - { - title: 'Docs', - items: [ - { - label: 'Tutorial', - to: '/docs/intro', - }, - ], - }, - { - title: 'Community', - items: [ - { - label: 'Stack Overflow', - href: 'https://stackoverflow.com/questions/tagged/docusaurus', - }, - { - label: 'Discord', - href: 'https://discordapp.com/invite/docusaurus', - }, - { - label: 'X', - href: 'https://x.com/docusaurus', - }, - ], + themeConfig: + /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ + { + docs: { + sidebar: { + hideable: false, }, - { - title: 'More', - items: [ - { - label: 'GitHub', - href: 'https://github.com/facebook/docusaurus', - }, - ], + }, + navbar: { + title: 'Talawa Admin Documentation', + logo: { + alt: 'Talawa Logo', + src: 'img/icons/favicon_palisadoes.ico', + className: 'LogoAnimation', }, - ], - copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`, - }, - prism: { - theme: prismThemes.github, - darkTheme: prismThemes.dracula, + items: [ + { + type: 'docSidebar', + sidebarId: 'tutorialSidebar', + label: 'General', + position: 'left', + }, + { + label: 'Mobile Guide', + position: 'left', + href: 'https://docs-mobile.talawa.io/', + target: '_self', + }, + { + label: 'Admin Guide', + position: 'left', + href: 'https://docs-admin.talawa.io/', + target: '_self', + }, + { + label: 'API Guide', + position: 'left', + href: 'https://docs-api.talawa.io/', + target: '_self', + }, + + { + label: 'Demo', + position: 'left', + href: 'http://admin-demo.talawa.io/', + }, + { + to: 'https://github.com/PalisadoesFoundation', + position: 'right', + className: 'header-github-link', + 'aria-label': 'GitHub repository', + }, + { + to: 'https://www.youtube.com/@PalisadoesOrganization', + position: 'right', + className: 'header-youtube-link', + 'aria-label': 'Palisadoes Youtube channel', + }, + ], + }, + colorMode: { + defaultMode: 'light', + disableSwitch: false, + respectPrefersColorScheme: false, + }, + footer: { + style: 'dark', + links: [ + { + title: 'Community', + items: [ + { + label: ' Slack', + to: 'https://github.com/PalisadoesFoundation', + className: 'footer__icon footer__slack', + }, + { + label: ' News', + to: 'https://www.palisadoes.org/news/', + className: 'footer__icon footer__news', + }, + { + label: ' Contact Us', + to: 'https://www.palisadoes.org/contact/', + className: 'footer__icon footer__contact', + }, + ], + }, + { + title: 'Social Media', + items: [ + { + label: ' Twitter', + to: 'https://twitter.com/palisadoesorg?lang=en', + className: 'footer__icon footer__twitter', + }, + { + label: ' Facebook', + to: 'https://www.facebook.com/palisadoesproject/', + className: 'footer__icon footer__facebook', + }, + { + label: ' Instagram', + to: 'https://www.instagram.com/palisadoes/?hl=en', + className: 'footer__icon footer__instagram', + }, + ], + }, + { + title: 'Development', + items: [ + { + label: ' GitHub', + to: 'https://github.com/PalisadoesFoundation', + className: 'footer__icon footer__github', + }, + ], + }, + ], + copyright: `Copyright © ${new Date().getFullYear()} The Palisadoes Foundation, LLC. Built with Docusaurus.`, + }, + prism: { + theme: prismThemes.github, + darkTheme: prismThemes.dracula, + }, }, - } satisfies Preset.ThemeConfig, }; export default config; diff --git a/docs/src/css/custom.css b/docs/src/css/custom.css index 2bc6a4cfde..f0f927b720 100644 --- a/docs/src/css/custom.css +++ b/docs/src/css/custom.css @@ -2,29 +2,424 @@ * Any CSS included here will be global. The classic template * bundles Infima by default. Infima is a CSS framework designed to * work well for content-centric websites. + * You can override the default Infima variables here. */ -/* You can override the default Infima variables here. */ :root { - --ifm-color-primary: #2e8555; - --ifm-color-primary-dark: #29784c; - --ifm-color-primary-darker: #277148; - --ifm-color-primary-darkest: #205d3b; - --ifm-color-primary-light: #33925d; - --ifm-color-primary-lighter: #359962; - --ifm-color-primary-lightest: #3cad6e; + --secondary-blue-900: #001c63; + --sidebar-bg-color: #f3f4f6; + --secondary-blue-500: #3970fd; + --primary-blue-600: #1e56e3; + --base-neutral-0: #ffffff; + --primary-neutral-800: #1f2a37; + --ifm-menu-color-active: #1e56e3; + --primary-neutral-600: #4d5761; + --ifm-breadcrumb-color-active: var(--primary-neutral-600); + --ifm-link-color: #1e56e3; + --ifm-button-background-color: #2e8555; + --ifm-button-background-color-dark: #205d3b; + --ifm-hover-overlay: rgba(0, 0, 0, 0.05); + --brand-color: black; + --next-prev-border-color: #e5e7eb; + --ifm-color-emphasis-100: #f4f8fb; + --ifm-color-emphasis-0: #fff; + --ifm-color-primary: #1e56e3; + --ifm-background-surface-color: var(--ifm-color-white); + --ifm-menu-color: var(--ifm-color-gray-600); + --ifm-toc-link-color: var(--ifm-color-gray-600); --ifm-code-font-size: 95%; - --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); -} - -/* For readability concerns, you should choose a lighter palette in dark mode. */ -[data-theme='dark'] { - --ifm-color-primary: #25c2a0; - --ifm-color-primary-dark: #21af90; - --ifm-color-primary-darker: #1fa588; - --ifm-color-primary-darkest: #1a8870; - --ifm-color-primary-light: #29d5b0; - --ifm-color-primary-lighter: #32d8b4; - --ifm-color-primary-lightest: #4fddbf; - --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); + --ifm-toc-border-color: transparent; + --ifm-code-background: #e5ecff; + --ifm-code-color: #0087ff; + --ifm-color-content: #000e33; + --ifm-heading-line-height: 1.5; + --ifm-h1-font-size: 2.25rem; + --ifm-h2-font-size: 1.875rem; + --ifm-navbar-shadow: 0 1px 2px 0 #0000001a; + --ifm-navbar-search-input-background-color: var(--ifm-color-gray-100); + --ifm-navbar-search-input-color: var(--ifm-color-content); + --ifm-table-stripe-background: #efeff2; + --ifm-font-family-base: system-ui, -apple-system, Segoe UI, Roboto, Ubuntu, + Cantarell, Noto Sans, sans-serif, BlinkMacSystemFont, 'Segoe UI', Helvetica, + Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; + --ifm-font-family-monospace: 'IBM Plex Mono', SFMono-Regular, Menlo, Monaco, + Consolas, 'Liberation Mono', 'Courier New', monospace; +} + +/* Dak mode css */ + +html[data-theme='dark'] { + --ifm-background-color: #111927; + --ifm-background-surface-color: var(--ifm-background-color); + --ifm-menu-color: var(--ifm-color-gray-200); + --ifm-toc-link-color: var(--ifm-color-gray-200); + --ifm-code-background: #001b66; + --ifm-color-content: var(--ifm-color-white); + --ifm-navbar-search-input-background-color: #001b66; + --ifm-table-stripe-background: #001242; + --ifm-navbar-search-input-placeholder-color: var(--ifm-color-gray-200); + --ifm-navbar-search-input-icon: url('data:image/svg+xml;utf8,'); + + --ifm-hover-overlay: rgba(0, 0, 0, 0); + --ifm-color-primary: #1e56e3; + --secondary-blue-900: #c6d6ff; + --sidebar-bg-color: #161f36; + --primary-neutral-800: #c9c9cc; + --ifm-button-background-color: #25c2a0; + --ifm-button-background-color-dark: #2e8555; + --ifm-navbar-link-color: #9da4ae; + --brand-color: white; + --primary-neutral-600: #c4c4c4; + --next-prev-border-color: #293441; + --ifm-color-emphasis-100: #1d1e30; + --ifm-color-emphasis-0: #111f3b; +} + +.docusaurus-highlight-code-line { + background-color: rgb(72, 77, 91); + display: block; + margin: 0 calc(-1 * var(--ifm-pre-padding)); + padding: 0 var(--ifm-pre-padding); +} + +.table-of-contents { + font-size: 0.75rem; +} + +h1.docTitle_node_modules-\@docusaurus-theme-classic-src-theme-DocItem- { + font-size: var(--ifm-h1-font-size); + margin-bottom: 1.5rem; +} + +.menu { + background-color: var(--sidebar-bg-color); +} + +.menu__link, +.menu * { + line-height: 1.5; + font-size: 0.7rem; + padding-left: 0.5rem; + padding-bottom: 0; + text-transform: uppercase; + font-weight: 700; + background: transparent !important; +} + +.menu__list { + border-bottom: 1px solid var(--next-prev-border-color); +} + +.menu__list ul { + margin-left: 15px; + margin-right: 15px; +} + +.markdown > h2 { + --ifm-h2-font-size: 1.875rem; + margin-bottom: 0.8rem; + margin-top: calc(var(--ifm-h2-vertical-rhythm-top) * 0rem); +} + +.markdown > h3 { + --ifm-h3-font-size: 1.5rem; + margin-bottom: 0.8rem; + margin-top: calc(var(--ifm-h3-vertical-rhythm-top) * 0rem); +} + +.navbar { + background-color: var(--sidebar-bg-color); + box-shadow: var(--ifm-navbar-shadow); + padding: 24px 48px; + height: auto; +} + +.navbar__title { + font-size: 1.155rem; +} + +.navbar__item { + font-size: 1rem; +} + +.navbar__link:hover, +.navbar__link--active { + color: var(--primary-blue-600); + text-decoration: none; +} + +.navbar__items--right > .navbar__item:not(:first-of-type) { + margin-left: 0.25px; +} + +.dropdown__link:hover { + color: #2563eb; +} + +.dropdown__link--active { + background-color: transparent; +} + +.dropdown__link { + color: var(--ifm-navbar-link-color); +} + +.header-github-link:hover { + opacity: 0.7; +} + +.header-youtube-link:hover { + opacity: 0.7; +} + +.youtube-button { + background: linear-gradient(90deg, #ff3600 0%, #ff8100 100%); + border: none; + border-radius: 4px; + padding: 7px 21px; + color: #fff; + font-weight: bold; + font-size: 14px; + text-decoration: none; + display: inline-flex; + margin-right: 2.75rem; +} + +.github-button { + background: linear-gradient(90deg, #ff3600 0%, #ff8100 100%); + border: none; + border-radius: 4px; + padding: 7px 21px; + color: #fff; + font-weight: bold; + font-size: 14px; + text-decoration: none; + display: inline-flex; + margin-right: 2.75rem; +} + +.github-button:hover { + color: #fff; + text-decoration: none; +} + +.youtube-button:hover { + color: #fff; + text-decoration: none; +} + +.header-github-link:before { + content: ''; + width: 20px; + height: 20px; + display: flex; + background: url('/img/icons/github-dark.svg') no-repeat; + position: relative; + right: 8px; + top: 1.5px; +} + +.header-twitter-link:before { + content: ''; + width: 15px; + height: 15px; + display: flex; + background: url('/img/icons/twitter.svg') no-repeat 90% 100%; + position: relative; + right: 6px; + top: 2px; +} + +.header-youtube-link:before { + content: ''; + width: 25px; + height: 30px; + display: flex; + background: url('/img/icons/youtube.svg') no-repeat; + position: relative; + right: 8px; + top: 4.5px; +} + +.footer--dark { + --ifm-footer-background-color: #111927; +} + +.footer--dark li { + margin-bottom: 0; + line-height: normal; +} + +.footer__icon { + margin: 0; + padding: 2px; + color: #fff; + font-size: 1rem; +} + +.footer__icon:before { + content: ''; + display: inline-flex; + height: 16px; + width: 16px; + background-color: #fff; +} + +.footer__icon:hover:before { + background-color: var(--ifm-navbar-link-hover-color); +} + +.footer__github:before { + mask: url(/img/icons/github.svg) no-repeat 100% 100%; + mask-size: cover; +} + +.footer__slack:before { + mask: url(/img/icons/slack.svg) no-repeat 100% 100%; + mask-size: cover; +} + +.footer__facebook:before { + mask: url(/img/icons/facebook.svg) no-repeat 100% 100%; + mask-size: cover; +} + +.footer__instagram:before { + mask: url(/img/icons/instagram.svg) no-repeat 100% 100%; + mask-size: cover; +} + +.footer__twitter:before { + mask: url(/img/icons/twitter.svg) no-repeat 100% 100%; + mask-size: cover; +} + +.footer__news:before { + mask: url(/img/icons/source.svg) no-repeat 100% 100%; + mask-size: cover; +} + +.footer__contact:before { + mask: url(/img/icons/source.svg) no-repeat 100% 100%; + mask-size: cover; +} + +.footer__opportunities:before { + mask: url(/img/icons/opportunities.svg) no-repeat 100% 100%; + mask-size: cover; +} + +.footer__team:before { + mask: url(/img/icons/team.svg) no-repeat 100% 100%; + mask-size: cover; +} + +html[data-theme='dark'] .header-github-link:before { + background: url(/img/icons/github.svg) no-repeat; +} +html[data-theme='dark'] .header-youtube-link:before { + background: url(/img/icons/youtube-white.svg) no-repeat; +} + +@media (max-width: 996px) { + .navbar__item.github-button { + display: none; + } + .github-button { + margin: var(--ifm-menu-link-padding-vertical) + var(--ifm-menu-link-padding-horizontal); + } + .navbar__item.youtube-button { + display: none; + } + .youtube-button { + margin: var(--ifm-menu-link-padding-vertical) + var(--ifm-menu-link-padding-horizontal); + } + .center { + text-align: center; + } +} + +@media (max-width: 1000px) { + .navbar__items--right > .navbar__item:not(:first-of-type) { + margin-left: 0.25rem; + } + .github-button { + margin-right: 0.5rem; + } + .youtube-button { + margin-right: 0.5rem; + } + .hero__title { + font-size: 2rem; + } +} + +@media (max-width: 1149px) and (min-width: 1050px) { + .navbar__items--right > .navbar__item:not(:first-of-type) { + margin-left: 1.5rem; + } + .github-button { + margin-right: 0.5rem; + } + .youtube-button { + margin-right: 0.5rem; + } +} + +@media (max-width: 1049px) and (min-width: 1001px) { + .navbar__items--right > .navbar__item:not(:first-of-type) { + margin-left: 0.5rem; + } + .github-button { + margin-right: 0.5rem; + } + .youtube-button { + margin-right: 0.5rem; + } +} + +h1 { + font-size: 1.75rem; + font-weight: 700; +} +.Heading { + font-size: 1.5rem; + font-weight: 700; + text-align: center !important; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + color: var(--secondary-blue-900); + margin: 20px 0 !important; +} + +p, +textarea, +li, +.Heading div { + margin-bottom: 1.25rem; + color: var(--primary-neutral-800); + font-size: 0.9375rem; + line-height: 1.625rem; +} + +a { + color: #2563eb; + text-decoration: none; +} + +a:hover { + color: #86a7ef; +} + +/* Hide external link svg on Navbar */ +.iconExternalLink_nPIU { + display: none !important; } diff --git a/docs/src/pages/index.tsx b/docs/src/pages/index.tsx index 270b7f9af8..300781adf2 100644 --- a/docs/src/pages/index.tsx +++ b/docs/src/pages/index.tsx @@ -10,20 +10,12 @@ import styles from './index.module.css'; function HomepageHeader() { const { siteConfig } = useDocusaurusContext(); return ( -
+
{siteConfig.title}

{siteConfig.tagline}

-
- - Docusaurus Tutorial - 5min ⏱️ - -
); diff --git a/docs/static/img/icons/facebook.svg b/docs/static/img/icons/facebook.svg new file mode 100644 index 0000000000..e8d1443db6 --- /dev/null +++ b/docs/static/img/icons/facebook.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs/static/img/icons/favicon_palisadoes.ico b/docs/static/img/icons/favicon_palisadoes.ico new file mode 100644 index 0000000000000000000000000000000000000000..0675af2934d8d350d002845f0fb9d223e1ccd06e GIT binary patch literal 870 zcmV-s1DX7ZP)nDoUaR(9kJ@aY0L*+dwyfI)>y5g7HwCMKH> z;A9gK+*@{Q_`KqaO<1}BeoZ|~GdREl@l4GDaI%R}U_jTQkW|wEa0_myGU#Lzp=JRL z?E(O{yJXJ*x^KTL(E(We-vGItIxUo1@Wm#y>~sLEQbo60UAh0NciAwER8s(MJUbM* zJKL*0VrQ0ur60dq4+GZ?!wByQKsZP(ueOCA&Fx?J%EZi4u=M0@C?I}z;|{Rh0{~;f z5%b>z`)*GkSbx17tWzqKTDUjcTdWDbC4+`xG@K*K{{mt7R7%}f{eArWS`gry&6|;*QJ+{ z9SVbEvJYSTtG;reK5L&(Ry+Q*JHHkFt{H|gqy=CYMg+JfQ!WLa;^&jq4n+{&MJn|L zvMth#sxnZN9lk$XX*iY(JvKl4Y*iK(v;a)goCCtZ!`k!ZBb#f59=lO|0NxE$g0`QH znxi6c$uv!AH#FRc#JgFxpMx)kH#(|qdh6TKFRkShA6h$saUiAY08apb*yF1gDs4=! zcS&!*h@x1#R{S4xm+zeRg7qB5gZ5MWGX)Ehu3S`C~@1LfoC1>mN_<`|0Slx5%|iq-;dia;tE zL%l;v$9o+>KAyI4Z}M+tFXB;9qAp~uHxHbX*(e8*XdjF1HXP2!)44_fHMTinR|Hb| wcv=bWISEAtNAmG>N+-Cm3FFp^ \ No newline at end of file diff --git a/docs/static/img/icons/github.svg b/docs/static/img/icons/github.svg new file mode 100644 index 0000000000..ab49f9955c --- /dev/null +++ b/docs/static/img/icons/github.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/static/img/icons/instagram.svg b/docs/static/img/icons/instagram.svg new file mode 100644 index 0000000000..0b5c5cef02 --- /dev/null +++ b/docs/static/img/icons/instagram.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs/static/img/icons/opportunities.svg b/docs/static/img/icons/opportunities.svg new file mode 100644 index 0000000000..85a807cee9 --- /dev/null +++ b/docs/static/img/icons/opportunities.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/docs/static/img/icons/slack.svg b/docs/static/img/icons/slack.svg new file mode 100644 index 0000000000..f4aa6e6d66 --- /dev/null +++ b/docs/static/img/icons/slack.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs/static/img/icons/source.svg b/docs/static/img/icons/source.svg new file mode 100644 index 0000000000..1d93acb91a --- /dev/null +++ b/docs/static/img/icons/source.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/docs/static/img/icons/team.svg b/docs/static/img/icons/team.svg new file mode 100644 index 0000000000..29dfc5b0ee --- /dev/null +++ b/docs/static/img/icons/team.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/docs/static/img/icons/twitter.svg b/docs/static/img/icons/twitter.svg new file mode 100644 index 0000000000..18eb8d3410 --- /dev/null +++ b/docs/static/img/icons/twitter.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/docs/static/img/icons/youtube-white.svg b/docs/static/img/icons/youtube-white.svg new file mode 100644 index 0000000000..2cf08c84dc --- /dev/null +++ b/docs/static/img/icons/youtube-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/docs/static/img/icons/youtube.svg b/docs/static/img/icons/youtube.svg new file mode 100644 index 0000000000..97a61232b1 --- /dev/null +++ b/docs/static/img/icons/youtube.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 7f115d04df..3b7c816f00 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "@mui/base": "^5.0.0-beta.61", "@mui/icons-material": "^6.1.6", "@mui/material": "^6.1.6", - "@mui/private-theming": "^6.1.6", + "@mui/private-theming": "^6.3.0", "@mui/system": "^6.1.6", "@mui/x-charts": "^7.22.2", "@mui/x-data-grid": "^7.22.1", @@ -55,7 +55,7 @@ "react-datepicker": "^7.5.0", "react-dom": "^18.3.1", "react-google-recaptcha": "^3.1.0", - "react-i18next": "^15.0.2", + "react-i18next": "^15.4.0", "react-icons": "^5.2.1", "react-infinite-scroll-component": "^6.1.0", "react-multi-carousel": "^2.8.5", @@ -106,7 +106,7 @@ "eslint": "^8.49.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.31.0", - "eslint-plugin-jest": "^28.8.0", + "eslint-plugin-jest": "^28.10.0", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-react": "^7.37.1", "eslint-plugin-tsdoc": "^0.3.0", @@ -116,8 +116,8 @@ "jest-localstorage-mock": "^2.4.19", "jest-location-mock": "^2.0.0", "jest-preview": "^0.3.1", - "lint-staged": "^15.2.8", - "postcss-modules": "^6.0.0", + "lint-staged": "^15.3.0", + "postcss-modules": "^6.0.1", "sass": "^1.80.7", "tsx": "^4.19.1", "vite-plugin-svgr": "^4.2.0", @@ -4201,12 +4201,12 @@ } }, "node_modules/@mui/private-theming": { - "version": "6.1.6", - "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.1.6.tgz", - "integrity": "sha512-ioAiFckaD/fJSnTrUMWgjl9HYBWt7ixCh7zZw7gDZ+Tae7NuprNV6QJK95EidDT7K0GetR2rU3kAeIR61Myttw==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@mui/private-theming/-/private-theming-6.3.0.tgz", + "integrity": "sha512-tdS8jvqMokltNTXg6ioRCCbVdDmZUJZa/T9VtTnX2Lwww3FTgCakst9tWLZSxm1fEE9Xp0m7onZJmgeUmWQYVw==", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/utils": "^6.1.6", + "@mui/utils": "^6.3.0", "prop-types": "^15.8.1" }, "engines": { @@ -4299,9 +4299,9 @@ } }, "node_modules/@mui/types": { - "version": "7.2.19", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.19.tgz", - "integrity": "sha512-6XpZEM/Q3epK9RN8ENoXuygnqUQxE+siN/6rGRi2iwJPgBUR25mphYQ9ZI87plGh58YoZ5pp40bFvKYOCDJ3tA==", + "version": "7.2.20", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-7.2.20.tgz", + "integrity": "sha512-straFHD7L8v05l/N5vcWk+y7eL9JF0C2mtph/y4BPm3gn2Eh61dDwDB65pa8DLss3WJfDXYC7Kx5yjP0EmXpgw==", "peerDependencies": { "@types/react": "^17.0.0 || ^18.0.0 || ^19.0.0" }, @@ -4312,16 +4312,16 @@ } }, "node_modules/@mui/utils": { - "version": "6.1.6", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.1.6.tgz", - "integrity": "sha512-sBS6D9mJECtELASLM+18WUcXF6RH3zNxBRFeyCRg8wad6NbyNrdxLuwK+Ikvc38sTZwBzAz691HmSofLqHd9sQ==", + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-6.3.0.tgz", + "integrity": "sha512-MkDBF08OPVwXhAjedyMykRojgvmf0y/jxkBWjystpfI/pasyTYrfdv4jic6s7j3y2+a+SJzS9qrD6X8ZYj/8AQ==", "dependencies": { "@babel/runtime": "^7.26.0", - "@mui/types": "^7.2.19", - "@types/prop-types": "^15.7.13", + "@mui/types": "^7.2.20", + "@types/prop-types": "^15.7.14", "clsx": "^2.1.1", "prop-types": "^15.8.1", - "react-is": "^18.3.1" + "react-is": "^19.0.0" }, "engines": { "node": ">=14.0.0" @@ -4340,6 +4340,11 @@ } } }, + "node_modules/@mui/utils/node_modules/react-is": { + "version": "19.0.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-19.0.0.tgz", + "integrity": "sha512-H91OHcwjZsbq3ClIDHMzBShc1rotbfACdWENsmEf0IFvZ3FgGPtdHMcsv45bQ1hAbgdfiA8SnxTKfDS+x/8m2g==" + }, "node_modules/@mui/x-charts": { "version": "7.22.2", "resolved": "https://registry.npmjs.org/@mui/x-charts/-/x-charts-7.22.2.tgz", @@ -4600,7 +4605,6 @@ "version": "2.5.0", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.0.tgz", "integrity": "sha512-i0GV1yJnm2n3Yq1qw6QrUrd/LI9bE8WEBOTtOkpCXHHdyN3TAGgqAK/DAT05z4fq2x04cARXt2pDmjWjL92iTQ==", - "dev": true, "hasInstallScript": true, "optional": true, "dependencies": { @@ -4639,7 +4643,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "android" @@ -4659,7 +4662,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -4679,7 +4681,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "darwin" @@ -4699,7 +4700,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "freebsd" @@ -4719,7 +4719,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "linux" @@ -4739,7 +4738,6 @@ "cpu": [ "arm" ], - "dev": true, "optional": true, "os": [ "linux" @@ -4759,7 +4757,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -4779,7 +4776,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -4799,7 +4795,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -4819,7 +4814,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -4839,7 +4833,6 @@ "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -4859,7 +4852,6 @@ "cpu": [ "ia32" ], - "dev": true, "optional": true, "os": [ "win32" @@ -4879,7 +4871,6 @@ "cpu": [ "x64" ], - "dev": true, "optional": true, "os": [ "win32" @@ -6283,9 +6274,9 @@ "dev": true }, "node_modules/@types/prop-types": { - "version": "15.7.13", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.13.tgz", - "integrity": "sha512-hCZTSvwbzWGvhqxp/RqVqwU999pBf2vp7hzIjiYOsl8wqOmUxkQ6ddw1cV3l8811+kdUFus/q4d1Y3E3SyEifA==" + "version": "15.7.14", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==" }, "node_modules/@types/react": { "version": "18.3.12", @@ -8676,9 +8667,9 @@ } }, "node_modules/cli-truncate/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "engines": { "node": ">=12" @@ -8688,9 +8679,9 @@ } }, "node_modules/cli-truncate/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "dev": true }, "node_modules/cli-truncate/node_modules/string-width": { @@ -9470,9 +9461,9 @@ "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==" }, "node_modules/debug": { - "version": "4.3.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", - "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dependencies": { "ms": "^2.1.3" }, @@ -9636,7 +9627,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", "integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==", - "dev": true, "optional": true, "bin": { "detect-libc": "bin/detect-libc.js" @@ -10419,11 +10409,10 @@ } }, "node_modules/eslint-plugin-jest": { - "version": "28.8.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.8.0.tgz", - "integrity": "sha512-Tubj1hooFxCl52G4qQu0edzV/+EZzPUeN8p2NnW5uu4fbDs+Yo7+qDVDc4/oG3FbCqEBmu/OC3LSsyiU22oghw==", + "version": "28.10.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jest/-/eslint-plugin-jest-28.10.0.tgz", + "integrity": "sha512-hyMWUxkBH99HpXT3p8hc7REbEZK3D+nk8vHXGgpB+XXsi0gO4PxMSP+pjfUzb67GnV9yawV9a53eUmcde1CCZA==", "dev": true, - "license": "MIT", "dependencies": { "@typescript-eslint/utils": "^6.0.0 || ^7.0.0 || ^8.0.0" }, @@ -10850,6 +10839,12 @@ "node": ">=0.10.0" } }, + "node_modules/eventemitter3": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", + "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "dev": true + }, "node_modules/events": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", @@ -11503,9 +11498,9 @@ } }, "node_modules/get-east-asian-width": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", - "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.3.0.tgz", + "integrity": "sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==", "dev": true, "engines": { "node": ">=18" @@ -12224,7 +12219,7 @@ "version": "5.0.2", "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.0.2.tgz", "integrity": "sha512-1NU7hWZDkV7hJ4PJ9dur9gTNQ4ePNPN4k9/0YhwjzykTi/+3Q5pF93YU5QoVj8BuOnhLgaY8gs0U2pj4kSYVcw==", - "dev": true + "devOptional": true }, "node_modules/import-fresh": { "version": "3.3.0", @@ -14808,21 +14803,21 @@ } }, "node_modules/lint-staged": { - "version": "15.2.8", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.8.tgz", - "integrity": "sha512-PUWFf2zQzsd9EFU+kM1d7UP+AZDbKFKuj+9JNVTBkhUFhbg4MAt6WfyMMwBfM4lYqd4D2Jwac5iuTu9rVj4zCQ==", + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.3.0.tgz", + "integrity": "sha512-vHFahytLoF2enJklgtOtCtIjZrKD/LoxlaUusd5nh7dWv/dkKQJY74ndFSzxCdv7g0ueGg1ORgTSt4Y9LPZn9A==", "dev": true, "dependencies": { - "chalk": "~5.3.0", + "chalk": "~5.4.1", "commander": "~12.1.0", - "debug": "~4.3.6", + "debug": "~4.4.0", "execa": "~8.0.1", - "lilconfig": "~3.1.2", - "listr2": "~8.2.4", - "micromatch": "~4.0.7", + "lilconfig": "~3.1.3", + "listr2": "~8.2.5", + "micromatch": "~4.0.8", "pidtree": "~0.6.0", "string-argv": "~0.3.2", - "yaml": "~2.5.0" + "yaml": "~2.6.1" }, "bin": { "lint-staged": "bin/lint-staged.js" @@ -14835,9 +14830,9 @@ } }, "node_modules/lint-staged/node_modules/chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", "dev": true, "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -14912,9 +14907,9 @@ } }, "node_modules/lint-staged/node_modules/lilconfig": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", - "integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", + "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", "dev": true, "engines": { "node": ">=14" @@ -15002,9 +14997,9 @@ } }, "node_modules/lint-staged/node_modules/yaml": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.5.0.tgz", - "integrity": "sha512-2wWLbGbYDiSqqIKoPjar3MPgB94ErzCtrNE1FdqGuaO0pi2JGjmE8aW8TDZwzU7vuxcGRdL/4gPQwQ7hD5AMSw==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz", + "integrity": "sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg==", "dev": true, "bin": { "yaml": "bin.mjs" @@ -15069,9 +15064,9 @@ } }, "node_modules/listr2": { - "version": "8.2.4", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.4.tgz", - "integrity": "sha512-opevsywziHd3zHCVQGAj8zu+Z3yHNkkoYhWIGnq54RrCVwLz0MozotJEDnKsIBLvkfLGN6BLOyAeRrYI0pKA4g==", + "version": "8.2.5", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.5.tgz", + "integrity": "sha512-iyAZCeyD+c1gPyE9qpFu8af0Y+MRtmKOncdGoA2S5EY8iFq99dmmvkNnHiWo+pj0s7yH7l3KPIgee77tKpXPWQ==", "dev": true, "dependencies": { "cli-truncate": "^4.0.0", @@ -15086,9 +15081,9 @@ } }, "node_modules/listr2/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "engines": { "node": ">=12" @@ -15110,15 +15105,9 @@ } }, "node_modules/listr2/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", - "dev": true - }, - "node_modules/listr2/node_modules/eventemitter3": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", - "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "dev": true }, "node_modules/listr2/node_modules/string-width": { @@ -15283,9 +15272,9 @@ } }, "node_modules/log-update/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", + "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", "dev": true, "engines": { "node": ">=12" @@ -15307,9 +15296,9 @@ } }, "node_modules/log-update/node_modules/emoji-regex": { - "version": "10.3.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", - "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz", + "integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==", "dev": true }, "node_modules/log-update/node_modules/is-fullwidth-code-point": { @@ -15905,7 +15894,6 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", - "dev": true, "optional": true }, "node_modules/node-fetch": { @@ -16774,19 +16762,19 @@ } }, "node_modules/postcss-modules": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-6.0.0.tgz", - "integrity": "sha512-7DGfnlyi/ju82BRzTIjWS5C4Tafmzl3R79YP/PASiocj+aa6yYphHhhKUOEoXQToId5rgyFgJ88+ccOUydjBXQ==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-modules/-/postcss-modules-6.0.1.tgz", + "integrity": "sha512-zyo2sAkVvuZFFy0gc2+4O+xar5dYlaVy/ebO24KT0ftk/iJevSNyPyQellsBLlnccwh7f6V6Y4GvuKRYToNgpQ==", "dev": true, "dependencies": { "generic-names": "^4.0.0", "icss-utils": "^5.1.0", "lodash.camelcase": "^4.3.0", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.0", - "postcss-modules-scope": "^3.0.0", + "postcss-modules-extract-imports": "^3.1.0", + "postcss-modules-local-by-default": "^4.0.5", + "postcss-modules-scope": "^3.2.0", "postcss-modules-values": "^4.0.0", - "string-hash": "^1.1.1" + "string-hash": "^1.1.3" }, "peerDependencies": { "postcss": "^8.0.0" @@ -18148,9 +18136,9 @@ } }, "node_modules/react-i18next": { - "version": "15.0.2", - "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.0.2.tgz", - "integrity": "sha512-z0W3/RES9Idv3MmJUcf0mDNeeMOUXe+xoL0kPfQPbDoZHmni/XsIoq5zgT2MCFUiau283GuBUK578uD/mkAbLQ==", + "version": "15.4.0", + "resolved": "https://registry.npmjs.org/react-i18next/-/react-i18next-15.4.0.tgz", + "integrity": "sha512-Py6UkX3zV08RTvL6ZANRoBh9sL/ne6rQq79XlkHEdd82cZr2H9usbWpUNVadJntIZP2pu3M2rL1CN+5rQYfYFw==", "dependencies": { "@babel/runtime": "^7.25.0", "html-parse-stringify": "^3.0.1" @@ -18977,7 +18965,7 @@ "version": "1.80.7", "resolved": "https://registry.npmjs.org/sass/-/sass-1.80.7.tgz", "integrity": "sha512-MVWvN0u5meytrSjsU7AWsbhoXi1sc58zADXFllfZzbsBT1GHjjar6JwBINYPRrkx/zqnQ6uqbQuHgE95O+C+eQ==", - "dev": true, + "devOptional": true, "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.0.2", @@ -18997,7 +18985,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.1.tgz", "integrity": "sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==", - "dev": true, + "devOptional": true, "dependencies": { "readdirp": "^4.0.1" }, @@ -19012,7 +19000,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", "integrity": "sha512-yDMz9g+VaZkqBYS/ozoBJwaBhTbZo3UNYQHNRw1D3UFQB8oHB4uS/tAODO+ZLjGWmUbKnIlOWO+aaIiAxrUWHA==", - "dev": true, + "devOptional": true, "engines": { "node": ">= 14.16.0" }, diff --git a/package.json b/package.json index 257949ead6..cd52ff6453 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "@mui/base": "^5.0.0-beta.61", "@mui/icons-material": "^6.1.6", "@mui/material": "^6.1.6", - "@mui/private-theming": "^6.1.6", + "@mui/private-theming": "^6.3.0", "@mui/system": "^6.1.6", "@mui/x-charts": "^7.22.2", "@mui/x-data-grid": "^7.22.1", @@ -52,7 +52,7 @@ "react-datepicker": "^7.5.0", "react-dom": "^18.3.1", "react-google-recaptcha": "^3.1.0", - "react-i18next": "^15.0.2", + "react-i18next": "^15.4.0", "react-icons": "^5.2.1", "react-infinite-scroll-component": "^6.1.0", "react-multi-carousel": "^2.8.5", @@ -143,7 +143,7 @@ "eslint": "^8.49.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-import": "^2.31.0", - "eslint-plugin-jest": "^28.8.0", + "eslint-plugin-jest": "^28.10.0", "eslint-plugin-prettier": "^5.2.1", "eslint-plugin-react": "^7.37.1", "eslint-plugin-tsdoc": "^0.3.0", @@ -153,8 +153,8 @@ "jest-localstorage-mock": "^2.4.19", "jest-location-mock": "^2.0.0", "jest-preview": "^0.3.1", - "lint-staged": "^15.2.8", - "postcss-modules": "^6.0.0", + "lint-staged": "^15.3.0", + "postcss-modules": "^6.0.1", "sass": "^1.80.7", "tsx": "^4.19.1", "vite-plugin-svgr": "^4.2.0", diff --git a/scripts/githooks/check-localstorage-usage.js b/scripts/githooks/check-localstorage-usage.js old mode 100644 new mode 100755 index 0a7e2adbfc..0a811df307 --- a/scripts/githooks/check-localstorage-usage.js +++ b/scripts/githooks/check-localstorage-usage.js @@ -86,10 +86,10 @@ if (filesWithLocalStorage.length > 0) { console.info( '\x1b[34m%s\x1b[0m', - '\nInfo: Consider using custom hook functions.', + '\nInfo: Consider using custom hook functions.' ); console.info( - 'Please use the getItem, setItem, and removeItem functions provided by the custom hook useLocalStorage.\n', + 'Please use the getItem, setItem, and removeItem functions provided by the custom hook useLocalStorage.\n' ); process.exit(1); diff --git a/src/App.tsx b/src/App.tsx index f78778bb1a..fbb394bc9d 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -30,7 +30,7 @@ import CommunityProfile from 'screens/CommunityProfile/CommunityProfile'; import OrganizationVenues from 'screens/OrganizationVenues/OrganizationVenues'; import Leaderboard from 'screens/Leaderboard/Leaderboard'; -import React from 'react'; +import React, { useEffect } from 'react'; // User Portal Components import Donate from 'screens/UserPortal/Donate/Donate'; import Events from 'screens/UserPortal/Events/Events'; @@ -38,16 +38,21 @@ import Posts from 'screens/UserPortal/Posts/Posts'; import Organizations from 'screens/UserPortal/Organizations/Organizations'; import People from 'screens/UserPortal/People/People'; import Settings from 'screens/UserPortal/Settings/Settings'; -import Chat from 'screens/UserPortal/Chat/Chat'; +// 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 useLocalStorage from 'utils/useLocalstorage'; import UserScreen from 'screens/UserPortal/UserScreen/UserScreen'; import EventDashboardScreen from 'components/EventDashboardScreen/EventDashboardScreen'; import Campaigns from 'screens/UserPortal/Campaigns/Campaigns'; import Pledges from 'screens/UserPortal/Pledges/Pledges'; import VolunteerManagement from 'screens/UserPortal/Volunteer/VolunteerManagement'; +import LeaveOrganization from 'screens/UserPortal/LeaveOrganization/LeaveOrganization'; -// const { setItem } = useLocalStorage(); +const { setItem } = useLocalStorage(); /** * This is the main function for our application. It sets up all the routes and components, @@ -92,20 +97,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); + 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]); + useEffect(() => { + if (!loading && data?.checkAuth) { + const auth = data.checkAuth; + setItem('IsLoggedIn', 'TRUE'); + setItem('id', auth._id); + setItem('name', `${auth.firstName} ${auth.lastName}`); + setItem('FirstName', auth.firstName); + setItem('LastName', auth.lastName); + setItem('email', auth.email); + setItem('Email', auth.email); + setItem('UserImage', auth.image); + } + }, [data, loading, setItem]); const extraRoutes = Object.entries(installedPlugins).map( ( @@ -192,9 +198,12 @@ function app(): JSX.Element { } /> } /> } /> - } /> } /> } /> + } + /> } @@ -207,6 +216,7 @@ function app(): JSX.Element { + {/* */} } /> diff --git a/src/GraphQl/Queries/AgendaCategoryQueries.ts b/src/GraphQl/Queries/AgendaCategoryQueries.ts index f766337c22..dc68afad39 100644 --- a/src/GraphQl/Queries/AgendaCategoryQueries.ts +++ b/src/GraphQl/Queries/AgendaCategoryQueries.ts @@ -8,8 +8,14 @@ import gql from 'graphql-tag'; */ export const AGENDA_ITEM_CATEGORY_LIST = gql` - query AgendaItemCategoriesByOrganization($organizationId: ID!) { - agendaItemCategoriesByOrganization(organizationId: $organizationId) { + query AgendaItemCategoriesByOrganization( + $organizationId: ID! + $where: AgendaItemCategoryWhereInput + ) { + agendaItemCategoriesByOrganization( + organizationId: $organizationId + where: $where + ) { _id name description diff --git a/src/assets/svgs/agenda-items.svg b/src/assets/svgs/agenda-items.svg index b38e571a5a..343d1808b4 100644 --- a/src/assets/svgs/agenda-items.svg +++ b/src/assets/svgs/agenda-items.svg @@ -1 +1 @@ -notebook +notebook diff --git a/src/components/AddOn/core/AddOnEntry/AddOnEntry.tsx b/src/components/AddOn/core/AddOnEntry/AddOnEntry.tsx index e2971fee14..0d317266d9 100644 --- a/src/components/AddOn/core/AddOnEntry/AddOnEntry.tsx +++ b/src/components/AddOn/core/AddOnEntry/AddOnEntry.tsx @@ -104,19 +104,8 @@ function addOnEntry({ <> - {/* {uninstalledOrgs.includes(currentOrg) && ( - {}} - disabled={switchInProgress} - checked={enabled} - /> - )} */} {title} diff --git a/src/components/AddOn/core/AddOnStore/AddOnStore.module.css b/src/components/AddOn/core/AddOnStore/AddOnStore.module.css deleted file mode 100644 index 9f5bb6c868..0000000000 --- a/src/components/AddOn/core/AddOnStore/AddOnStore.module.css +++ /dev/null @@ -1,72 +0,0 @@ -.container { - display: flex; -} - -.logintitle { - color: #707070; - font-weight: 600; - font-size: 20px; - margin-bottom: 30px; - padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; - width: 15%; -} -.input { - display: flex; - position: relative; - width: 560px; -} -/* .actioninput { - text-decoration: none; - margin-bottom: 50px; - border-color: #e8e5e5; - width: 80%; - border-radius: 7px; - padding-top: 5px; - padding-bottom: 5px; - padding-right: 10px; - padding-left: 10px; - box-shadow: none; -} */ -.actioninput { - margin-top: 10px; - margin-bottom: 10px; - background-color: white; - box-shadow: 0 1px 1px #31bb6b; -} -.inputField > button { - padding-top: 10px; - padding-bottom: 10px; -} - -.actionradio input { - width: fit-content; - margin: inherit; -} -.cardGridItem { - width: 38vw; -} -.justifysp { - display: grid; - width: 100%; - justify-content: space-between; - align-items: baseline; - grid-template-rows: auto; - grid-template-columns: repeat(2, 1fr); - grid-gap: 0.8rem 0.4rem; -} - -@media screen and (max-width: 600px) { - .cardGridItem { - width: 100%; - } - .justifysp { - display: grid; - width: 100%; - justify-content: center; - align-items: start; - grid-template-rows: auto; - grid-template-columns: 1fr; - grid-gap: 0.8rem 0.4rem; - } -} diff --git a/src/components/AddOn/core/AddOnStore/AddOnStore.spec.tsx b/src/components/AddOn/core/AddOnStore/AddOnStore.spec.tsx index 9a7eb08e1b..b357309893 100644 --- a/src/components/AddOn/core/AddOnStore/AddOnStore.spec.tsx +++ b/src/components/AddOn/core/AddOnStore/AddOnStore.spec.tsx @@ -155,18 +155,6 @@ const PLUGIN_GET_MOCK = { }, }; -const PLUGIN_LOADING_MOCK = { - request: { - query: PLUGIN_GET, - }, - result: { - data: { - getPlugins: [], - }, - loading: true, - }, -}; - vi.mock('react-router-dom', async () => { const actualModule = await vi.importActual('react-router-dom'); return { @@ -310,15 +298,13 @@ describe('Testing AddOnStore Component', () => { expect(message.length).toBeGreaterThanOrEqual(1); }); - test('AddOnStore loading test', async () => { - expect(true).toBe(true); - const mocks = [ORGANIZATIONS_LIST_MOCK, PLUGIN_LOADING_MOCK]; + test('renders loader while loading', async () => { render( - + @@ -327,6 +313,226 @@ describe('Testing AddOnStore Component', () => { , ); + // Simulate loading state expect(screen.getByTestId('AddOnEntryStore')).toBeInTheDocument(); }); + + test('renders available plugins by default', async () => { + const mocks = [ + { + request: { + query: PLUGIN_GET, + }, + result: { + data: { + getPlugins: [ + { + _id: '1', + pluginName: 'Plugin 1', + pluginDesc: 'Desc 1', + pluginCreatedBy: 'User 1', + uninstalledOrgs: [], + installed: false, + enabled: true, + }, + ], + }, + }, + }, + ]; + + render( + + + + + + + + + + + , + ); + + await wait(); + + // Ensure plugin is displayed + expect(screen.getAllByText('Plugin 1')).toHaveLength(2); + }); + + test('switches to installed tab and displays plugins', async () => { + const mocks = [ + { + request: { + query: PLUGIN_GET, + }, + result: { + data: { + getPlugins: [ + { + _id: '2', + pluginName: 'Plugin 2', + pluginDesc: 'Desc 2', + pluginCreatedBy: 'User 2', + uninstalledOrgs: [], + installed: true, + enabled: false, + }, + ], + }, + }, + }, + ]; + + render( + + + + + + + + + + + , + ); + + await wait(); + + // Switch to installed tab + const installedTab = screen.getByText('Installed'); + fireEvent.click(installedTab); + + // Ensure installed plugin is displayed + expect(screen.getAllByText('Plugin 2')).toHaveLength(2); + }); + + test('filters plugins based on search input', async () => { + const mocks = [ + { + request: { + query: PLUGIN_GET, + }, + result: { + data: { + getPlugins: [ + { + _id: '1', + pluginName: 'Test Plugin', + pluginDesc: 'Description', + pluginCreatedBy: 'User', + uninstalledOrgs: [], + installed: false, + enabled: true, + }, + ], + }, + }, + }, + ]; + + render( + + + + + + + + + + + , + ); + + await wait(); + + const searchInput = screen.getByPlaceholderText('Ex: Donations'); + fireEvent.change(searchInput, { target: { value: 'Test' } }); + + // Ensure the filtered plugin is displayed + const plugins = screen.getAllByText('Test Plugin'); + expect(plugins).toHaveLength(2); + }); + + test('shows a message when no plugins match the search', async () => { + render( + + + + + + + + + + + , + ); + + await wait(); + + const elements = screen.getAllByText('Plugin does not exists'); + expect(elements).toHaveLength(2); // Ensure there are exactly 2 matching elements + }); + + test('sets showEnabled based on dropdown value', async () => { + const mocks = [ + { + request: { query: PLUGIN_GET }, + result: { + data: { + getPlugins: [ + { + _id: '1', + pluginName: 'Test Plugin 1', + pluginDesc: 'Description', + pluginCreatedBy: 'User1', + uninstalledOrgs: [], + installed: false, + enabled: true, + }, + { + _id: '2', + pluginName: 'Test Plugin 2', + pluginDesc: 'Description', + pluginCreatedBy: 'User2', + uninstalledOrgs: [], + installed: false, + enabled: true, + }, + ], + }, + }, + }, + ]; + render( + + + + + + + + + + + , + ); + + await wait(); + + fireEvent.click(await screen.findByText('Installed')); + + // Wait for the dropdown to appear + const dropdownToggle = await screen.findByTestId('filter-dropdown'); + fireEvent.click(dropdownToggle); + + // Click 'disabled' item + // fireEvent.click(await screen.findByText('Disabled')); + + expect(dropdownToggle.textContent).toBe('Enabled'); + }); }); diff --git a/src/components/AddOn/core/AddOnStore/AddOnStore.tsx b/src/components/AddOn/core/AddOnStore/AddOnStore.tsx index 90a32d9bb3..3da19f8a51 100644 --- a/src/components/AddOn/core/AddOnStore/AddOnStore.tsx +++ b/src/components/AddOn/core/AddOnStore/AddOnStore.tsx @@ -1,5 +1,5 @@ import React, { useState } from 'react'; -import styles from './AddOnStore.module.css'; +import styles from '../../../../style/app.module.css'; import AddOnEntry from '../AddOnEntry/AddOnEntry'; import { useQuery } from '@apollo/client'; import { PLUGIN_GET } from 'GraphQl/Queries/Queries'; // PLUGIN_LIST @@ -122,36 +122,19 @@ function addOnStore(): JSX.Element { return ( <> - - -
+ + +
setSearchText(e.target.value)} /> -
@@ -199,7 +182,7 @@ function addOnStore(): JSX.Element { title={t('available')} style={{ backgroundColor: 'white' }} > -
+
{(() => { const filteredPlugins = filterPlugins( data?.getPlugins || [], @@ -211,7 +194,7 @@ function addOnStore(): JSX.Element { } return ( -
+
{filteredPlugins.map((plug, i) => (
-
+
{(() => { const installedPlugins = (data?.getPlugins || []).filter( (plugin) => !plugin.uninstalledOrgs.includes(orgId ?? ''), diff --git a/src/components/AddPeopleToTag/AddPeopleToTag.test.tsx b/src/components/AddPeopleToTag/AddPeopleToTag.spec.tsx similarity index 86% rename from src/components/AddPeopleToTag/AddPeopleToTag.test.tsx rename to src/components/AddPeopleToTag/AddPeopleToTag.spec.tsx index 824bc25654..8867335017 100644 --- a/src/components/AddPeopleToTag/AddPeopleToTag.test.tsx +++ b/src/components/AddPeopleToTag/AddPeopleToTag.spec.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { vi, expect, describe, it } from 'vitest'; import { MockedProvider } from '@apollo/react-testing'; import type { RenderResult } from '@testing-library/react'; import { @@ -10,7 +11,7 @@ import { } from '@testing-library/react'; import { Provider } from 'react-redux'; import { MemoryRouter, Route, Routes } from 'react-router-dom'; -import 'jest-location-mock'; + import { I18nextProvider } from 'react-i18next'; import { store } from 'state/store'; @@ -34,10 +35,10 @@ async function wait(): Promise { }); } -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - error: jest.fn(), + success: vi.fn(), + error: vi.fn(), }, })); @@ -114,19 +115,25 @@ const renderAddPeopleToTagModal = ( describe('Organisation Tags Page', () => { beforeEach(() => { - jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: 'orgId' }), - })); - cache.reset(); + // Mocking `react-router-dom` to return the actual module and override `useParams` + vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); // Import the actual module + return { + ...actual, + useParams: () => ({ orgId: '1', tagId: '1' }), // Mock `useParams` to return a custom object + }; + }); + + // Reset any necessary cache or mocks + vi.clearAllMocks(); // Clear all mocks to ensure a clean state before each test }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); cleanup(); }); - test('Component loads correctly', async () => { + it('Component loads correctly', async () => { const { getByText } = renderAddPeopleToTagModal(props, link); await wait(); @@ -136,7 +143,7 @@ describe('Organisation Tags Page', () => { }); }); - test('Renders error component when when query is unsuccessful', async () => { + it('Renders error component when when query is unsuccessful', async () => { const { queryByText } = renderAddPeopleToTagModal(props, link2); await wait(); @@ -146,7 +153,7 @@ describe('Organisation Tags Page', () => { }); }); - test('Selects and deselects members to assign to', async () => { + it('Selects and deselects members to assign to', async () => { renderAddPeopleToTagModal(props, link); await wait(); @@ -174,7 +181,7 @@ describe('Organisation Tags Page', () => { userEvent.click(screen.getAllByTestId('deselectMemberBtn')[0]); }); - test('searchs for tags where the firstName matches the provided firstName search input', async () => { + it('searchs for tags where the firstName matches the provided firstName search input', async () => { renderAddPeopleToTagModal(props, link); await wait(); @@ -207,7 +214,7 @@ describe('Organisation Tags Page', () => { }); }); - test('searchs for tags where the lastName matches the provided lastName search input', async () => { + it('searchs for tags where the lastName matches the provided lastName search input', async () => { renderAddPeopleToTagModal(props, link); await wait(); @@ -240,7 +247,7 @@ describe('Organisation Tags Page', () => { }); }); - test('Renders more members with infinite scroll', async () => { + it('Renders more members with infinite scroll', async () => { const { getByText } = renderAddPeopleToTagModal(props, link); await wait(); @@ -269,7 +276,7 @@ describe('Organisation Tags Page', () => { }); }); - test('Toasts error when no one is selected while assigning', async () => { + it('Toasts error when no one is selected while assigning', async () => { renderAddPeopleToTagModal(props, link); await wait(); @@ -284,7 +291,7 @@ describe('Organisation Tags Page', () => { }); }); - test('Assigns tag to multiple people', async () => { + it('Assigns tag to multiple people', async () => { renderAddPeopleToTagModal(props, link); await wait(); diff --git a/src/components/Advertisements/Advertisements.module.css b/src/components/Advertisements/Advertisements.module.css deleted file mode 100644 index 6d9eb7f612..0000000000 --- a/src/components/Advertisements/Advertisements.module.css +++ /dev/null @@ -1,47 +0,0 @@ -.container { - display: flex; -} -.listBox { - display: grid; - width: 100%; - grid-template-rows: auto; - grid-template-columns: repeat(6, 1fr); - grid-gap: 0.8rem 0.4rem; -} - -.logintitle { - color: #707070; - font-weight: 600; - font-size: 20px; - margin-bottom: 30px; - padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; - width: 15%; -} -.input { - display: flex; - position: relative; - width: 560px; -} -.justifysp { - display: grid; - width: 100%; - margin-top: 30px; -} -.actioninput { - text-decoration: none; - /* margin-bottom: 50px; */ - border-color: #e8e5e5; - background-color: white; - border-radius: 7px; - padding-top: 10px; - padding-bottom: 10px; - padding-right: 10px; - padding-left: 10px; - box-shadow: none; -} - -.actionradio input { - width: fit-content; - margin: inherit; -} diff --git a/src/components/Advertisements/Advertisements.tsx b/src/components/Advertisements/Advertisements.tsx index 5f0e2b2033..f428b569a0 100644 --- a/src/components/Advertisements/Advertisements.tsx +++ b/src/components/Advertisements/Advertisements.tsx @@ -1,5 +1,5 @@ import React, { useEffect, useState } from 'react'; -import styles from './Advertisements.module.css'; +import styles from '../../style/app.module.css'; import { useQuery } from '@apollo/client'; import { ORGANIZATION_ADVERTISEMENT_LIST } from 'GraphQl/Queries/Queries'; import { Button, Col, Form, Row, Tab, Tabs } from 'react-bootstrap'; @@ -79,29 +79,20 @@ export default function advertisements(): JSX.Element { return ( <> - -
- -
+ +
+ +
setSearchText("search")} /> -
@@ -145,7 +136,7 @@ export default function advertisements(): JSX.Element { orgAdvertisementListData?.organizations[0].advertisements .pageInfo.hasNextPage ?? false } - className={styles.listBox} + className={styles.listBoxAdvertisements} data-testid="organizations-list" endMessage={ advertisements.filter( @@ -221,7 +212,7 @@ export default function advertisements(): JSX.Element { orgAdvertisementListData?.organizations[0].advertisements .pageInfo.hasNextPage ?? false } - className={styles.listBox} + className={styles.listBoxAdvertisements} data-testid="organizations-list" endMessage={ advertisements.filter( diff --git a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.module.css b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.module.css deleted file mode 100644 index 9d009cf021..0000000000 --- a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.module.css +++ /dev/null @@ -1,57 +0,0 @@ -.modalbtn { - margin-top: 1rem; - display: flex !important; - margin-left: auto; - align-items: center; -} - -.modalbtn i, -.button i { - height: min-content; - margin-right: 4px; -} - -.preview { - display: flex; - position: relative; - width: 100%; - margin-top: 10px; - justify-content: center; -} -.preview img { - width: 400px; - height: auto; -} -.preview video { - width: 400px; - height: auto; -} - -.closeButton { - position: absolute; - top: 0px; - right: 0px; - background: transparent; - transform: scale(1.2); - cursor: pointer; - border: none; - color: #707070; - font-weight: 600; - font-size: 16px; - cursor: pointer; -} - -.button { - min-width: 102px; -} - -.editHeader { - background-color: #31bb6b; - color: white; -} - -.link_check { - display: flex; - justify-content: center; - align-items: flex-start; -} diff --git a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.tsx b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.tsx index c347ae8959..e329ce6855 100644 --- a/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.tsx +++ b/src/components/Advertisements/core/AdvertisementRegister/AdvertisementRegister.tsx @@ -314,7 +314,10 @@ function advertisementRegister({ }} /> {formState.advertisementMedia && ( -
+
{formState.advertisementMedia.includes('video') ? (
-
+
{renderMonthDays()}
diff --git a/src/components/EventListCard/EventListCard.module.css b/src/components/EventListCard/EventListCard.module.css deleted file mode 100644 index 1e47972a42..0000000000 --- a/src/components/EventListCard/EventListCard.module.css +++ /dev/null @@ -1,223 +0,0 @@ -.cards h2 { - font-size: 15px; - color: #4e4c4c; - font-weight: 500; -} -.cards > h3 { - font-size: 17px; -} -.cards > p { - font-size: 14px; - margin-top: 0px; - margin-bottom: 7px; -} -.cards a { - color: #fff; - font-weight: 600; -} -.cards a:hover { - color: black; -} -.cards { - position: relative; - overflow: hidden; - transition: all 0.3s; - margin-bottom: 5px; -} -.dispflex { - display: flex; - cursor: pointer; - justify-content: space-between; - margin: 10px 5px 5px 0px; -} -.eventtitle { - margin-bottom: 0px; - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; -} -.iconContainer { - display: flex; - justify-content: flex-end; -} -.icon { - margin: 2px; -} - -.cards { - width: 100%; - background: #5cacf7 !important; - padding: 2px 3px; - border-radius: 5px; - border: 1px solid #e8e8e8; - box-shadow: 0 3px 2px #e8e8e8; - color: #737373; - box-sizing: border-box; -} -.cards:last-child:nth-last-child(odd) { - grid-column: auto / span 2; -} - -.cards:first-child:nth-last-child(even), -.cards:first-child:nth-last-child(even) ~ .box { - grid-column: auto / span 1; -} - -.sidebarsticky > input { - text-decoration: none; - margin-bottom: 50px; - border-color: #e8e5e5; - width: 80%; - border-radius: 7px; - padding-top: 5px; - padding-bottom: 5px; - padding-right: 10px; - padding-left: 10px; - box-shadow: none; -} -.datediv { - display: flex; - flex-direction: row; - margin-top: 5px; - margin-bottom: 5px; -} -.datebox { - width: 90%; - border-radius: 7px; - border-color: #e8e5e5; - outline: none; - box-shadow: none; - padding-top: 2px; - padding-bottom: 2px; - padding-right: 5px; - padding-left: 5px; -} -.datediv > div > p { - margin-bottom: 0.5rem; -} - -.startDate { - margin-right: 0.25rem; -} -.endDate { - margin-left: 1.5rem; -} - -.checkboxdiv > div label { - margin-right: 50px; -} -.checkboxdiv > label > input { - margin-left: 10px; -} - -.dispflex > input { - width: 20%; - border: none; - box-shadow: none; - margin-top: 5px; -} - -.checkboxContainer { - display: flex; - justify-content: space-between; -} - -.checkboxdiv { - display: flex; - flex-direction: column; -} - -.preview { - display: flex; - flex-direction: row; - font-weight: 700; - font-size: 16px; - color: #000000; - margin: 0; -} -.view { - margin-left: 2%; - font-weight: 600; - font-size: 16px; - color: #707070; -} -.flexdir { - display: flex; - flex-direction: row; - justify-content: space-between; - border: none; -} - -.form_wrapper { - margin-top: 27px; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - position: absolute; - display: flex; - flex-direction: column; - padding: 20px 30px; - background: #ffffff; - border-color: #e8e5e5; - border-width: 5px; - border-radius: 10px; - width: 40%; -} - -.form_wrapper form { - display: flex; - align-items: left; - justify-content: left; - flex-direction: column; -} -.titlemodal { - color: #000000; - font-weight: 600; - font-size: 24px; - margin-bottom: 20px; - padding-bottom: 5px; - border-bottom: 4px solid #31bb6b; - width: 50%; -} -.cancel > i { - margin-top: 5px; - transform: scale(1.2); - cursor: pointer; - color: #707070; -} -.modalbody { - width: 50px; -} -.list_box { - height: 70vh; - overflow-y: auto; - width: auto; -} -@media only screen and (max-width: 600px) { - .form_wrapper { - width: 90%; - top: 45%; - } - .checkboxContainer { - flex-direction: column; - } - - .datediv { - flex-direction: column; - } - - .datediv > div { - width: 100%; - margin-left: 0; - margin-bottom: 10px; - } - - .datediv > div p { - margin-bottom: 5px; - } -} - -.customButton { - width: 90%; - margin: 0 auto; -} diff --git a/src/components/EventListCard/EventListCard.tsx b/src/components/EventListCard/EventListCard.tsx index ffa508ff7c..dba2ef4541 100644 --- a/src/components/EventListCard/EventListCard.tsx +++ b/src/components/EventListCard/EventListCard.tsx @@ -1,6 +1,6 @@ import React, { useState } from 'react'; import { useTranslation } from 'react-i18next'; -import styles from './EventListCard.module.css'; +import styles from '../../style/app.module.css'; import { Navigate, useParams } from 'react-router-dom'; import EventListCardModals from './EventListCardModals'; import type { InterfaceRecurrenceRule } from 'utils/recurrenceUtils'; @@ -74,14 +74,14 @@ function eventListCard(props: InterfaceEventListCardProps): JSX.Element { return ( <>
-
+

{props.eventName ? <>{props.eventName} : <>Dogs Care}

diff --git a/src/components/EventListCard/EventListCardModals.tsx b/src/components/EventListCard/EventListCardModals.tsx index 7755da2a5a..6f93c709fd 100644 --- a/src/components/EventListCard/EventListCardModals.tsx +++ b/src/components/EventListCard/EventListCardModals.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from 'react'; import { Button, Form, Modal, Popover } from 'react-bootstrap'; -import styles from './EventListCard.module.css'; +import styles from '../../style/app.module.css'; import { DatePicker, TimePicker } from '@mui/x-date-pickers'; import dayjs from 'dayjs'; import type { Dayjs } from 'dayjs'; @@ -401,7 +401,9 @@ function EventListCardModals({
-

{t('eventTitle')}

+

+ {t('eventTitle')} +

-

{tCommon('description')}

+

+ {tCommon('description')} +

-

{tCommon('location')}

+

+ {tCommon('location')} +

)}
-
-
+
+
-
+
-
-
+
+
-
+
{ , ); - - await wait(); - await waitFor(() => { expect(getByText(translations.createAgendaItem)).toBeInTheDocument(); }); @@ -117,9 +113,6 @@ describe('Testing Agenda Items Components', () => { , ); - - await wait(); - await waitFor(() => { expect( queryByText(translations.createAgendaItem), @@ -142,8 +135,6 @@ describe('Testing Agenda Items Components', () => { , ); - await wait(); - await waitFor(() => { expect(screen.getByTestId('createAgendaItemBtn')).toBeInTheDocument(); }); @@ -160,6 +151,7 @@ describe('Testing Agenda Items Components', () => { screen.queryByTestId('createAgendaItemModalCloseBtn'), ); }); + it('creates new agenda item', async () => { render( diff --git a/src/components/EventManagement/EventAttendance/EventAttendance.tsx b/src/components/EventManagement/EventAttendance/EventAttendance.tsx index 06b047a973..57ce357835 100644 --- a/src/components/EventManagement/EventAttendance/EventAttendance.tsx +++ b/src/components/EventManagement/EventAttendance/EventAttendance.tsx @@ -312,12 +312,12 @@ function EventAttendance(): JSX.Element { componentsProps={{ tooltip: { sx: { - backgroundColor: 'white', + backgroundColor: 'var(--bs-white)', fontSize: '2em', maxHeight: '170px', overflowY: 'scroll', scrollbarColor: 'white', - border: '1px solid green', + border: 'var(--primary-border-solid)', borderRadius: '6px', boxShadow: '0 0 5px rgba(0,0,0,0.1)', }, diff --git a/src/components/EventManagement/EventRegistrant/EventRegistrants.tsx b/src/components/EventManagement/EventRegistrant/EventRegistrants.tsx index efcc2e91f7..d6488025ac 100644 --- a/src/components/EventManagement/EventRegistrant/EventRegistrants.tsx +++ b/src/components/EventManagement/EventRegistrant/EventRegistrants.tsx @@ -9,7 +9,7 @@ import { } from '@mui/material'; import { Button, Table } from 'react-bootstrap'; import { useTranslation } from 'react-i18next'; -import style from '../../../style/app.module.css'; +import styles from '../../../style/app.module.css'; import { useLazyQuery } from '@apollo/client'; import { EVENT_ATTENDEES, EVENT_REGISTRANTS } from 'GraphQl/Queries/Queries'; import { useParams } from 'react-router-dom'; @@ -112,7 +112,7 @@ function EventRegistrants(): JSX.Element { )}
- + - + @@ -137,25 +137,25 @@ function EventRegistrants(): JSX.Element { {t('registrant')} {t('registeredAt')} {t('createdAt')} {t('addRegistrant')} diff --git a/src/components/EventRegistrantsModal/AddOnSpotAttendee.spec.tsx b/src/components/EventRegistrantsModal/AddOnSpotAttendee.spec.tsx index 66f0dda38b..a3c207a2e1 100644 --- a/src/components/EventRegistrantsModal/AddOnSpotAttendee.spec.tsx +++ b/src/components/EventRegistrantsModal/AddOnSpotAttendee.spec.tsx @@ -98,20 +98,86 @@ describe('AddOnSpotAttendee Component', () => { expect(screen.getByLabelText('Gender')).toBeInTheDocument(); }); - it('handles form input changes correctly', async () => { - renderAddOnSpotAttendee(); + it('handles case where signUp response is undefined', async () => { + const mockWithoutSignUp = [ + { + request: { + query: SIGNUP_MUTATION, + variables: { + firstName: 'John', + lastName: 'Doe', + email: 'john@example.com', + phoneNo: '1234567890', + gender: 'Male', + password: '123456', + orgId: '123', + }, + }, + result: { + data: {}, // No signUp property + }, + }, + ]; + + render( + + + + + + + + + , + ); + + userEvent.type(screen.getByLabelText('First Name'), 'John'); + userEvent.type(screen.getByLabelText('Last Name'), 'Doe'); + userEvent.type(screen.getByLabelText('Email'), 'john@example.com'); + userEvent.type(screen.getByLabelText('Phone No.'), '1234567890'); + const genderSelect = screen.getByLabelText('Gender'); + fireEvent.change(genderSelect, { target: { value: 'Male' } }); + + fireEvent.submit(screen.getByTestId('onspot-attendee-form')); - const firstNameInput = screen.getByLabelText('First Name'); - const lastNameInput = screen.getByLabelText('Last Name'); - const emailInput = screen.getByLabelText('Email'); + await waitFor(() => { + expect(toast.success).not.toHaveBeenCalled(); // Ensure success toast is not shown + expect(toast.error).not.toHaveBeenCalled(); // Ensure no unexpected error toast + expect(mockProps.reloadMembers).not.toHaveBeenCalled(); // Reload should not be triggered + expect(mockProps.handleClose).not.toHaveBeenCalled(); // Modal should not close + }); + }); - userEvent.type(firstNameInput, 'John'); - userEvent.type(lastNameInput, 'Doe'); - userEvent.type(emailInput, 'john@example.com'); + it('handles error during form submission', async () => { + render( + + + + + + + + + , + ); + + // Fill the form + userEvent.type(screen.getByLabelText('First Name'), 'John'); + userEvent.type(screen.getByLabelText('Last Name'), 'Doe'); + userEvent.type(screen.getByLabelText('Email'), 'john@example.com'); + userEvent.type(screen.getByLabelText('Phone No.'), '1234567890'); + const genderSelect = screen.getByLabelText('Gender'); + fireEvent.change(genderSelect, { target: { value: 'Male' } }); + + // Submit the form + fireEvent.submit(screen.getByTestId('onspot-attendee-form')); - expect(firstNameInput).toHaveValue('John'); - expect(lastNameInput).toHaveValue('Doe'); - expect(emailInput).toHaveValue('john@example.com'); + // Wait for the error to be handled + await waitFor(() => { + expect(toast.error).toHaveBeenCalledWith( + expect.stringContaining('Failed to add attendee'), + ); + }); }); it('submits form successfully and calls necessary callbacks', async () => { diff --git a/src/components/LeftDrawer/LeftDrawer.test.tsx b/src/components/LeftDrawer/LeftDrawer.spec.tsx similarity index 90% rename from src/components/LeftDrawer/LeftDrawer.test.tsx rename to src/components/LeftDrawer/LeftDrawer.spec.tsx index a4ad1cc47a..dc22717e3d 100644 --- a/src/components/LeftDrawer/LeftDrawer.test.tsx +++ b/src/components/LeftDrawer/LeftDrawer.spec.tsx @@ -1,10 +1,8 @@ import React, { act } from 'react'; import { fireEvent, render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import 'jest-localstorage-mock'; import { I18nextProvider } from 'react-i18next'; import { BrowserRouter } from 'react-router-dom'; - import i18nForTest from 'utils/i18nForTest'; import type { InterfaceLeftDrawerProps } from './LeftDrawer'; import LeftDrawer from './LeftDrawer'; @@ -12,12 +10,13 @@ import { REVOKE_REFRESH_TOKEN } from 'GraphQl/Mutations/mutations'; import { StaticMockLink } from 'utils/StaticMockLink'; import { MockedProvider } from '@apollo/react-testing'; import useLocalStorage from 'utils/useLocalstorage'; +import { vi, it, describe, beforeEach, afterEach, expect } from 'vitest'; const { setItem } = useLocalStorage(); const props = { hideDrawer: true, - setHideDrawer: jest.fn(), + setHideDrawer: vi.fn(), }; const resizeWindow = (width: number): void => { @@ -40,11 +39,11 @@ const MOCKS = [ const link = new StaticMockLink(MOCKS, true); -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - warn: jest.fn(), - error: jest.fn(), + success: vi.fn(), + warn: vi.fn(), + error: vi.fn(), }, })); @@ -58,12 +57,12 @@ beforeEach(() => { }); afterEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); localStorage.clear(); }); describe('Testing Left Drawer component for SUPERADMIN', () => { - test('Component should be rendered properly', async () => { + it('Component should be rendered properly', async () => { setItem('UserImage', ''); setItem('SuperAdmin', true); setItem('FirstName', 'John'); @@ -113,7 +112,7 @@ describe('Testing Left Drawer component for SUPERADMIN', () => { }); }); - test('Testing Drawer when hideDrawer is null', async () => { + it('Testing Drawer when hideDrawer is null', async () => { const tempProps: InterfaceLeftDrawerProps = { ...props, hideDrawer: false, @@ -132,7 +131,7 @@ describe('Testing Left Drawer component for SUPERADMIN', () => { }); }); - test('Testing Drawer when hideDrawer is false', async () => { + it('Testing Drawer when hideDrawer is false', async () => { const tempProps: InterfaceLeftDrawerProps = { ...props, hideDrawer: false, @@ -151,7 +150,7 @@ describe('Testing Left Drawer component for SUPERADMIN', () => { }); }); - test('Testing Drawer when the screen size is less than or equal to 820px', async () => { + it('Testing Drawer when the screen size is less than or equal to 820px', async () => { const tempProps: InterfaceLeftDrawerProps = { ...props, hideDrawer: false, @@ -184,7 +183,7 @@ describe('Testing Left Drawer component for SUPERADMIN', () => { }); describe('Testing Left Drawer component for ADMIN', () => { - test('Components should be rendered properly', async () => { + it('Components should be rendered properly', async () => { await act(async () => { render( diff --git a/src/components/LeftDrawerOrg/LeftDrawerOrg.module.css b/src/components/LeftDrawerOrg/LeftDrawerOrg.module.css deleted file mode 100644 index 6296b1aa73..0000000000 --- a/src/components/LeftDrawerOrg/LeftDrawerOrg.module.css +++ /dev/null @@ -1,362 +0,0 @@ -.leftDrawer { - width: calc(300px + 2rem); - min-height: 100%; - position: fixed; - top: 0; - bottom: 0; - z-index: 100; - display: flex; - flex-direction: column; - padding: 0.8rem 0rem 0 1rem; - background-color: #f6f8fc; - transition: 0.5s; - font-family: var(--bs-leftDrawer-font-family); -} - -.avatarContainer { - display: flex; - justify-content: center; - align-items: center; - margin: 1rem 0; - width: 75%; - height: 75%; -} - -.activeDrawer { - width: calc(300px + 2rem); - position: fixed; - top: 0; - left: 0; - bottom: 0; - animation: comeToRightBigScreen 0.5s ease-in-out; -} - -.inactiveDrawer { - position: fixed; - top: 0; - left: calc(-300px - 2rem); - bottom: 0; - animation: goToLeftBigScreen 0.5s ease-in-out; -} - -.leftDrawer .brandingContainer { - display: flex; - justify-content: flex-start; - align-items: center; -} - -.leftDrawer .organizationContainer button { - position: relative; - margin: 0.7rem 0; - padding: 2.5rem 0.1rem; - border-radius: 16px; -} - -.leftDrawer .talawaLogo { - width: 50px; - height: 50px; - margin-right: 0.3rem; -} - -.leftDrawer .talawaText { - font-size: 18px; - font-weight: 500; -} - -.leftDrawer .titleHeader { - font-weight: 600; - margin: 0.6rem 0rem; -} - -.leftDrawer .optionList { - height: 100%; - overflow-y: scroll; - padding-bottom: 1.5rem; -} - -.leftDrawer .optionList button { - display: flex; - align-items: center; - width: 100%; - text-align: start; - margin-bottom: 0.8rem; - border-radius: 16px; - font-size: 16px; - padding: 0.6rem; - padding-left: 0.8rem; - outline: none; - border: none; -} - -.leftDrawer button .iconWrapper { - width: 36px; -} - -.leftDrawer .optionList .collapseBtn { - height: 48px; - border: none; -} - -.leftDrawer button .iconWrapperSm { - width: 36px; - display: flex; - justify-content: center; - align-items: center; -} - -.leftDrawer .organizationContainer .profileContainer { - background-color: #e0e9ff; - padding-right: 10px; -} - -.leftDrawer .profileContainer { - border: none; - width: 100%; - height: 52px; - border-radius: 16px; - display: flex; - align-items: center; - background-color: var(--bs-white); -} - -.leftDrawer .profileContainer:focus { - outline: none; -} - -.leftDrawer .imageContainer { - width: 68px; - margin-left: 0.75rem; - margin-right: 8px; -} - -.leftDrawer .profileContainer img { - height: 52px; - width: 52px; - border-radius: 50%; -} - -.leftDrawer .profileContainer .profileText { - flex: 1; - text-align: start; - overflow: hidden; -} - -.leftDrawer .profileContainer .profileText .primaryText { - font-size: 1.1rem; - font-weight: 600; - overflow: hidden; - display: -webkit-box; - -webkit-line-clamp: 2; /* number of lines to show */ - -webkit-box-orient: vertical; - word-wrap: break-word; - white-space: normal; -} - -.leftDrawer .profileContainer .profileText .secondaryText { - font-size: 0.8rem; - font-weight: 400; - /* color: var(--bs-secondary); */ - display: block; - text-transform: capitalize; -} - -@media (max-width: 1120px) { - .leftDrawer { - width: calc(250px + 2rem); - padding: 1rem 0rem 0 1rem; - } -} - -/* For tablets */ -@media (max-height: 900px) { - .leftDrawer { - width: calc(300px + 1rem); - } - .leftDrawer .talawaLogo { - width: 38px; - height: 38px; - margin-right: 0.4rem; - } - .leftDrawer .talawaText { - font-size: 1rem; - } - .leftDrawer .organizationContainer button { - margin: 0.6rem 0; - padding: 2.2rem 0.1rem; - } - .leftDrawer .optionList button { - margin-bottom: 0.05rem; - font-size: 16px; - padding-left: 0.8rem; - } - .leftDrawer .profileContainer .profileText .primaryText { - font-size: 1rem; - } - .leftDrawer .profileContainer .profileText .secondaryText { - font-size: 0.8rem; - } -} -@media (max-height: 650px) { - .leftDrawer { - padding: 0.5rem 0rem 0 0.8rem; - width: calc(250px); - } - .leftDrawer .talawaText { - font-size: 0.8rem; - } - .leftDrawer .organizationContainer button { - margin: 0.2rem 0; - padding: 1.6rem 0rem; - } - .leftDrawer .titleHeader { - font-size: 16px; - } - .leftDrawer .optionList button { - margin-bottom: 0.05rem; - font-size: 14px; - padding: 0.4rem; - padding-left: 0.8rem; - } - .leftDrawer .profileContainer .profileText .primaryText { - font-size: 0.8rem; - } - .leftDrawer .profileContainer .profileText .secondaryText { - font-size: 0.6rem; - } - .leftDrawer .imageContainer { - width: 40px; - margin-left: 0.75rem; - margin-right: 12px; - } - .leftDrawer .imageContainer img { - width: 40px; - height: 100%; - } -} - -@media (max-width: 820px) { - .hideElemByDefault { - display: none; - } - - .leftDrawer { - width: 100%; - left: 0; - right: 0; - } - - .inactiveDrawer { - opacity: 0; - left: 0; - z-index: -1; - animation: closeDrawer 0.2s ease-in-out; - } - - .activeDrawer { - display: flex; - z-index: 100; - animation: openDrawer 0.4s ease-in-out; - } - - .logout { - margin-bottom: 2.5rem; - } -} - -@keyframes goToLeftBigScreen { - from { - left: 0; - } - - to { - opacity: 0.1; - left: calc(-300px - 2rem); - } -} - -/* Webkit prefix for older browser compatibility */ -@-webkit-keyframes goToLeftBigScreen { - from { - left: 0; - } - - to { - opacity: 0.1; - left: calc(-300px - 2rem); - } -} - -@keyframes comeToRightBigScreen { - from { - opacity: 0.4; - left: calc(-300px - 2rem); - } - - to { - opacity: 1; - left: 0; - } -} - -/* Webkit prefix for older browser compatibility */ -@-webkit-keyframes comeToRightBigScreen { - from { - opacity: 0.4; - left: calc(-300px - 2rem); - } - - to { - opacity: 1; - left: 0; - } -} - -@keyframes closeDrawer { - from { - left: 0; - opacity: 1; - } - - to { - left: -1000px; - opacity: 0; - } -} - -/* Webkit prefix for older browser compatibility */ -@-webkit-keyframes closeDrawer { - from { - left: 0; - opacity: 1; - } - - to { - left: -1000px; - opacity: 0; - } -} - -@keyframes openDrawer { - from { - opacity: 0; - left: -1000px; - } - - to { - left: 0; - opacity: 1; - } -} - -/* Webkit prefix for older browser compatibility */ -@-webkit-keyframes openDrawer { - from { - opacity: 0; - left: -1000px; - } - - to { - left: 0; - opacity: 1; - } -} diff --git a/src/components/LeftDrawerOrg/LeftDrawerOrg.tsx b/src/components/LeftDrawerOrg/LeftDrawerOrg.tsx index a687351c98..35173a930e 100644 --- a/src/components/LeftDrawerOrg/LeftDrawerOrg.tsx +++ b/src/components/LeftDrawerOrg/LeftDrawerOrg.tsx @@ -11,7 +11,7 @@ import type { TargetsType } from 'state/reducers/routesReducer'; import type { InterfaceQueryOrganizationsListObject } from 'utils/interfaces'; import AngleRightIcon from 'assets/svgs/angleRight.svg?react'; import TalawaLogo from 'assets/svgs/talawa.svg?react'; -import styles from './LeftDrawerOrg.module.css'; +import styles from './../../style/app.module.css'; // Import the global CSS file import Avatar from 'components/Avatar/Avatar'; import useLocalStorage from 'utils/useLocalstorage'; @@ -31,6 +31,7 @@ export interface InterfaceLeftDrawerProps { * @param setHideDrawer - Function to update the visibility state of the drawer. * @returns JSX element for the left navigation drawer with organization details. */ + const leftDrawerOrg = ({ targets, orgId, @@ -45,7 +46,9 @@ const leftDrawerOrg = ({ const getIdFromPath = (pathname: string): string => { if (!pathname) return ''; const segments = pathname.split('/'); + // Index 2 (third segment) represents the ID in paths like /member/{userId} + return segments.length > 2 ? segments[2] : ''; }; const [isProfilePage, setIsProfilePage] = useState(false); @@ -66,11 +69,13 @@ const leftDrawerOrg = ({ }); // Get the ID from the current path + const pathId = useMemo( () => getIdFromPath(location.pathname), [location.pathname], ); // Check if the current page is admin profile page + useEffect(() => { // if param id is equal to userId, then it is a profile page setIsProfilePage(pathId === userId); @@ -88,7 +93,6 @@ const leftDrawerOrg = ({ isMounted = false; }; }, [data]); - /** * Handles link click to hide the drawer on smaller screens. */ @@ -121,16 +125,14 @@ const leftDrawerOrg = ({ {/* Organization Section */}
{loading ? ( - <> - + + {t('deletePostMsg')} + + + + + + ); +}; + +export default DeletePostModal; diff --git a/src/components/OrgPostCard/OrgPostCard.module.css b/src/components/OrgPostCard/OrgPostCard.module.css deleted file mode 100644 index c7ff8073d2..0000000000 --- a/src/components/OrgPostCard/OrgPostCard.module.css +++ /dev/null @@ -1,278 +0,0 @@ -.cards h2 { - font-size: 20px; -} -.cards > h3 { - font-size: 17px; -} -.card { - width: 100%; - height: 20rem; - margin-bottom: 2rem; -} -.postimage { - border-radius: 0px; - width: 100%; - height: 12rem; - max-width: 100%; - max-height: 12rem; - object-fit: cover; - position: relative; - color: black; -} -.preview { - display: flex; - position: relative; - width: 100%; - margin-top: 10px; - justify-content: center; -} -.preview img { - width: 400px; - height: auto; -} -.preview video { - width: 400px; - height: auto; -} -.nopostimage { - border-radius: 0px; - width: 100%; - height: 12rem; - max-height: 12rem; - object-fit: cover; - position: relative; -} -.cards:hover { - filter: brightness(0.8); -} -.cards:hover::before { - opacity: 0.5; -} -.knowMoreText { - position: absolute; - top: 50%; - left: 50%; - transform: translate(-50%, -50%); - opacity: 0; - color: white; - padding: 10px; - font-weight: bold; - font-size: 1.5rem; - transition: opacity 0.3s ease-in-out; -} - -.cards:hover .knowMoreText { - opacity: 1; -} -.modal { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - display: flex; - align-items: center; - justify-content: center; - background-color: rgba( - 0, - 0, - 0, - 0.9 - ); /* Dark grey modal background with transparency */ - z-index: 9999; -} - -.modalContent { - display: flex; - align-items: center; - justify-content: center; - background-color: #fff; - padding: 20px; - max-width: 800px; - max-height: 600px; - overflow: auto; -} - -.modalImage { - flex: 1; - margin-right: 20px; - width: 25rem; - height: 15rem; -} -.nomodalImage { - flex: 1; - margin-right: 20px; - width: 100%; - height: 15rem; -} - -.modalImage img, -.modalImage video { - border-radius: 0px; - width: 100%; - height: 25rem; - max-width: 25rem; - max-height: 15rem; - object-fit: cover; - position: relative; -} -.modalInfo { - flex: 1; -} -.title { - font-size: 16px; - color: #000; - font-weight: 600; -} -.text { - font-size: 13px; - color: #000; - font-weight: 300; -} -.author { - color: #737373; - font-weight: 100; - font-size: 13px; -} -.closeButton { - position: relative; - bottom: 5rem; - right: 10px; - padding: 4px; - background-color: red; /* Red close button color */ - color: #fff; - border: none; - cursor: pointer; -} -.closeButtonP { - position: absolute; - top: 0px; - right: 0px; - background: transparent; - transform: scale(1.2); - cursor: pointer; - border: none; - color: #707070; - font-weight: 600; - font-size: 16px; - cursor: pointer; -} -.cards:hover::after { - opacity: 1; - mix-blend-mode: normal; -} -.cards > p { - font-size: 14px; - margin-top: 0px; - margin-bottom: 7px; -} -.cards a { - color: #737373; - font-weight: 600; -} -.cards a:hover { - color: black; -} -.infodiv { - margin-bottom: 7px; - width: 15rem; - text-align: justify; - word-wrap: break-word; -} -.infodiv > p { - margin: 0; -} -.dispflex { - display: flex; - justify-content: space-between; -} -.iconContainer { - display: flex; -} -.icon { - transform: scale(0.75); - cursor: pointer; -} -/* .cards { - width: 75%; - background: #fcfcfc; - margin: 10px 40px; - padding: 20px 30px; - border-radius: 5px; - border: 1px solid #e8e8e8; - box-shadow: 0 3px 5px #c9c9c9; - margin-right: 30px; - color: #737373; - box-sizing: border-box; -} */ -.cards:last-child:nth-last-child(odd) { - grid-column: auto / span 2; -} -.cards:first-child:nth-last-child(even), -.cards:first-child:nth-last-child(even) ~ .box { - grid-column: auto / span 1; -} -.toggleClickBtn { - color: #31bb6b; - cursor: pointer; - border: none; - font-size: 12px; - background-color: white; -} -.toggleClickBtnNone { - display: none; -} -/* Menu Modal Styles */ -.menuModal { - position: fixed; - top: 0; - left: 0; - width: 100%; - height: 100%; - display: flex; - align-items: center; - justify-content: center; - background-color: rgba(0, 0, 0, 0.7); /* Dark grey modal background */ - z-index: 9999; -} - -.menuContent { - display: flex; - align-items: center; - justify-content: center; - background-color: #fff; - padding-top: 20px; - max-width: 700px; - max-height: 500px; - overflow: hidden; - position: relative; -} - -.menuOptions { - list-style-type: none; - padding: 0; - margin: 0; -} - -.menuOptions li { - padding: 10px; - border-bottom: 1px solid #ccc; - padding-left: 100px; - padding-right: 100px; - cursor: pointer; -} - -.moreOptionsButton { - position: relative; - bottom: 5rem; - right: 10px; - padding: 2px; - background-color: transparent; - color: #000; - border: none; - cursor: pointer; -} -.list { - color: red; - cursor: pointer; -} diff --git a/src/components/OrgPostCard/OrgPostCard.tsx b/src/components/OrgPostCard/OrgPostCard.tsx index b7cc419d12..5bc9ca1407 100644 --- a/src/components/OrgPostCard/OrgPostCard.tsx +++ b/src/components/OrgPostCard/OrgPostCard.tsx @@ -14,7 +14,8 @@ import { toast } from 'react-toastify'; import convertToBase64 from 'utils/convertToBase64'; import { errorHandler } from 'utils/errorHandler'; import type { InterfacePostForm } from 'utils/interfaces'; -import styles from './OrgPostCard.module.css'; +import styles from '../../style/app.module.css'; +import DeletePostModal from './DeletePostModal'; interface InterfaceOrgPostCardProps { postID: string; id: string; @@ -29,8 +30,14 @@ export default function OrgPostCard( props: InterfaceOrgPostCardProps, ): JSX.Element { const { - postID, // Destructure the key prop from props - // ...rest // Spread the rest of the props + postID, + id, + postTitle, + postInfo, + postAuthor, + postPhoto, + postVideo, + pinned, } = props; const [postformState, setPostFormState] = useState({ posttitle: '', @@ -51,11 +58,7 @@ export default function OrgPostCard( const [toggle] = useMutation(TOGGLE_PINNED_POST); const togglePostPin = async (id: string, pinned: boolean): Promise => { try { - const { data } = await toggle({ - variables: { - id, - }, - }); + const { data } = await toggle({ variables: { id } }); if (data) { setModalVisible(false); setMenuVisible(false); @@ -66,7 +69,6 @@ export default function OrgPostCard( } } catch (error: unknown) { if (error instanceof Error) { - /* istanbul ignore next */ errorHandler(t, error); } } @@ -100,10 +102,7 @@ export default function OrgPostCard( setMenuVisible(true); }; const clearImageInput = (): void => { - setPostFormState({ - ...postformState, - postphoto: '', - }); + setPostFormState({ ...postformState, postphoto: '' }); setPostPhotoUpdated(true); const fileInput = document.getElementById( 'postImageUrl', @@ -150,11 +149,11 @@ export default function OrgPostCard( } useEffect(() => { setPostFormState({ - posttitle: props.postTitle, - postinfo: props.postInfo, - postphoto: props.postPhoto, - postvideo: props.postVideo, - pinned: props.pinned, + posttitle: postTitle, + postinfo: postInfo, + postphoto: postPhoto, + postvideo: postVideo, + pinned: pinned, }); }, []); const { t } = useTranslation('translation', { @@ -166,9 +165,7 @@ export default function OrgPostCard( const deletePost = async (): Promise => { try { const { data } = await deletePostMutation({ - variables: { - id: props.id, - }, + variables: { id }, }); if (data) { toast.success(t('postDeleted') as string); @@ -197,7 +194,7 @@ export default function OrgPostCard( try { const { data } = await updatePostMutation({ variables: { - id: props.id, + id: id, title: postformState.posttitle, text: postformState.postinfo, ...(postPhotoUpdated && { @@ -228,13 +225,13 @@ export default function OrgPostCard( data-testid="post-item" >
- {props.postVideo && ( + {postVideo && ( - + - {props.pinned && ( + {pinned && ( )} - - {props.postTitle} + + {postTitle} - - {props.postInfo} + + {postInfo} - - {props.postAuthor} - + {postAuthor} )} - {props.postPhoto ? ( - + {postPhoto ? ( + - {props.pinned && ( + {pinned && ( )} - - {props.postTitle} + + {postTitle} - {props.postInfo} - {props.postAuthor} + + {postInfo} + + {postAuthor} - ) : !props.postVideo ? ( + ) : !postVideo ? ( - + - {props.pinned && ( + {pinned && ( )} - - {props.postTitle} + + {postTitle} - - {props.postInfo && props.postInfo.length > 20 - ? props.postInfo.substring(0, 20) + '...' - : props.postInfo} + + {postInfo && postInfo.length > 20 + ? postInfo.substring(0, 20) + '...' + : postInfo} {' '} - - {props.postAuthor} - + {postAuthor} @@ -325,21 +326,24 @@ export default function OrgPostCard( )}
{modalVisible && ( -
-
- {props.postPhoto && ( +
+
+ {postPhoto && (
- Post Image + Post Image
)} - {props.postVideo && ( + {postVideo && (
)} - {!props.postPhoto && !props.postVideo && ( + {!postPhoto && !postVideo && (
{' '} Post Image @@ -347,23 +351,23 @@ export default function OrgPostCard( )}

- {t('author')}: {props.postAuthor} + {t('author')}: {postAuthor}

{togglePost === 'Read more' ? (

- {props.postInfo.length > 43 - ? props.postInfo.substring(0, 40) + '...' - : props.postInfo} + {postInfo.length > 43 + ? postInfo.substring(0, 40) + '...' + : postInfo}

) : ( -

{props.postInfo}

+

{postInfo}

)}
- - -
{t('deletePost')}
- -
- {t('deletePostMsg')} - - - - -
+ deletePost()} + /> - {!props.postPhoto && ( + {!postPhoto && ( <> {t('image')} - {props.postPhoto && ( + {postPhoto && ( <> {postformState.postphoto && ( -
+
Post Image Preview )} - {!props.postVideo && ( + {!postVideo && ( <> {t('video')} {postformState.postvideo && ( -
+
- Sr. No. - Group Name - + + Sr. No. + + + Group Name + + No. of Members @@ -171,12 +167,7 @@ const VolunteerViewModal: React.FC = ({ {groups.map((group, index) => { const { _id, name, volunteers } = group; return ( - + {index + 1} @@ -199,4 +190,5 @@ const VolunteerViewModal: React.FC = ({ ); }; + export default VolunteerViewModal; diff --git a/src/screens/ForgotPassword/ForgotPassword.test.tsx b/src/screens/ForgotPassword/ForgotPassword.spec.tsx similarity index 85% rename from src/screens/ForgotPassword/ForgotPassword.test.tsx rename to src/screens/ForgotPassword/ForgotPassword.spec.tsx index be1b1706f8..6c534905e1 100644 --- a/src/screens/ForgotPassword/ForgotPassword.test.tsx +++ b/src/screens/ForgotPassword/ForgotPassword.spec.tsx @@ -2,32 +2,49 @@ import React from 'react'; import { MockedProvider } from '@apollo/react-testing'; import { act, render, screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; -import 'jest-localstorage-mock'; -import 'jest-location-mock'; import { I18nextProvider } from 'react-i18next'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; -import { toast, ToastContainer } from 'react-toastify'; - -import { GENERATE_OTP_MUTATION } from 'GraphQl/Mutations/mutations'; +import { toast } from 'react-toastify'; +import { + FORGOT_PASSWORD_MUTATION, + GENERATE_OTP_MUTATION, +} from 'GraphQl/Mutations/mutations'; import { store } from 'state/store'; import { StaticMockLink } from 'utils/StaticMockLink'; // import i18nForTest from 'utils/i18nForTest'; import ForgotPassword from './ForgotPassword'; import i18n from 'utils/i18nForTest'; import useLocalStorage from 'utils/useLocalstorage'; +import { vi, beforeEach, afterEach, expect, it, describe } from 'vitest'; const { setItem, removeItem } = useLocalStorage(); -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - error: jest.fn(), - warn: jest.fn(), + success: vi.fn(), + error: vi.fn(), + warn: vi.fn(), }, })); const MOCKS = [ + { + request: { + query: FORGOT_PASSWORD_MUTATION, + variables: { + otpToken: 'lorem ipsum', + userOtp: '12345', + newPassword: 'johnDoe@12345', + }, + }, + result: { + data: { + forgotPassword: true, + }, + }, + }, + { request: { query: GENERATE_OTP_MUTATION, @@ -100,8 +117,8 @@ afterEach(() => { }); describe('Testing Forgot Password screen', () => { - test('Component should be rendered properly', async () => { - window.location.assign('/orglist'); + it('Component should be rendered properly', async () => { + window.history.pushState({}, 'Test page', '/orglist'); render( @@ -121,10 +138,10 @@ describe('Testing Forgot Password screen', () => { expect(screen.getByText(/Registered Email/i)).toBeInTheDocument(); expect(screen.getByText(/Get Otp/i)).toBeInTheDocument(); expect(screen.getByText(/Back to Login/i)).toBeInTheDocument(); - expect(window.location).toBeAt('/orglist'); + expect(window.location.pathname).toBe('/orglist'); }); - test('Testing, If user is already loggedIn', async () => { + it('Testing, If user is already loggedIn', async () => { setItem('IsLoggedIn', 'TRUE'); render( @@ -142,7 +159,7 @@ describe('Testing Forgot Password screen', () => { await wait(); }); - test('Testing get OTP functionality', async () => { + it('Testing get OTP functionality', async () => { const formData = { email: 'johndoe@gmail.com', }; @@ -172,11 +189,11 @@ describe('Testing Forgot Password screen', () => { }); }); - test('Testing forgot password functionality', async () => { + it('Testing forgot password functionality', async () => { const formData = { userOtp: '12345', - newPassword: 'johnDoe', - confirmNewPassword: 'johnDoe', + newPassword: 'johnDoe@12345', + confirmNewPassword: 'johnDoe@12345', email: 'johndoe@gmail.com', }; @@ -213,7 +230,7 @@ describe('Testing Forgot Password screen', () => { await wait(); }); - test('Testing forgot password functionality, if the otp got deleted from the local storage', async () => { + it('Testing forgot password functionality, if the otp got deleted from the local storage', async () => { const formData = { userOtp: '12345', newPassword: 'johnDoe', @@ -254,7 +271,7 @@ describe('Testing Forgot Password screen', () => { await wait(); }); - test('Testing forgot password functionality, when new password and confirm password is not same', async () => { + it('Testing forgot password functionality, when new password and confirm password is not same', async () => { const formData = { email: 'johndoe@gmail.com', userOtp: '12345', @@ -294,7 +311,7 @@ describe('Testing Forgot Password screen', () => { userEvent.click(screen.getByText('Change Password')); }); - test('Testing forgot password functionality, when the user is not found', async () => { + it('Testing forgot password functionality, when the user is not found', async () => { const formData = { email: 'notexists@gmail.com', }; @@ -324,7 +341,7 @@ describe('Testing Forgot Password screen', () => { }); }); - test('Testing forgot password functionality, when there is an error except unregistered email and api failure', async () => { + it('Testing forgot password functionality, when there is an error except unregistered email and api failure', async () => { render( @@ -342,7 +359,7 @@ describe('Testing Forgot Password screen', () => { }); }); - test('Testing forgot password functionality, when talawa api failed', async () => { + it('Testing forgot password functionality, when talawa api failed', async () => { const formData = { email: 'johndoe@gmail.com', }; @@ -372,7 +389,7 @@ describe('Testing Forgot Password screen', () => { }); }); - test('Testing forgot password functionality, when otp token is not present', async () => { + it('Testing forgot password functionality, when otp token is not present', async () => { const formData = { userOtp: '12345', newPassword: 'johnDoe', diff --git a/src/screens/ForgotPassword/ForgotPassword.tsx b/src/screens/ForgotPassword/ForgotPassword.tsx index 83f20b4375..00fdb77c3b 100644 --- a/src/screens/ForgotPassword/ForgotPassword.tsx +++ b/src/screens/ForgotPassword/ForgotPassword.tsx @@ -135,7 +135,7 @@ const ForgotPassword = (): JSX.Element => { }, }); - /* istanbul ignore next */ + /* istanbul ignore else -- @preserve */ if (data) { toast.success(t('passwordChanges') as string); setShowEnterEmail(true); @@ -147,7 +147,6 @@ const ForgotPassword = (): JSX.Element => { } } catch (error: unknown) { setShowEnterEmail(true); - /* istanbul ignore next */ errorHandler(t, error); } }; diff --git a/src/screens/ManageTag/ManageTag.tsx b/src/screens/ManageTag/ManageTag.tsx index 7eb6a3221d..38466f6f11 100644 --- a/src/screens/ManageTag/ManageTag.tsx +++ b/src/screens/ManageTag/ManageTag.tsx @@ -536,7 +536,7 @@ function ManageTag(): JSX.Element {
{ }); }); - it('should render dropdown for settings tabs', async () => { + it('should handle dropdown item selection correctly', async () => { renderOrganisationSettings(); await waitFor(() => { - expect(screen.getByTestId('settingsDropdownToggle')).toBeInTheDocument(); + expect( + screen.getByTestId('settingsDropdownContainer'), + ).toBeInTheDocument(); }); - userEvent.click(screen.getByTestId('settingsDropdownToggle')); + const dropdownToggle = screen.getByTestId('settingsDropdownToggle'); + userEvent.click(dropdownToggle); - const dropdownItems = screen.getAllByRole('button', { - name: /general|actionItemCategories|agendaItemCategories/i, - }); + // Find all dropdown items + const dropdownItems = screen.getAllByRole('menuitem'); expect(dropdownItems).toHaveLength(3); + + for (const item of dropdownItems) { + userEvent.click(item); + + if (item.textContent?.includes('general')) { + await waitFor(() => { + expect(screen.getByTestId('generalTab')).toBeInTheDocument(); + }); + } else if (item.textContent?.includes('actionItemCategories')) { + await waitFor(() => { + expect( + screen.getByTestId('actionItemCategoriesTab'), + ).toBeInTheDocument(); + }); + } else if (item.textContent?.includes('agendaItemCategories')) { + await waitFor(() => { + expect( + screen.getByTestId('agendaItemCategoriesTab'), + ).toBeInTheDocument(); + }); + } + + if (item !== dropdownItems[dropdownItems.length - 1]) { + userEvent.click(dropdownToggle); + } + } + + expect(dropdownToggle).toHaveTextContent( + screen.getByTestId('agendaItemCategoriesSettings').textContent || '', + ); }); }); diff --git a/src/screens/OrgSettings/OrgSettings.tsx b/src/screens/OrgSettings/OrgSettings.tsx index c7b01138ae..641bc27c7d 100644 --- a/src/screens/OrgSettings/OrgSettings.tsx +++ b/src/screens/OrgSettings/OrgSettings.tsx @@ -81,10 +81,8 @@ function OrgSettings(): JSX.Element { {settingtabs.map((setting, index) => ( setTab(setting) - } + role="menuitem" + onClick={() => setTab(setting)} className={tab === setting ? 'text-secondary' : ''} > {t(setting)} diff --git a/src/screens/OrganizationActionItems/ItemModal.spec.tsx b/src/screens/OrganizationActionItems/ItemModal.spec.tsx index 1fe3d6fca5..a3467d4cf6 100644 --- a/src/screens/OrganizationActionItems/ItemModal.spec.tsx +++ b/src/screens/OrganizationActionItems/ItemModal.spec.tsx @@ -543,6 +543,12 @@ describe('Testing ItemModal', () => { const volunteerInputField = within(volunteerSelect).getByRole('combobox'); fireEvent.mouseDown(volunteerInputField); + // Select Invalid User with no _id + const invalidVolunteerOption = await screen.findByText('Invalid User'); + expect(invalidVolunteerOption).toBeInTheDocument(); + fireEvent.click(invalidVolunteerOption); + + fireEvent.mouseDown(volunteerInputField); const volunteerOption = await screen.findByText('Bruce Graza'); expect(volunteerOption).toBeInTheDocument(); fireEvent.click(volunteerOption); @@ -578,6 +584,12 @@ describe('Testing ItemModal', () => { const inputField = within(categorySelect).getByRole('combobox'); fireEvent.mouseDown(inputField); + // Select Invalid Category with no _id + const invalidCategoryOption = await screen.findByText('Category 3'); + expect(invalidCategoryOption).toBeInTheDocument(); + fireEvent.click(invalidCategoryOption); + + fireEvent.mouseDown(inputField); const categoryOption = await screen.findByText('Category 1'); expect(categoryOption).toBeInTheDocument(); fireEvent.click(categoryOption); @@ -595,6 +607,12 @@ describe('Testing ItemModal', () => { const groupInputField = within(groupSelect).getByRole('combobox'); fireEvent.mouseDown(groupInputField); + // Select Invalid Group with no _id + const invalidGroupOption = await screen.findByText('group3'); + expect(invalidGroupOption).toBeInTheDocument(); + fireEvent.click(invalidGroupOption); + + fireEvent.mouseDown(groupInputField); const groupOption = await screen.findByText('group2'); expect(groupOption).toBeInTheDocument(); fireEvent.click(groupOption); @@ -692,6 +710,12 @@ describe('Testing ItemModal', () => { const memberInputField = within(memberSelect).getByRole('combobox'); fireEvent.mouseDown(memberInputField); + // Select invalid member with no _id + const invalidMemberOption = await screen.findByText('Invalid User'); + expect(invalidMemberOption).toBeInTheDocument(); + fireEvent.click(invalidMemberOption); + + fireEvent.mouseDown(memberInputField); const memberOption = await screen.findByText('Harve Lance'); expect(memberOption).toBeInTheDocument(); fireEvent.click(memberOption); diff --git a/src/screens/OrganizationActionItems/ItemModal.tsx b/src/screens/OrganizationActionItems/ItemModal.tsx index b7555af121..98a4611bf6 100644 --- a/src/screens/OrganizationActionItems/ItemModal.tsx +++ b/src/screens/OrganizationActionItems/ItemModal.tsx @@ -404,7 +404,6 @@ const ItemModal: FC = ({ item.name } onChange={(_, newCategory): void => { - /* istanbul ignore next */ handleFormChange( 'actionItemCategoryId', newCategory?._id ?? '', @@ -507,7 +506,6 @@ const ItemModal: FC = ({ `${volunteer.user.firstName} ${volunteer.user.lastName}` } onChange={(_, newAssignee): void => { - /* istanbul ignore next */ handleFormChange('assigneeId', newAssignee?._id ?? ''); setAssignee(newAssignee); }} @@ -531,7 +529,6 @@ const ItemModal: FC = ({ group: InterfaceVolunteerGroupInfo, ): string => `${group.name}`} onChange={(_, newAssignee): void => { - /* istanbul ignore next */ handleFormChange('assigneeId', newAssignee?._id ?? ''); setAssigneeGroup(newAssignee); }} @@ -559,7 +556,6 @@ const ItemModal: FC = ({ `${member.firstName} ${member.lastName}` } onChange={(_, newAssignee): void => { - /* istanbul ignore next */ handleFormChange('assigneeId', newAssignee?._id ?? ''); setAssigneeUser(newAssignee); }} @@ -578,7 +574,8 @@ const ItemModal: FC = ({ className={styles.noOutline} value={dayjs(dueDate)} onChange={(date: Dayjs | null): void => { - /* istanbul ignore next */ + // Added istanbul ignore else, which will ignore else condition, we are not using else condition here + /* istanbul ignore else -- @preserve */ if (date) handleFormChange('dueDate', date.toDate()); }} /> diff --git a/src/screens/OrganizationActionItems/testObject.mocks.ts b/src/screens/OrganizationActionItems/testObject.mocks.ts index d43f574e8c..02b8b97b27 100644 --- a/src/screens/OrganizationActionItems/testObject.mocks.ts +++ b/src/screens/OrganizationActionItems/testObject.mocks.ts @@ -210,6 +210,14 @@ export const memberListQuery = { organizationsBlockedBy: [], createdAt: '2024-02-14', }, + { + firstName: 'Invalid', + lastName: 'User', + email: 'wilt@example.com', + image: '', + organizationsBlockedBy: [], + createdAt: '2024-02-14', + }, ], }, ], @@ -262,6 +270,17 @@ export const volunteerListQuery = [ assignments: [], groups: [], }, + { + hasAccepted: true, + hoursVolunteered: 0, + user: { + firstName: 'Invalid', + lastName: 'User', + image: null, + }, + assignments: [], + groups: [], + }, ], }, }, @@ -346,6 +365,29 @@ export const groupListQuery = [ _id: 'eventId', }, }, + { + name: 'group3', + description: 'desc', + volunteersRequired: 10, + createdAt: '2024-10-27T15:34:15.889Z', + creator: { + _id: 'userId2', + firstName: 'Wilt', + lastName: 'Shepherd', + image: null, + }, + leader: { + _id: 'userId1', + firstName: 'Teresa', + lastName: 'Bradley', + image: null, + }, + volunteers: [], + assignments: [], + event: { + _id: 'eventId', + }, + }, ], }, }, @@ -396,6 +438,15 @@ export const actionItemCategoryListQuery = { lastName: 'Doe', }, }, + { + name: 'Category 3', + isDisabled: true, + createdAt: '2024-08-25', + creator: { + firstName: 'John', + lastName: 'Doe', + }, + }, ], }, }, diff --git a/src/screens/OrganizationEvents/OrganizationEvents.test.tsx b/src/screens/OrganizationEvents/OrganizationEvents.spec.tsx similarity index 93% rename from src/screens/OrganizationEvents/OrganizationEvents.test.tsx rename to src/screens/OrganizationEvents/OrganizationEvents.spec.tsx index 09e896e031..e329130895 100644 --- a/src/screens/OrganizationEvents/OrganizationEvents.test.tsx +++ b/src/screens/OrganizationEvents/OrganizationEvents.spec.tsx @@ -9,7 +9,6 @@ import { } from '@testing-library/react'; import { Provider } from 'react-redux'; import { BrowserRouter } from 'react-router-dom'; -import 'jest-location-mock'; import { I18nextProvider } from 'react-i18next'; import OrganizationEvents from './OrganizationEvents'; @@ -23,7 +22,7 @@ import { ThemeProvider } from 'react-bootstrap'; import { LocalizationProvider } from '@mui/x-date-pickers'; import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'; import { MOCKS } from './OrganizationEventsMocks'; - +import { describe, test, expect, vi } from 'vitest'; const theme = createTheme({ palette: { primary: { @@ -31,6 +30,23 @@ const theme = createTheme({ }, }, }); +Object.defineProperty(window, 'location', { + value: { + href: 'http://localhost/', + assign: vi.fn((url) => { + const urlObj = new URL(url, 'http://localhost'); + window.location.href = urlObj.href; + window.location.pathname = urlObj.pathname; + window.location.search = urlObj.search; + window.location.hash = urlObj.hash; + }), + reload: vi.fn(), + pathname: '/', + search: '', + hash: '', + origin: 'http://localhost', + }, +}); const link = new StaticMockLink(MOCKS, true); const link2 = new StaticMockLink([], true); @@ -42,7 +58,6 @@ async function wait(ms = 100): Promise { }); }); } - const translations = { ...JSON.parse( JSON.stringify( @@ -53,19 +68,20 @@ const translations = { ...JSON.parse(JSON.stringify(i18n.getDataByLanguage('en')?.errors ?? {})), }; -jest.mock('@mui/x-date-pickers/DateTimePicker', () => { +vi.mock('@mui/x-date-pickers/DateTimePicker', async () => { + const actual = await vi.importActual( + '@mui/x-date-pickers/DesktopDateTimePicker', + ); return { - DateTimePicker: jest.requireActual( - '@mui/x-date-pickers/DesktopDateTimePicker', - ).DesktopDateTimePicker, + DateTimePicker: actual.DesktopDateTimePicker, }; }); -jest.mock('react-toastify', () => ({ +vi.mock('react-toastify', () => ({ toast: { - success: jest.fn(), - warning: jest.fn(), - error: jest.fn(), + success: vi.fn(), + warning: vi.fn(), + error: vi.fn(), }, })); @@ -80,7 +96,7 @@ describe('Organisation Events Page', () => { endTime: '05:00 PM', }; - global.alert = jest.fn(); + global.alert = vi.fn(); test('It is necessary to query the correct mock data.', async () => { const dataQuery1 = MOCKS[0]?.result?.data?.eventsByOrganizationConnection; @@ -148,7 +164,7 @@ describe('Organisation Events Page', () => { expect(container.textContent).not.toBe('Loading data...'); await wait(); expect(container.textContent).toMatch('Month'); - expect(window.location).toBeAt('/orglist'); + expect(window.location.pathname).toBe('/orglist'); }); test('No mock data', async () => { diff --git a/src/screens/OrganizationFunds/OrganizationFunds.tsx b/src/screens/OrganizationFunds/OrganizationFunds.tsx index ec9409fbe0..1935e5306e 100644 --- a/src/screens/OrganizationFunds/OrganizationFunds.tsx +++ b/src/screens/OrganizationFunds/OrganizationFunds.tsx @@ -300,7 +300,7 @@ const organizationFunds = (): JSX.Element => {
({ - toast: { success: jest.fn() }, // Mock toast function +vi.mock('react-toastify', () => ({ + toast: { success: vi.fn() }, // Mock toast function })); Object.defineProperty(window, 'localStorage', { value: { - getItem: jest.fn(), - setItem: jest.fn(), - removeItem: jest.fn(), - clear: jest.fn(), + getItem: vi.fn(), + setItem: vi.fn(), + removeItem: vi.fn(), + clear: vi.fn(), }, writable: true, }); // Mock useParams to return a test organization ID -jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: jest.fn(), - useNavigate: jest.fn(), -})); + +vi.mock('react-router-dom', async () => { + const actualDom = await vi.importActual('react-router-dom'); + return { + ...actualDom, + useParams: vi.fn(), + useNavigate: vi.fn(), + }; +}); // Mock the custom hook -jest.mock('utils/useLocalstorage', () => { +vi.mock('utils/useLocalstorage', () => { return { - getItem: jest.fn((prefix: string, key: string) => { + getItem: vi.fn((prefix: string, key: string) => { if (prefix === 'Talawa-admin' && key === 'email') return 'test@example.com'; if (prefix === 'Talawa-admin' && key === 'userId') return '12345'; @@ -235,8 +240,10 @@ const errorMocks = [ beforeEach(() => { localStorage.clear(); - jest.clearAllMocks(); // Clear mocks before each test - (useParams as jest.Mock).mockReturnValue({ orgId: 'test-org-id' }); + vi.clearAllMocks(); + (useParams as unknown as ReturnType).mockReturnValue({ + orgId: 'test-org-id', + }); }); describe('LeaveOrganization Component', () => { @@ -309,7 +316,9 @@ describe('LeaveOrganization Component', () => { }); test('logs an error when unable to access localStorage', () => { - const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(); + const consoleErrorSpy = vi + .spyOn(console, 'error') + .mockImplementation(() => {}); const userEmail = (() => { try { return getItem('Talawa-admin-error', 'user-email-error') ?? ''; @@ -336,9 +345,11 @@ describe('LeaveOrganization Component', () => { }); test('navigates and shows toast when email matches', async () => { - const mockNavigate = jest.fn(); - (useNavigate as jest.Mock).mockReturnValue(mockNavigate); - const toastSuccessMock = jest.fn(); + const mockNavigate = vi.fn(); + (useNavigate as unknown as ReturnType).mockReturnValue( + mockNavigate, + ); + const toastSuccessMock = vi.fn(); toast.success = toastSuccessMock; render( @@ -485,8 +496,10 @@ describe('LeaveOrganization Component', () => { }); test('closes modal and resets state when Esc key is pressed', async () => { - const mockNavigate = jest.fn(); - (useNavigate as jest.Mock).mockReturnValue(mockNavigate); + const mockNavigate = vi.fn(); + (useNavigate as unknown as ReturnType).mockReturnValue( + mockNavigate, + ); render( diff --git a/src/screens/UserPortal/People/People.spec.tsx b/src/screens/UserPortal/People/People.spec.tsx index 11051538db..8837bee265 100644 --- a/src/screens/UserPortal/People/People.spec.tsx +++ b/src/screens/UserPortal/People/People.spec.tsx @@ -11,6 +11,7 @@ import { Provider } from 'react-redux'; import { store } from 'state/store'; import i18nForTest from 'utils/i18nForTest'; import { StaticMockLink } from 'utils/StaticMockLink'; +// import type { InterfaceMember } from './People'; import People from './People'; import userEvent from '@testing-library/user-event'; import { vi } from 'vitest'; diff --git a/src/screens/UserPortal/People/People.tsx b/src/screens/UserPortal/People/People.tsx index 4904e75b20..827a5b49c6 100644 --- a/src/screens/UserPortal/People/People.tsx +++ b/src/screens/UserPortal/People/People.tsx @@ -37,20 +37,19 @@ interface InterfaceMember { * and paginate through the list. */ export default function people(): JSX.Element { - // i18n translation hook for user organization related translations const { t } = useTranslation('translation', { keyPrefix: 'people', }); - // i18n translation hook for common translations const { t: tCommon } = useTranslation('common'); - // State for managing current page in pagination const [page, setPage] = useState(0); // State for managing the number of rows per page in pagination const [rowsPerPage, setRowsPerPage] = useState(5); - const [members, setMembers] = useState([]); + const [members, setMembers] = useState([]); + const [allMembers, setAllMembers] = useState([]); + const [admins, setAdmins] = useState([]); const [mode, setMode] = useState(0); // Extracting organization ID from URL parameters @@ -69,17 +68,11 @@ export default function people(): JSX.Element { }, }, ); - // Query to fetch list of admins of the organization const { data: data2 } = useQuery(ORGANIZATION_ADMINS_LIST, { variables: { id: organizationId }, }); - /** - * Handles page change in pagination. - * - */ - /* istanbul ignore next */ const handleChangePage = ( _event: React.MouseEvent | null, newPage: number, @@ -87,11 +80,6 @@ export default function people(): JSX.Element { setPage(newPage); }; - /** - * Handles change in the number of rows per page. - * - */ - /* istanbul ignore next */ const handleChangeRowsPerPage = ( event: React.ChangeEvent, ): void => { @@ -101,20 +89,12 @@ export default function people(): JSX.Element { setPage(0); }; - /** - * Searches for members based on the filter value. - * - */ const handleSearch = (newFilter: string): void => { refetch({ firstName_contains: newFilter, }); }; - /** - * Handles search operation triggered by pressing the Enter key. - * - */ const handleSearchByEnter = ( e: React.KeyboardEvent, ): void => { @@ -124,9 +104,6 @@ export default function people(): JSX.Element { } }; - /** - * Handles search operation triggered by clicking the search button. - */ const handleSearchByBtnClick = (): void => { const inputValue = (document.getElementById('searchPeople') as HTMLInputElement)?.value || @@ -134,24 +111,51 @@ export default function people(): JSX.Element { handleSearch(inputValue); }; + useEffect(() => { + if (data2) { + const admin = data2.organizations[0].admins[0]; + const updatedAdmin: InterfaceMember = { + ...admin, + userType: 'Admin', + }; + setAdmins([updatedAdmin]); + } + }, [data2]); + useEffect(() => { if (data) { - setMembers(data.organizationsMemberConnection.edges); + const updatedAdmins = data.organizationsMemberConnection.edges.map( + (memberData: InterfaceMember) => ({ + ...memberData, // Spread the existing properties + userType: admins?.some((admin) => admin._id === memberData._id) + ? 'Admin' + : 'Member', + }), + ); + + setAllMembers(updatedAdmins); + setMembers(updatedAdmins); } - }, [data]); + }, [data, admins]); - /** - * Updates the list of members based on the selected filter mode. - */ - /* istanbul ignore next */ + if (admins && admins.length > 0) { + const adminIds = admins.map((adm) => adm._id); + for (let i = 0; i < allMembers.length; i++) { + if (adminIds.includes(allMembers[i]._id)) { + allMembers[i].userType = 'Admin'; + } else { + allMembers[i].userType = 'Member'; + } + } + } useEffect(() => { if (mode == 0) { if (data) { - setMembers(data.organizationsMemberConnection.edges); + setMembers(allMembers); } } else if (mode == 1) { if (data2) { - setMembers(data2.organizations[0].admins); + setMembers(admins); } } }, [mode]); diff --git a/src/screens/UserPortal/Volunteer/VolunteerManagement.test.tsx b/src/screens/UserPortal/Volunteer/VolunteerManagement.spec.tsx similarity index 78% rename from src/screens/UserPortal/Volunteer/VolunteerManagement.test.tsx rename to src/screens/UserPortal/Volunteer/VolunteerManagement.spec.tsx index 80ac0df833..6fb9c218f9 100644 --- a/src/screens/UserPortal/Volunteer/VolunteerManagement.test.tsx +++ b/src/screens/UserPortal/Volunteer/VolunteerManagement.spec.tsx @@ -13,6 +13,7 @@ import userEvent from '@testing-library/user-event'; import { MOCKS } from './UpcomingEvents/UpcomingEvents.mocks'; import { StaticMockLink } from 'utils/StaticMockLink'; import useLocalStorage from 'utils/useLocalstorage'; +import { vi } from 'vitest'; const { setItem } = useLocalStorage(); const link1 = new StaticMockLink(MOCKS); @@ -43,10 +44,13 @@ const renderVolunteerManagement = (): RenderResult => { describe('Volunteer Management', () => { beforeAll(() => { - jest.mock('react-router-dom', () => ({ - ...jest.requireActual('react-router-dom'), - useParams: () => ({ orgId: 'orgId' }), - })); + vi.mock('react-router-dom', async () => { + const actual = await vi.importActual('react-router-dom'); // Import the actual implementation + return { + ...actual, + useParams: () => ({ orgId: 'orgId' }), + }; + }); }); beforeEach(() => { @@ -54,10 +58,11 @@ describe('Volunteer Management', () => { }); afterAll(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); it('should redirect to fallback URL if URL params are undefined', async () => { + setItem('userId', null); render( @@ -126,4 +131,24 @@ describe('Volunteer Management', () => { const groupsTab = screen.getByTestId('groupsTab'); expect(groupsTab).toBeInTheDocument(); }); + test('Component should highlight the selected tab', async () => { + renderVolunteerManagement(); + + const upcomingEventsBtn = screen.getByTestId('upcomingEventsBtn'); + const invitationsBtn = screen.getByTestId('invitationsBtn'); + // Click the invitations tab + userEvent.click(invitationsBtn); + await waitFor(() => { + expect(invitationsBtn).toHaveClass('btn-success'); + expect(upcomingEventsBtn).not.toHaveClass('btn-success'); + }); + }); + test('should update the component state on tab switch', async () => { + renderVolunteerManagement(); + + const actionsBtn = screen.getByTestId('actionsBtn'); + userEvent.click(actionsBtn); + const actionsTab = screen.getByTestId('actionsTab'); + expect(actionsTab).toBeInTheDocument(); + }); }); diff --git a/src/screens/UserPortal/Volunteer/VolunteerManagement.tsx b/src/screens/UserPortal/Volunteer/VolunteerManagement.tsx index 87be9d7adc..fd90584d62 100644 --- a/src/screens/UserPortal/Volunteer/VolunteerManagement.tsx +++ b/src/screens/UserPortal/Volunteer/VolunteerManagement.tsx @@ -151,10 +151,7 @@ const VolunteerManagement = (): JSX.Element => { {volunteerDashboardTabs.map(({ value, icon }, index) => ( setTab(value) - } + onClick={() => setTab(value)} className={`d-flex gap-2 ${tab === value && 'text-secondary'}`} > {icon} {t(value)} diff --git a/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.test.ts b/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.spec.ts similarity index 63% rename from src/setup/askForTalawaApiUrl/askForTalawaApiUrl.test.ts rename to src/setup/askForTalawaApiUrl/askForTalawaApiUrl.spec.ts index 3a11a0d799..bceecb806f 100644 --- a/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.test.ts +++ b/src/setup/askForTalawaApiUrl/askForTalawaApiUrl.spec.ts @@ -1,17 +1,22 @@ import inquirer from 'inquirer'; import { askForTalawaApiUrl } from './askForTalawaApiUrl'; - -jest.mock('inquirer', () => ({ - prompt: jest.fn(), -})); +import { vi, it, describe, expect, beforeEach } from 'vitest'; + +vi.mock('inquirer', async () => { + const actual = await vi.importActual('inquirer'); + return { + ...actual, + prompt: vi.fn(), + }; +}); describe('askForTalawaApiUrl', () => { beforeEach(() => { - jest.clearAllMocks(); + vi.clearAllMocks(); }); - test('should return the provided endpoint when user enters it', async () => { - const mockPrompt = jest.spyOn(inquirer, 'prompt').mockResolvedValueOnce({ + it('should return the provided endpoint when user enters it', async () => { + const mockPrompt = vi.spyOn(inquirer, 'prompt').mockResolvedValueOnce({ endpoint: 'http://example.com/graphql/', }); @@ -29,8 +34,8 @@ describe('askForTalawaApiUrl', () => { expect(result).toBe('http://example.com/graphql/'); }); - test('should return the default endpoint when the user does not enter anything', async () => { - const mockPrompt = jest.spyOn(inquirer, 'prompt').mockResolvedValueOnce({ + it('should return the default endpoint when the user does not enter anything', async () => { + const mockPrompt = vi.spyOn(inquirer, 'prompt').mockResolvedValueOnce({ endpoint: 'http://localhost:4000/graphql/', }); diff --git a/src/style/app.module.css b/src/style/app.module.css index 137ff0bd01..b9f7d49328 100644 --- a/src/style/app.module.css +++ b/src/style/app.module.css @@ -1,42 +1,112 @@ :root { + /* Neutral Colors */ + --grey-light: #eaebef; + --grey-dark: #707070; + --grey-border: #e8e5e5; + --input-shadow: #dddddd; + + /* Blue Shades */ + --blue-primary: #0056b3; + --blue-subtle: #7c9beb; + --blue-subtle-hover: #5f7e91; + --blue-search-bg: #a8c7fa; + --toggle-bg: #1e4e8c; + --dropdown-hover: #eff1f7; + + /* Red Shades */ + --red-delete-bg: #f8d6dc; + --red-delete-text: #ff4d4f; + + /* Yellow/Orange Shades */ + --loader-color: #febc59; + + /* Miscellaneous */ --brown-color: #555555; + --blue-color: #0000ff; + --light-blue-color: #286fe0; + --dimp-white: #b5b5b5; + --gray-blue: #1e293b; + --gray-white: #808080; --dropdown-hover-color: #eff1f7; --grey-bg-color: #eaebef; + --light-dark-green: #08780b; + --light-green: #31bb6b; + --green-color: #21d015; + --light-more-green: #39a440; + --off-light-green: #31bb6a60; + --dark-emerald-green: #23864c; + --light-neon-green: #afffe8; + --white-color: #ffffff; + --off-white-color: #ffffff97; + --black-color: #000000; + --black-shadow-color: #00000029; + --white-shadow-color: #ffffff33; + --light-dark-gray-color: #505050; + --light-orange: #febc59; --grey-border-box-color: #e8e5e5; --subtle-blue-grey: #7c9beb; --subtle-blue-grey-hover: #5f7e91; + --white: #fff; + --black: black; + + /* Background and Border */ + --table-bg: #eaebef; + --tablerow-bg: #eff1f7; + --date-picker-bg: #f2f2f2; + --table-bg-color: var(--grey-bg-color); + --tablerow-bg-color: var(--dropdown-hover-color); + --row-background: var(--bs-white, var(--bs-white)); + --modal-background: rgba(0, 0, 0, 0.7); + + /* Font Sizes */ + --font-size-header: 16px; + + /* Borders and Radius */ + --primary-border-solid: 1px solid var(--dropdown-border-color); + --table-head-radius: 20px; + + /* Loader Sizes */ + --loader-size: 10em; + --loader-border-width: 1.1em; + + /* Image Sizes */ + --table-image-size: 50px; + --table-image-small-size: 25px; + + /* Modal Dimensions */ --modal-width: 670px; --modal-max-width: 680px; + + /* Additional Variables */ --input-shadow-color: #dddddd; --delete-button-bg: #f8d6dc; --delete-button-color: #ff4d4f; --search-button-bg: #a8c7fa; - --search-button-border: #555555; - --table-image-size: 50px; - --table-image-small-size: 25px; + --search-button-border: var(--brown-color); --bs-primary: #0056b3; + --bs-warning: #ffc107; --bs-white: #fff; + --bs-gray-600: #4b5563; + --bs-gray-400: #9ca3af; + --bs-gray-300: #d1d5db; --toggle-button-bg: #1e4e8c; - --table-head-bg: var( - --bs-primary, - blue - ); /* Assuming var(--bs-primary) is defined elsewhere */ - --loader-size: 10em; - --loader-border-width: 1.1em; - --loader-color: #febc59; - --table-head-color: white; - --table-header-color: var(--bs-greyish-black, black); - --table-head-radius: 20px; - --table-bg-color: #eaebef; - --tablerow-bg-color: #eff1f7; - --row-background: var(--bs-white, white); - --font-size-header: 16px; + --table-head-bg: var(--bs-primary, var(--blue-color)); + --table-head-color: var(--bs-white, var(--white-color)); + --table-header-color: var(--bs-greyish-black, var(--black-color)); --input-area-color: #f1f3f6; --date-picker-background: #f2f2f2; --grey-bg-color-dark: #707070; + --dropdown-border-color: #cccccc; + --primary-border-solid: 1px solid var(--dropdown-border-color); + --card-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + + /* breakpoints */ + --breakpoint-mobile: 576px; + --breakpoint-tablet: 768px; + --breakpoint-desktop: 1024px; } .fonts { - color: #707070; + color: var(--grey-bg-color-dark); } .fonts > span { @@ -78,7 +148,7 @@ .capacityLabel { background-color: var(--bs-primary); - color: white; + color: var(--white-color); height: 22.19px; font-size: 12px; font-weight: bolder; @@ -99,7 +169,7 @@ height: 100%; } .sidebar:after { - background-color: #f7f7f7; + background-color: var(--grey-border-box-color); position: absolute; width: 2px; height: 600px; @@ -116,22 +186,22 @@ } .logintitle { - color: #707070; + color: var(--grey-bg-color-dark); font-weight: 600; font-size: 20px; margin-bottom: 30px; padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; + border-bottom: 3px solid var(--light-green); width: 15%; } .searchtitle { - color: #707070; + color: var(--grey-bg-color-dark); font-weight: 600; font-size: 18px; margin-bottom: 20px; padding-bottom: 5px; - border-bottom: 3px solid #31bb6b; + border-bottom: 3px solid var(--light-green); width: 60%; } @@ -216,7 +286,7 @@ } .dropdown:is(:focus, :focus-visible) { - outline: 2px solid var(--highlight-color, #a8c7fa); + outline: 2px solid var(--highlight-color, var(--search-button-bg)); } .dropdownItem { @@ -227,16 +297,19 @@ .dropdownItem:focus, .dropdownItem:hover { - outline: 2px solid var(--highlight-color, #a8c7fa); + outline: 2px solid var(--highlight-color, var(--search-button-bg)); } .dropdownItem:hover, .dropdownItem:focus, .dropdownItem:active { - background-color: var(--dropdown-hover-color, #e0e0e0) !important; + background-color: var( + --dropdown-hover-color, + var(--grey-border-box-color) + ) !important; color: var(--brown-color) !important; outline: none !important; - box-shadow: 0 0 4px var(--highlight-color, #a8c7fa); + box-shadow: 0 0 4px var(--highlight-color, var(--search-button-bg)); } .input { @@ -311,7 +384,7 @@ .createButton { background-color: var(--grey-bg-color) !important; - color: black !important; + color: var(--black-color) !important; margin-top: 10px; margin-left: 5px; border: 1px solid var(--brown-color); @@ -319,7 +392,7 @@ .createButton:hover { background-color: var(--grey-bg-color) !important; - color: black !important; + color: var(--black-color) !important; border: 1px solid var(--brown-color) !important; } @@ -366,7 +439,7 @@ } .searchButton:hover { - background-color: var(--search-button-hover-bg, #286fe0); + background-color: var(--search-button-hover-bg, var(--light-blue-color)); border-color: var(--search-button-border); } @@ -381,7 +454,7 @@ } .addButton:hover { - background-color: #286fe0; + background-color: var(--light-blue-color); border-color: var(--search-button-border); } @@ -403,7 +476,7 @@ } .infoButton:hover { - background-color: #286fe0; + background-color: var(--light-blue-color); border-color: var(--search-button-border); } @@ -441,7 +514,7 @@ .errorIcon { transform: scale(1.5); - color: var(--bs-danger); + color: var(--bs-danger, var(--delete-button-color)); margin-bottom: 1rem; /* Add error icon for non-color indication */ &::before { @@ -461,7 +534,7 @@ font-size: 16px; letter-spacing: 0; line-height: 1; - color: #08780b; + color: var(--light-dark-green); } .subTagsLink i { @@ -488,7 +561,7 @@ } .tagsBreadCrumbs:hover { - color: var(--bs-blue); + color: var(--blue-color); font-weight: 600; text-decoration: underline; } @@ -507,7 +580,7 @@ input[type='checkbox']:checked + label { } input[type='radio']:checked + label:hover { - color: black !important; + color: var(--black-color) !important; } .actionItemsContainer { @@ -567,7 +640,7 @@ hr { flex-direction: row; font-weight: 900; font-size: 16px; - color: rgb(80, 80, 80); + color: var(--light-dark-gray-color); } .rankings { @@ -614,7 +687,7 @@ hr { .pageNotFound h1.head { font-size: 250px; font-weight: 900; - color: #31bb6b; + color: var(--light-green); letter-spacing: 25px; margin: 10px 0 0 0; } @@ -694,7 +767,7 @@ hr { .inputFieldPledge { background-color: var(--bs-white); - box-shadow: 0 1px 1px #31bb6b; + box-shadow: 0 1px 1px var(--light-green); } .dropdownPledge { @@ -747,9 +820,9 @@ hr { justify-content: space-between; margin: 1.5rem 0 0 0; padding: 1.25rem 2rem; - background-color: rgba(255, 255, 255, 0.591); + background-color: var(--off-white-color); - box-shadow: rgba(0, 0, 0, 0.16) 0px 1px 4px; + box-shadow: var(--black-shadow-color) 0px 1px 4px; border-radius: 0.5rem; } @@ -762,7 +835,7 @@ hr { .titleContainer h3 { font-size: 1.75rem; font-weight: 750; - color: #5e5e5e; + color: var(--light-dark-gray-color); margin-top: 0.2rem; } @@ -770,7 +843,7 @@ hr { font-size: 0.9rem; margin-left: 0.5rem; font-weight: lighter; - color: #707070; + color: var(--grey-bg-color-dark); } .raisedAmount { @@ -779,7 +852,7 @@ hr { align-items: center; font-size: 1.25rem; font-weight: 750; - color: #5e5e5e; + color: var(--light-dark-gray-color); } .progressContainer { @@ -833,7 +906,7 @@ hr { padding: 0.75rem; border: 1px solid #e2e8f0; background-color: var(--bs-white); - color: #1e293b; + color: var(--gray-blue); box-shadow: 0 0.5rem 1rem rgb(0 0 0 / 0.15); display: flex; flex-direction: column; @@ -860,7 +933,7 @@ hr { } .toggleBtnPledge:hover { - color: #31bb6b !important; + color: var(--light-green) !important; } .card { @@ -883,7 +956,7 @@ hr { font-weight: normal; padding-bottom: 0; font-size: 1rem; - color: black; + color: var(--black-color); } .cardBody { @@ -907,7 +980,7 @@ hr { .eventDetailsBox { position: relative; box-sizing: border-box; - background: #ffffff; + background: var(--white-color); width: 66%; padding: 0.3rem; box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1); @@ -919,15 +992,15 @@ hr { padding: 20px; width: 100%; display: flex; - background-color: #ffffff; + background-color: var(--white-color); margin: 0 4px; justify-content: space-between; - box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1); + box-shadow: 0 3px 8px var(--black-shadow-color); align-items: center; border-radius: 20px; } .ctacards span { - color: rgb(181, 181, 181); + color: var(--dimp-white); font-size: small; } @@ -951,13 +1024,13 @@ hr { color: var(--delete-button-color); margin-right: 5px; background-color: var(--delete-button-bg); - border: white; + border: var(--white-color); } .closeButtonOrganizationEvents:hover { color: var(--delete-button-bg) !important; background-color: var(--delete-button-color) !important; - border: white; + border: var(--white-color); } .datedivOrganizationEvents { @@ -1000,7 +1073,7 @@ hr { .createButtonOrganizationEvents { background-color: var(--search-button-bg) !important; - color: black !important; + color: var(--black-color) !important; margin: 15px 0 0; padding: 10px 10px; border-radius: 5px; @@ -1017,7 +1090,7 @@ hr { .createButtonOrganizationEvents:hover { background-color: var(--bs-primary) !important; - color: white !important; + color: var(--white-color) !important; border: 1px solid var(--search-button-border) !important; } @@ -1029,7 +1102,7 @@ hr { width: 33%; box-sizing: border-box; - background: #ffffff; + background: var(--white-color); box-shadow: 0 3px 8px rgba(0, 0, 0, 0.1); border-radius: 20px; margin-bottom: 0; @@ -1049,7 +1122,7 @@ hr { .startDate, .endDate { - color: #808080; + color: var(--gray-white); font-size: 14px; } @@ -1065,7 +1138,7 @@ hr { } .description { - color: #737373; + color: var(--gray-white); font-weight: 300; font-size: 14px; word-wrap: break-word; @@ -1079,7 +1152,7 @@ hr { } .toporgloc span { - color: #737373; + color: var(--gray-white); } .eventAgendaItemContainer h2 { @@ -1101,7 +1174,7 @@ hr { } .customcell { - background-color: #31bb6b !important; + background-color: var(--light-green) !important; color: var(--bs-white) !important; font-size: medium !important; font-weight: 500 !important; @@ -1111,23 +1184,23 @@ hr { .eventsAttended, .membername { - color: blue; + color: var(--blue-color); } .actionBtn { - background-color: #ffffff !important; + background-color: var(--white-color) !important; } .actionBtn:hover, .actionBtn:focus, .actionBtn:active { - color: #39a440 !important; + color: var(--light-more-green) !important; } .table-body > .table-row { - background-color: #fff !important; + background-color: var(--white-color) !important; } .table-body > .table-row:nth-child(2n) { - background: #afffe8 !important; + background: var(--light-neon-green) !important; } .organizationFundCampaignContainer { @@ -1167,7 +1240,7 @@ hr { .goalButtonOrganizationFundCampaign { border: 1px solid var(--grey-border-box-color) !important; - color: #707070 !important; + color: var(--grey-bg-color-dark) !important; width: 75%; padding: 10px; border-radius: 8px; @@ -1201,7 +1274,7 @@ hr { cursor: pointer; } .campaignNameInfo:hover { - color: blue; + color: var(--blue-color); transform: translateY(-2px); } @@ -1215,7 +1288,7 @@ hr { border: 1px solid var(--grey-border-box-color); position: relative; display: inline-block; - color: #707070; + color: var(--grey-bg-color-dark); } .btnsContainerOrganizationFundCampaign { @@ -1513,7 +1586,7 @@ hr { } .subTagsLink { - color: var(--bs-blue); + color: var(--blue-color); font-weight: 500; cursor: pointer; /* Prevent layout shift */ @@ -1543,7 +1616,7 @@ hr { .tagsBreadCrumbs:hover, .tagsBreadCrumbs:focus { - color: var(--bs-blue); + color: var(--blue-color); font-weight: 600; text-decoration: underline; } @@ -1563,7 +1636,7 @@ hr { } .toggleBtn:hover { - color: #31bb6b !important; + color: var(--light-green) !important; } input[type='radio']:checked + label { @@ -1571,7 +1644,7 @@ input[type='radio']:checked + label { } input[type='radio']:checked + label:hover { - color: black !important; + color: var(--black-color) !important; } .dropdownToggle { @@ -1660,11 +1733,11 @@ input[type='radio']:checked + label:hover { } .noOutline input:disabled { - -webkit-text-fill-color: black !important; + -webkit-text-fill-color: var(--black-color) !important; } .noOutline textarea:disabled { - color: var(--bs-black) !important; + color: var(--black-color) !important; opacity: 1; } @@ -1674,10 +1747,10 @@ input[type='radio']:checked + label:hover { .dropdowns { background-color: var(--bs-white); - border: 1px solid #31bb6b; + border: 1px solid var(--light-green); position: relative; display: inline-block; - color: #31bb6b; + color: var(--light-green); } .chipIcon { @@ -1706,7 +1779,7 @@ input[type='radio']:checked + label:hover { } .titlemodal { - color: #707070; + color: var(--grey-bg-color-dark); font-weight: 600; font-size: 32px; width: 65%; @@ -1822,16 +1895,16 @@ input[type='radio']:checked + label:hover { .sampleOrgCreationBtn { width: 100%; background-color: transparent; - color: #707070; - border-color: #707070; + color: var(--grey-bg-color-dark); + border-color: var(--grey-bg-color-dark); display: flex; justify-content: center; align-items: center; } .sampleHover:hover { - border-color: grey; - color: grey; + border-color: var(--gray-white); + color: var(--gray-white); } .sampleModalTitle { @@ -1923,13 +1996,13 @@ input[type='radio']:checked + label:hover { } .searchtitleMemberDetail { - color: #707070; + color: var(--grey-bg-color-dark); font-weight: 600; font-size: 18px; margin-top: 60px; margin-bottom: 20px; padding-bottom: 5px; - border-bottom: 3px solid #eaebef; + border-bottom: 3px solid var(--grey-bg-color); width: 60%; } @@ -1951,23 +2024,23 @@ input[type='radio']:checked + label:hover { } .logintitleMemberDetail { - color: #707070; + color: var(--grey-bg-color-dark); font-weight: 600; font-size: 20px; margin-bottom: 30px; padding-bottom: 5px; - border-bottom: 3px solid #eaebef; + border-bottom: 3px solid var(--grey-bg-color); width: 30%; } .logintitleadmin { - color: #707070; + color: var(--grey-bg-color-dark); font-weight: 600; font-size: 20px; margin-top: 50px; margin-bottom: 40px; padding-bottom: 5px; - border-bottom: 3px solid #eaebef; + border-bottom: 3px solid var(--grey-bg-color); width: 60%; } @@ -2025,7 +2098,7 @@ input[type='radio']:checked + label:hover { transition: transform 0.2s, box-shadow 0.2s; - background-color: #eaebef; + background-color: var(--grey-bg-color); margin-right: 13px; } @@ -2046,7 +2119,7 @@ input[type='radio']:checked + label:hover { flex-direction: column; width: 30%; padding: 40px 30px; - background: #ffffff; + background: var(--white-color); border-color: var(--grey-border-box-color); border-width: 5px; border-radius: 10px; @@ -2062,12 +2135,12 @@ input[type='radio']:checked + label:hover { } .titlemodalMemberDetail { - color: #707070; + color: var(--grey-bg-color-dark); font-weight: 600; font-size: 20px; margin-bottom: 20px; padding-bottom: 5px; - border-bottom: 3px solid #eaebef; + border-bottom: 3px solid var(--grey-bg-color); width: 65%; } @@ -2093,7 +2166,7 @@ input[type='radio']:checked + label:hover { margin-top: 5px; transform: scale(1.2); cursor: pointer; - color: #707070; + color: var(--grey-bg-color-dark); } .greenregbtnMemberDetail { @@ -2103,7 +2176,7 @@ input[type='radio']:checked + label:hover { box-shadow: 0 2px 2px var(--grey-border-box-color); padding: 10px 10px; border-radius: 5px; - background-color: #eaebef; + background-color: var(--grey-bg-color); font-size: 16px; color: var(--bs-white); outline: none; @@ -2118,12 +2191,12 @@ input[type='radio']:checked + label:hover { margin: 1rem 0 0; margin-right: 2px; margin-top: 10px; - border: 1px solid #eaebef; + border: 1px solid var(--grey-bg-color); padding: 10px 10px; border-radius: 5px; background-color: var(--bs-white); font-size: 16px; - color: #707070; + color: var(--grey-bg-color-dark); outline: none; font-weight: 600; cursor: pointer; @@ -2208,7 +2281,7 @@ input[type='radio']:checked + label:hover { .memberfontcreatedbtn { border-radius: 7px; border-color: var(--grey-border-box-color); - background-color: #eaebef; + background-color: var(--grey-bg-color); color: var(--bs-white); box-shadow: none; height: 2.5rem; @@ -2235,30 +2308,30 @@ input[type='radio']:checked + label:hover { .activeBtn { width: 100%; display: flex; - color: #fff; - border: 1px solid #000; - background-color: #eaebef; + color: var(--white-color); + border: 1px solid var(--black-color); + background-color: var(--grey-bg-color); transition: 0.5s; } .activeBtn:hover { - color: #fff; - background: #23864c; + color: var(--white-color); + background: var(--dark-emerald-green); transition: 0.5s; } .inactiveBtn { width: 100%; display: flex; - color: #707070; - border: 1px solid #31bb6a60; - background-color: #fff; + color: var(--grey-bg-color-dark); + border: 1px solid var(--off-light-green); + background-color: var(--white-color); transition: 0.5s; } .inactiveBtn:hover { - color: #fff; - background: #eaebef; + color: var(--white-color); + background: var(--grey-bg-color); transition: 0.5s; } @@ -2284,27 +2357,27 @@ input[type='radio']:checked + label:hover { } .activeBtn .bgFill { - background-color: #fff; + background-color: var(--white-color); } .activeBtn i { - color: #707070; + color: var(--grey-bg-color-dark); } .inactiveBtn .bgFill { - background-color: #eaebef; + background-color: var(--grey-bg-color); } .inactiveBtn:hover .bgFill { - background-color: #fff; + background-color: var(--white-color); } .inactiveBtn i { - color: #fff; + color: var(--white-color); } .inactiveBtn:hover i { - color: #707070; + color: var(--grey-bg-color-dark); } .topRadius { @@ -2327,11 +2400,11 @@ input[type='radio']:checked + label:hover { } .toporglocMemberDetail span { - color: #737373; + color: var(--grey-bg-color-dark); } .inputColor { - background: #f1f3f6; + background: var(--input-area-color); } .cardHeaderMemberDetail { @@ -2374,7 +2447,7 @@ input[type='radio']:checked + label:hover { .dateboxMemberDetail > div > input { padding: 0.5rem 0 0.5rem 0.5rem !important; /* top, right, bottom, left */ - background-color: #f1f3f6; + background-color: var(--input-area-color); border-radius: var(--bs-border-radius) !important; border: none !important; } @@ -2385,17 +2458,17 @@ input[type='radio']:checked + label:hover { .dateboxMemberDetail > div > fieldset { border: none !important; - /* background-color: #f1f3f6; */ - border-radius: var(--bs-border-radius) !important; + /* background-color: var(--input-area-color); */ + border-radius: var(--bs-border-radius, 4px) !important; } .dateboxMemberDetail > div { margin: 0.5rem !important; - background-color: #f1f3f6; + background-color: var(--input-area-color); } input::file-selector-button { - background-color: black; + background-color: var(--black-color); color: var(--bs-white); } @@ -2411,7 +2484,7 @@ input::file-selector-button { .tagLink:hover { font-weight: 800; - color: var(--bs-blue); + color: var(--blue-color); text-decoration: underline; } @@ -2530,7 +2603,7 @@ input::file-selector-button { .cardBody .textWrapper .secondaryText { font-size: 14px; display: block; - color: var(--bs-secondary); + color: var(--bs-secondary, var(--bs-gray-400)); } /* Loading OrgList CSS */ @@ -2541,7 +2614,7 @@ input::file-selector-button { height: calc(120px + 2rem); padding: 1rem; border-radius: 8px; - outline: 1px solid var(--bs-gray-200); + outline: 1px solid var(--bs-gray-200, var(--bs-gray-300)); position: relative; } @@ -2563,7 +2636,7 @@ input::file-selector-button { } .titlemodaldialog { - color: #707070; + color: var(--grey-bg-color-dark); font-size: 20px; margin-bottom: 20px; padding-bottom: 5px; @@ -2573,7 +2646,7 @@ form label { font-weight: bold; padding-bottom: 1px; font-size: 14px; - color: #707070; + color: var(--grey-bg-color-dark); } form > input { @@ -2674,7 +2747,7 @@ form > input { } .row .right_portion::-webkit-scrollbar-thumb { - background-color: rgba(0, 0, 0, 0.2); + background-color: var(--black-shadow-color); border-radius: 4px; } @@ -2723,14 +2796,14 @@ form > input { height: 100%; display: flex; background-color: var(--search-button-bg); - border-color: var(--search-button-border); + border-color: var(--search-button-border, var(--black-color)); justify-content: center; align-items: center; } .login_btn { background-color: var(--search-button-bg); - border-color: var(--search-button-border); + border-color: var(--search-button-border, var(--black-color)); margin-top: 1rem; margin-bottom: 1rem; width: 100%; @@ -2895,9 +2968,9 @@ form > input { .cardTemplate { padding: 2rem; - background-color: #fff; + background-color: var(--white-color); border-radius: 0.8rem; - border: 1px solid var(--bs-gray-200); + border: 1px solid var(--bs-gray-200, var(--bs-gray-300)); } .keyWrapper { @@ -3135,7 +3208,7 @@ form > input { transform: scale(1.2); cursor: pointer; border: none; - color: #707070; + color: var(--grey-bg-color-dark); font-weight: 600; font-size: 16px; } @@ -3154,10 +3227,10 @@ button[data-testid='createPostBtn'] { font-size: 10px; position: relative; text-indent: -9999em; - border-top: 1.1em solid rgba(255, 255, 255, 0.2); - border-right: 1.1em solid rgba(255, 255, 255, 0.2); - border-bottom: 1.1em solid rgba(255, 255, 255, 0.2); - border-left: 1.1em solid #febc59; + border-top: 1.1em solid var(--white-shadow-color); + border-right: 1.1em solid var(--white-shadow-color); + border-bottom: 1.1em solid var(--white-shadow-color); + border-left: 1.1em solid var(--light-orange); -webkit-transform: translateZ(0); -ms-transform: translateZ(0); transform: translateZ(0); @@ -3275,7 +3348,7 @@ button[data-testid='createPostBtn'] { .cardItem .creator { font-size: 1rem; - color: var(--bs-success, #21d015); + color: var(--bs-success, var(--green-color)); } .rightCard { display: flex; @@ -3313,7 +3386,7 @@ button[data-testid='createPostBtn'] { display: flex !important; align-items: center; background-color: transparent; - color: #31bb6b; + color: var(--light-green); } .entryaction .spinner-grow { @@ -3332,7 +3405,7 @@ button[data-testid='createPostBtn'] { display: flex; flex-direction: column; padding: 1rem 1rem 0 1rem; - background-color: #f6f8fc; + background-color: var(--input-area-color); transition: 0.5s; font-family: var(--bs-leftDrawer-font-family); } @@ -3397,7 +3470,7 @@ button[data-testid='createPostBtn'] { .leftDrawer .profileContainer:focus { outline: none; - background-color: var(--bs-gray-100); + background-color: var(--bs-gray-100, var(--white-color)); } .leftDrawer .imageContainer { @@ -3562,6 +3635,183 @@ button[data-testid='createPostBtn'] { } } +/* LeftDrawer general styles */ +.leftDrawer { + height: 100vh; /* Ensure it spans the full height */ + overflow-y: auto; /* Enable vertical scrolling */ + transition: transform 0.3s ease; + will-change: transform; /* NEW */ + position: fixed; /* Ensure it's positioned properly */ + padding-bottom: 1rem; /* Prevent last item clipping */ + overscroll-behavior: contain; + /* Improve scroll performance */ + -webkit-overflow-scrolling: touch; +} + +.hideElemByDefault { + display: none; +} + +[data-hidden='true'] { + visibility: hidden; +} + +[data-hidden='false'] { + visibility: visible; +} + +.inactiveDrawer { + transform: translateX(-100%); + &[data-hidden='true'] { + /* Specific styles for inactive drawers if needed */ + } +} + +.activeDrawer { + transform: translateX(0); + &[data-hidden='false'] { + /* Specific styles for active drawers if needed */ + } +} + +/* Organization Section */ +.organizationContainer { + padding-right: 3rem; +} + +.profileContainer { + display: flex; + align-items: center; + justify-content: space-between; + width: 100%; + /* Add focus styles for keyboard navigation */ + &:focus-within { + @extend .reusable-focus-visible; /* Referencing the reusable class from the general section */ + } +} + +.bg-danger { + background-color: var(--delete-button-color); +} + +.text-start { + text-align: start; +} + +.text-white { + color: var(--bs-white); +} + +.imageContainer img { + width: 40px; + height: 40px; + border-radius: 50%; + /* Add alt text styles */ + &[alt] { + font-size: 0.875rem; + color: var(--bs-emphasis-color); + } +} + +.profileText { + margin-left: 1rem; +} + +.primaryText { + font-weight: bold; + color: var(--bs-emphasis-color, #000); + @extend .reusable-text-ellipsis; /* Referencing the reusable class from the general section */ +} + +.secondaryText { + font-size: 0.9rem; + color: var(--bs-secondary-text); + @extend .reusable-text-ellipsis; /* Referencing the reusable class from the general section */ +} + +/* Dropdown and options list */ +.titleHeader { + font-size: 1.2rem; + color: var(--bs-secondary); + line-height: 1.5; /* NEW */ + margin: var(--spacing-md, 1rem) 0; /* NEW */ +} + +/* Active and inactive buttons */ +.activeButton, +.inactiveButton { + position: relative; + transition: all 0.2s ease; + + &:active { + transform: scale(0.98); + } + + &.focus-visible { + @extend .reusable-focus-visible; /* Referencing the reusable class from the general section */ + } +} + +.activeButton { + background-color: var(--grey-bg-color); + color: black; + + &::before { + @extend .reusable-indicator; /* Referencing the reusable class from the general section */ + } + + &::after { + @extend .reusable-arrow-indicator; /* Referencing the reusable class from the general section */ + } +} + +.activeButton:hover .arrow-indicator { + transform: translateY(-50%) scale(1.1); + opacity: 1; +} + +.inactiveButton { + background-color: transparent; + color: var(--bs-emphasis-color, #000); + + &:hover { + background-color: var(--grey-bg-color); + } +} + +/* Icon wrapper styles */ +.iconWrapper { + display: flex; + align-items: center; + margin-inline-end: 8px; + margin-inline-start: 0; + + &[aria-label]:not([aria-label='']) { + position: relative; + + &::after { + content: attr(aria-label); + position: absolute; + inset-inline-start: 100%; + background: var(--bs-dark); + color: var(--bs-white); + padding: 0.25rem 0.5rem; + border-radius: 4px; + font-size: 0.875rem; + opacity: 0; + visibility: hidden; + transform: translateX(var(--transform-direction, 8px)); + transition: all 0.2s ease; + } + + &:hover::after { + opacity: 1; + visibility: visible; + transform: translateX(0); + } + } +} + /* CustomRecurrenceModal.tsx */ .titlemodalCustomRecurrenceModal { @@ -3636,7 +3886,7 @@ button[data-testid='createPostBtn'] { .recurrenceRuleSubmitBtn:hover { transform: translateY(-1px); - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); + box-shadow: 0 2px 4px var(--black-shadow-color); } .recurrenceRuleSubmitBtn:focus-visible { @@ -3645,7 +3895,7 @@ button[data-testid='createPostBtn'] { } .attendance-modal .borderRightGreen { - border-right: 1px solid green; + border-right: 1px solid var(--light-dark-green); } .attendance-modal .positionedTopRight { top: 10px; @@ -3795,16 +4045,16 @@ button[data-testid='createPostBtn'] { background-color: rgba(0, 0, 0, 0); padding: 0; border: none; - color: black; + color: var(--black-color); transition: all 0.2s ease-in-out; border-radius: 4px; } .cardActionBtn:hover, .cardActionBtn:focus-visible { - background-color: ghostwhite; + background-color: var(--dropdown-hover-color); border: none; - color: black !important; + color: var(--black-color) !important; outline: 2px solid var(--subtle-blue-grey); outline-offset: 2px; } @@ -4035,7 +4285,7 @@ button[data-testid='createPostBtn'] { padding-right: 40px; width: 100%; border-radius: 4px; - border: 1px solid #ced4da; + border: 1px solid var(--bs-gray-300); } .submitBtn { @@ -4052,3 +4302,1587 @@ button[data-testid='createPostBtn'] { overflow-y: scroll; overflow-x: hidden; } + +/* VolunteerViewModal.tsx */ + +.modalTitle { + margin: 0; +} + +.modalForm { + padding: 1rem; +} + +.formGroup { + margin-bottom: 1rem; +} + +.tableImage { + width: 40px; + height: 40px; + border-radius: 50%; + margin-right: 8px; +} + +.statusGroup { + display: flex; + gap: 1rem; + margin: 0 auto; + margin-bottom: 0.5rem; + role: 'status'; +} + +.statusIcon { + margin-right: 0.5rem; +} + +.acceptedStatus { + color: var(--bs-primary); + -webkit-text-fill-color: var(--bs-primary); + outline: 1px solid currentColor; + border-radius: 4px; + padding: 2px 4px; +} + +.pendingStatus { + color: var(--bs-warning); + -webkit-text-fill-color: var(--bs-warning); + outline: 1px solid currentColor; + border-radius: 4px; + padding: 2px 4px; +} + +.hoursField { + width: 100%; +} + +.groupsLabel { + font-weight: lighter; + margin-left: 0.5rem; + margin-bottom: 0; + font-size: 0.8rem; + color: var(--bs-secondary); +} + +.tableHeader { + font-weight: bold; +} + +.tableRow:last-child td, +.tableRow:last-child th { + border: 0; +} + +/* UpdateSession.tsx */ + +.updateTimeoutCard { + width: 700px; + background: var(--white-color); + border: none; + border-radius: 16px; + filter: drop-shadow(0px 4px 15.3px rgba(0, 0, 0, 0.08)); + padding: 20px; +} + +.updateTimeoutCardHeader { + background: none; + padding: 16px; + border-bottom: none; +} + +.updateTimeoutCardTitle { + font-family: 'Lato', sans-serif; + font-weight: 600; + font-size: 24px; + color: var(--black-color); +} + +.updateTimeoutCardBody { + padding: 20px; +} + +.updateTimeoutCurrent { + font-family: 'Lato', sans-serif; + font-weight: 400; + font-size: 16px; + color: var(--black-color); + margin-bottom: 20px; +} + +.updateTimeoutLabel { + font-family: 'Lato', sans-serif; + font-weight: 400; + font-size: 16px; + color: var(--black-color); + margin-bottom: 10px; +} + +.updateTimeoutLabelsContainer { + display: flex; + flex-direction: column; + align-items: start; +} + +.updateTimeoutValue { + color: var(--light-more-green); + font-weight: bold; +} + +.updateTimeoutSliderLabels { + display: flex; + justify-content: space-between; + font-size: 0.9rem; + color: var(--grey-dark); +} + +.updateTimeoutButtonContainer { + display: flex; + justify-content: right; + margin-top: 20px; +} + +.updateTimeoutButton { + width: 112px; + height: 36px; + background: var(--light-green); + border-radius: 6px; + font-family: 'Lato', sans-serif; + font-weight: 500; + font-size: 16px; + color: var(--white-color); + display: flex; + align-items: center; + justify-content: center; + border: none; + box-shadow: none; +} + +.updateTimeoutButton:hover { + background-color: var(--light-more-green); + border-color: var(--light-more-green); + box-shadow: none; +} + +.updateTimeoutButton:active { + transform: scale(0.98); +} + +/* UserListCard.tsx */ + +.memberlist { + margin-top: -1px; +} + +.memberimg { + width: 12.5rem; + height: 6.25rem; + border-radius: 7px; + margin-left: 20px; +} + +.singledetails { + display: flex; + flex-direction: row; + justify-content: space-between; +} + +.singledetails p { + margin-bottom: -5px; +} + +.singledetails_data_left { + margin-top: 10px; + margin-left: 10px; + color: var(--grey-dark); +} + +.singledetails_data_right { + justify-content: right; + margin-top: 10px; + text-align: right; + color: var(--grey-dark); +} + +.membername { + font-size: 16px; + font-weight: bold; +} + +.memberfont { + margin-top: 3px; +} + +.memberfont > span { + width: 80%; +} + +.memberfontcreated { + margin-top: 18px; +} + +.memberfontcreatedbtnUserListCard { + margin-top: 33px; + border-radius: 7px; + border-color: var(--light-green); + background-color: var(--light-green); + color: var(--white-color); + padding-right: 10px; + padding-left: 10px; + justify-content: flex-end; + float: right; + text-align: right; + box-shadow: none; +} + +@media only screen and (max-width: var(--breakpoint-mobile)) { + .singledetails { + margin-left: 20px; + } + + .memberimg { + margin: auto; + } + + .singledetails_data_right { + margin-right: -52px; + } + + .singledetails_data_left { + margin-left: 0px; + } +} + +/* UserPasswordUpdate.tsx */ + +.userupdatediv { + border: 1px solid var(--grey-border); + box-shadow: 2px 1px var(--grey-border); + padding: 25px 16px; + border-radius: 5px; + background: var(--white-color); +} + +.dispflexUserPasswordUpdate { + display: flex; + justify-content: flex-start; + margin: 0 auto; +} + +.dispbtnflex { + width: 90%; + display: flex; + margin: 20px 30% 0 30%; +} + +.dispflexUserPasswordUpdate > div { + width: 50%; + margin-right: 50px; +} + +.whitebtn { + margin: 1rem 0 0; + margin-top: 10px; + border: 1px solid var(--grey-border); + box-shadow: 0 2px 2px var(--grey-border); + padding: 10px 20px; + border-radius: 5px; + background: none; + width: 20%; + font-size: 16px; + color: var(--light-green); + outline: none; + font-weight: 600; + cursor: pointer; + float: left; + transition: + transform 0.2s, + box-shadow 0.2s; +} + +/* VenueModal.tsx */ + +.previewVenueModal { + display: flex; + position: relative; + width: 100%; + margin-top: 10px; + justify-content: center; +} + +.previewVenueModal img { + width: 400px; + height: auto; +} + +.closeButtonP { + position: absolute; + top: 0px; + right: 0px; + background: transparent; + transform: scale(1.2); + cursor: pointer; + border: none; + color: var(--grey-dark); + font-weight: 600; + font-size: 16px; +} + +/* YearlyEventCalender.tsx */ + +.calendar__weekdays { + display: grid; + grid-template-columns: repeat(7, 1fr); + background-color: var(--grey-dark); + height: 60px; +} + +.calendar__days { + display: grid; + grid-template-columns: repeat(7, minmax(0, 1fr)); + grid-template-rows: repeat(6, 1fr); +} + +.day__outside { + color: var(--grey-dark) !important; +} + +.day__selected { + background-color: var(--blue-primary); + color: var(--grey-dark); +} + +.day__today { + background-color: var(--light-neon-green); + font-weight: 700; + text-decoration: underline; + color: var(--light-green); +} + +.yearlyCalender { + background-color: var(--white-color); + box-sizing: border-box; +} + +.closebtnYearlyEventCalender { + padding: 10px; +} + +.yearlyCalendarHeader { + display: flex; + flex-direction: row; +} + +.yearlyCalendarHeader > div { + font-weight: 600; + font-size: 2rem; + padding: 0 10px; + color: var(--grey-dark); +} + +.cardYearlyEventCalender { + padding: 16px; + text-align: center; + height: 21rem; +} + +.cardHeaderYearlyEventCalender { + text-align: left; +} + +.rowYearlyEventCalender { + margin: 1px -5px; +} + +.rowYearlyEventCalender:after { + content: ''; + display: table; + clear: both; + margin: 0 -5px; + content: ''; + display: table; + clear: both; +} + +.weekday__yearly { + display: flex; + justify-content: center; + align-items: center; + background-color: var(--white-color); + font-weight: 600; +} + +.columnYearlyEventCalender { + float: left; + width: 25%; + padding: 10px; +} + +.btn__more { + border: 0px; + font-size: 14px; + background-color: initial; + font-weight: 600; + transition: all 200ms; + position: relative; + display: block; + margin: -9px; + margin-top: -28px; +} + +.btn__more:hover { + color: var(--light-green); +} + +.expand_event_list { + display: block; +} + +.expand_list_container { + width: 200px; + max-height: 250px; + z-index: 10; + position: absolute; + left: auto; + right: auto; + overflow: auto; + padding: 10px 4px 0px 4px; + background-color: var(--grey-bg-color); + border: 1px solid var(--grey-border); + border-radius: 5px; + margin: 5px; +} + +@media only screen and (max-width: var(--breakpoint-tablet)) { + .event_list { + display: none; + } + + .expand_list_container { + width: 150px; + padding: 4px 4px 0px 4px; + } +} + +@media only screen and (max-width: var(--breakpoint-mobile)) { + .btn__more { + font-size: 12px; + } + + .columnYearlyEventCalender { + float: left; + width: 100%; + padding: 10px; + } +} + +/* AgendaItems */ + +.titlemodalAgendaItems { + color: var(--bs-gray-600); + font-weight: 600; + font-size: 20px; + margin-bottom: 20px; + padding-bottom: 5px; + border-bottom: 3px solid var(--bs-primary); + width: 65%; +} + +.agendaItemsOptionsButton { + width: 24px; + height: 24px; +} + +.agendaItemModal { + max-width: 80vw; + margin-top: 2vh; + margin-left: 13vw; +} + +.greenregbtnAgendaItems { + margin: 1rem 0 0; + margin-top: 15px; + border: 1px solid var(--bs-gray-300); + box-shadow: 0 2px 2px var(--bs-gray-300); + padding: 10px 10px; + border-radius: 5px; + background-color: var(--bs-primary); + width: 100%; + font-size: 16px; + color: var(--bs-white); + outline: none; + font-weight: 600; + cursor: pointer; + transition: + transform 0.2s, + box-shadow 0.2s; + width: 100%; +} + +.previewFile { + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + margin-top: 10px; +} + +.previewFile img, +.previewFile video { + width: 100%; + max-width: 400px; + height: auto; + margin-bottom: 10px; +} + +.attachmentPreview { + position: relative; + width: 100%; +} + +.closeButtonFile { + position: absolute; + top: 10px; + right: 10px; + background: transparent; + transform: scale(1.2); + cursor: pointer; + border: none; + color: var(--grey-dark); + font-weight: 600; + font-size: 16px; + cursor: pointer; +} + +.categoryContainer { + display: flex; + flex-wrap: wrap; + gap: 10px; + justify-content: center; +} + +.categoryChip { + display: inline-flex; + align-items: center; + background-color: var(--grey-bg-color); + border-radius: 16px; + padding: 0 12px; + font-size: 14px; + height: 32px; + margin: 5px; +} + +.urlListItem { + display: flex; + align-items: center; + justify-content: space-between; + padding: 5px 0; +} + +.urlIcon { + margin-right: 10px; +} + +.deleteButtonAgendaItems { + margin-left: auto; + padding: 2px 5px; +} + +.urlListItem a { + text-decoration: none; + color: inherit; +} + +.urlListItem a:hover { + text-decoration: underline; +} + +.agendaItemRow { + border: 1px solid var(--grey-border); + border-radius: 4px; + transition: box-shadow 0.2s ease; + background-color: var(--white-color); +} + +.agendaItemRow:hover { + background-color: var(--white-color); +} + +.dragging { + box-shadow: 0 4px 8px var(--grey-border-box-color); + z-index: 1000; + background-color: var(--grey-bg-color); +} + +.droppable { + background-color: var(--grey-bg-color); +} + +.droppableDraggingOver { + background-color: var(--grey-bg-color); +} + +.tableHeadAgendaItems { + background-color: var(--light-green) !important; + color: var(--white); + border-radius: 20px 20px 0px 0px !important; + padding: 20px; +} + +@media (max-width: 768px) { + .agendaItemModal { + margin: 10vh auto; + max-width: 90%; + } + + .titlemodalAgendaItems { + width: 90%; + } + + .greenregbtnAgendaItems { + width: 90%; + } +} + +@media (max-width: 576px) { + .agendaItemModal { + margin: 5vh auto; + max-width: 95%; + } + + .titlemodalAgendaItems { + width: 100%; + } + + .greenregbtnAgendaItems { + width: 100%; + } +} + +/* AddOnStore.tsx */ + +.containerAddOnStore { + display: flex; + flex-direction: column; + background: var(--white); + margin: 2px; + padding: 10px; + border-radius: 20px; +} + +.colAddOnStore { + display: flex; + align-items: center; + justify-content: space-between; +} + +.inputAddOnStore { + display: flex; + position: relative; + width: 560px; +} + +.cardGridItem { + width: 38vw; +} + +.justifyspAddOnStore { + display: grid; + width: 100%; + justify-content: space-between; + align-items: baseline; + grid-template-rows: auto; + grid-template-columns: repeat(2, 1fr); + grid-gap: 0.8rem 0.4rem; +} + +@media screen and (max-width: 600px) { + .cardGridItem { + width: 100%; + } + .justifyspAddOnStore { + grid-template-columns: 1fr; + justify-content: center; + align-items: start; + } +} + +/* Advertisements.tsx */ + +.containerAdvertisements { + background-color: var(--white); + border-radius: 20px; +} + +.justifyspAdvertisements { + display: grid; + width: 100%; + margin-top: 30px; +} + +.colAdvertisements { + display: flex; + align-items: center; + justify-content: space-between; + padding: 10px; +} + +.inputAdvertisements { + display: flex; + position: relative; + width: 560px; +} + +.listBoxAdvertisements { + display: grid; + width: 100%; + grid-template-rows: auto; + grid-template-columns: repeat(6, 1fr); + grid-gap: 0.8rem 0.4rem; +} + +/* AdvertisementRegister.tsx */ + +.modalbtn { + margin-top: 1rem; + display: flex !important; + margin-left: auto; + align-items: center; +} + +.modalbtn i, +.button i { + height: min-content; + margin-right: 4px; +} + +.previewAdvertisementRegister { + display: flex; + position: relative; + width: 100%; + margin-top: 10px; + justify-content: center; +} + +.previewAdvertisementRegister img { + width: 400px; + height: auto; +} + +.previewAdvertisementRegister video { + width: 400px; + height: auto; +} + +.closeButtonAdvertisementRegister { + background: transparent; + cursor: pointer; + border: none; + color: var(--grey-dark); + font-weight: 600; + font-size: 16px; + margin-bottom: 10px; + cursor: pointer; +} + +.buttonAdvertisementRegister { + min-width: 102px; +} + +.editHeader { + background-color: var(--light-green); + color: var(--white-color); +} + +.link_check { + display: flex; + justify-content: center; + align-items: flex-start; +} + +/* EventCalendar.tsx */ + +.calendar { + font-family: sans-serif; + font-size: 1.2rem; + margin-bottom: 20px; + background: var(--grey-bg-color); + border-radius: 10px; + padding: 5px; +} + +.calendar__header { + display: flex; + align-items: center; + margin: 2rem 10px 0px 10px; +} + +.calendar__header_month { + margin: 0.5rem; + color: var(--grey-dark); + font-weight: 800; + font-size: 55px; + display: flex; + gap: 23px; + flex-direction: row; +} + +.calendar__header_month div { + font-weight: 400; + color: var(--black-color); + font-family: Outfit; +} + +.buttonEventCalendar { + border-radius: 100px; + color: var(--bs-gray-600); + background-color: var(--black-shadow-color); + font-weight: bold; + border: 0px; + font-size: 20px; +} + +.calendar__weekdays { + display: grid; + grid-template-columns: repeat(7, 1fr); + background-color: var(--black-color); + font-family: Outfit; + height: 60px; +} + +.calendar__scroll { + height: 80vh; + padding: 10px; +} + +.weekday { + display: flex; + justify-content: center; + align-items: center; + background-color: var(--white); + font-weight: 600; +} + +.calendar__days { + display: grid; + grid-template-columns: repeat(7, minmax(0, 1fr)); + grid-template-rows: repeat(6, 1fr); +} + +.calendar_hour_text_container { + display: flex; + flex-direction: row; + align-items: flex-end; + border-right: 1px solid var(--grey-border); + width: 40px; +} + +.calendar_timezone_text { + top: -10px; + left: -11px; + position: relative; + color: var(--grey-dark); + font-size: 9px; +} + +.calendar_hour_block { + display: flex; + flex-direction: row; + border-bottom: 1px solid var(--grey-border); + position: relative; + height: 50px; + border-bottom-right-radius: 5px; +} + +.btn__more { + border: 0px; + font-size: 14px; + background-color: initial; + color: var(--gray-blue); + font-weight: 600; + transition: all 200ms; + position: relative; + display: block; + margin: 2px; +} + +.btn__more:hover { + color: var(--grey-dark); +} + +.event_list_parent { + position: relative; + width: 100%; +} + +.event_list_parent_current { + background-color: var(--grey-bg-color); + position: relative; + width: 100%; +} + +.dummyWidth { + width: 1px; +} + +.day { + background-color: var(--white); + padding-left: 0.3rem; + padding-right: 0.3rem; + border-radius: 10px; + margin: 5px; + background-color: var(--white); + border: 1px solid var(--grey-border); + color: var(--grey-dark); + font-weight: 600; + height: 9rem; + position: relative; +} + +.day_weekends { + background-color: var(--black-shadow-color); +} + +.day__outside { + background-color: var(--white); + color: var(--grey-dark); +} + +.day__selected { + background-color: var(--blue-primary); + color: var(--grey-dark); +} + +.day__today { + background-color: var(--grey-bg-color); + font-weight: 700; + text-decoration: underline; + color: var(--light-green); +} + +.day__events { + background-color: var(--white); +} + +.expand_event_list { + display: block; +} + +.event_list_hour { + display: flex; + flex-direction: row; +} + +.expand_list_container { + width: 200px; + max-height: 250px; + z-index: 10; + position: absolute; + left: auto; + right: auto; + overflow: auto; + padding: 10px 4px 0px 4px; + background-color: var(--black-shadow-color); + border: 1px solid var(--grey-border); + border-radius: 5px; + margin: 5px; +} + +.holidays_card { + background-color: var(--black-shadow-color); +} + +.events_card { + background-color: var(--white); +} + +.holidayText { + font-size: 14px; + color: var(--grey-dark); +} + +.eventsLegend { + display: flex; + align-items: center; + gap: 8px; +} + +.list_container { + padding: 5px; + width: fit-content; + display: flex; + align-items: center; + gap: 8px; +} + +.holidayIndicator { + background-color: var(--grey-bg-color-dark); +} + +.organizationIndicator { + background-color: var(--gray-blue); +} + +.legendText { + font-size: 14px; + color: var(--grey-dark); +} + +.card_list { + list-style: none; + padding: 0; + margin: 0; +} + +.card_list_item { + display: flex; + align-items: center; + margin-bottom: 10px; + font-size: 14px; + color: var(--grey-bg-color-dark); +} + +.holiday_date { + font-weight: 500; + margin-right: 10px; + color: var(--burnt-orange); +} + +.calendar_infocards { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: flex-start; + gap: 20px; + padding: 20px; + background-color: var(--grey-bg-color); +} + +.holidays_card, +.events_card { + flex: 1; + padding: 20px; + border-radius: 10px; + box-shadow: var(--card-shadow); +} + +.holidays_card { + background-color: var(--white); +} + +.events_card { + background-color: var(--white-color); +} + +.legend { + display: flex; + flex-direction: column; + gap: 12px; +} + +.card_list_item:hover { + background-color: var(--grey-bg-color-dark); + transition: background-color 0.2s ease; +} + +.card_list_item:focus-visible { + background-color: var(--grey-bg-color-dark); + transition: background-color 0.2s ease; +} + +@media only screen and (max-width: var(--breakpoint-mobile)) { + .btn__more { + font-size: 12px; + } +} + +@media only screen and (max-width: var(--breakpoint-tablet)) { + .holidayIndicator, + .organizationIndicator { + width: 16px; + height: 10px; + } + + .expand_list_container { + width: 150px; + padding: 4px 4px 0px 4px; + } +} + +/* EventHeader.tsx */ + +.calendarEventHeader { + width: 100%; + margin-bottom: 20px; + background: var(--grey-bg-color); + border-radius: 10px; + padding: 5px; +} + +.flex_grow { + flex-grow: 1; +} + +.space { + flex: 1; + display: flex; + align-items: center; + justify-content: space-around; +} + +.createButtonEventHeader { + background-color: var(--grey-bg-color); + color: var(--black-color); + width: 130px; + margin-left: 5px; + border: 1px solid var(--brown-color); +} + +.createButtonEventHeader:hover { + background-color: var(--grey-bg-color); + color: var(--black-color); + border: 1px solid var(--brown-color); +} + +.selectTypeEventHeader { + border-radius: 10px; + margin-left: 5px; +} + +/* EventListCardModals.tsx */ + +.dispflexEventListCardModals { + display: flex; + cursor: pointer; + justify-content: space-between; + margin: 10px 5px 5px 0px; +} + +.eventtitle { + margin-bottom: 0px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} + +.checkboxdivEventListCardModals > div label { + margin-right: 50px; +} + +.checkboxdivEventListCardModals > label > input { + margin-left: 10px; +} + +.dispflexEventListCardModals > input { + width: 20%; + border: none; + box-shadow: none; + margin-top: 5px; +} + +.checkboxContainer { + display: flex; + justify-content: space-between; +} + +.checkboxdivEventListCardModals { + display: flex; + flex-direction: column; +} + +.previewEventListCardModals { + display: flex; + flex-direction: row; + font-weight: 700; + font-size: 16px; + color: var(--black-color); + margin: 0; +} + +@media only screen and (max-width: 600px) { + .checkboxContainer { + flex-direction: column; + } + + .datediv { + flex-direction: column; + } + + .datediv > div { + width: 100%; + margin-left: 0; + margin-bottom: 10px; + } + + .datediv > div p { + margin-bottom: 5px; + } +} + +.customButton { + width: 90%; + margin: 0 auto; +} + +/* EventListCard.tsx */ + +.cardsEventListCard { + width: 100%; + background: var(--subtle-blue-grey) !important; + padding: 2px 3px; + border-radius: 5px; + border: 1px solid var(--grey-border); + box-shadow: 0 3px 2px var(--grey-border-box-color); + color: var(--grey-dark); + box-sizing: border-box; + position: relative; + overflow: hidden; + transition: all 0.3s; + margin-bottom: 5px; +} + +.cardsEventListCard h2 { + font-size: 15px; + color: var(--grey-dark); + font-weight: 500; +} + +.cardsEventListCard > h3 { + font-size: 17px; +} + +.cardsEventListCard > p { + font-size: 14px; + margin-top: 0px; + margin-bottom: 7px; +} + +.cardsEventListCard a { + color: var(--white-color); + font-weight: 600; +} + +.cardsEventListCard a:hover { + color: var(--black-color); +} + +.cardsEventListCard:last-child:nth-last-child(odd) { + grid-column: auto / span 2; +} + +.cardsEventListCard:first-child:nth-last-child(even), +.cardsEventListCard:first-child:nth-last-child(even) ~ .box { + grid-column: auto / span 1; +} + +.dispflexEventListCard { + display: flex; + cursor: pointer; + justify-content: space-between; + margin: 10px 5px 5px 0px; +} + +.dispflexEventListCard > input { + width: 20%; + border: none; + box-shadow: none; + margin-top: 5px; +} + +/* OrgPostCard.tsx */ + +.cardOrgPostCard { + width: 100%; + height: 20rem; + margin-bottom: 2rem; +} + +.cardsOrgPostCard h2 { + font-size: 20px; +} + +.cardsOrgPostCard > h3 { + font-size: 17px; +} + +.cardOrgPostCard { + width: 100%; + height: 20rem; + margin-bottom: 2rem; +} + +.cardsOrgPostCard:hover { + filter: brightness(0.8); +} + +.cardsOrgPostCard:hover::before { + opacity: 0.5; +} + +.postimageOrgPostCard { + border-radius: 0px; + width: 100%; + height: 12rem; + max-width: 100%; + max-height: 12rem; + object-fit: cover; + position: relative; + color: var(--black-color); +} + +.previewOrgPostCard { + display: flex; + position: relative; + width: 100%; + margin-top: 10px; + justify-content: center; +} + +.previewOrgPostCard img { + width: 400px; + height: auto; +} + +.previewOrgPostCard video { + width: 400px; + height: auto; +} + +.nopostimage { + border-radius: 0px; + width: 100%; + height: 12rem; + max-height: 12rem; + object-fit: cover; + position: relative; +} + +.menuModal { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + background-color: var(--black-shadow-color); + z-index: 100; +} + +.modalOrgPostCard { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + background-color: var(--modal-background); + z-index: 100; +} + +.modalContentOrgPostCard { + display: flex; + align-items: center; + justify-content: center; + background-color: var(--white); + padding: 20px; + max-width: 800px; + max-height: 600px; + overflow: auto; +} + +.modalImage { + flex: 1; + margin-right: 20px; + width: 25rem; + height: 15rem; +} + +.modalImage img, +.modalImage video { + border-radius: 0px; + width: 100%; + height: 25rem; + max-width: 25rem; + max-height: 15rem; + object-fit: cover; + position: relative; +} + +.modalInfo { + flex: 1; +} + +.titleOrgPostCard { + font-size: 16px; + color: var(--black-color); + font-weight: 600; +} + +.textOrgPostCard { + font-size: 13px; + color: var(--black-color); + font-weight: 300; +} + +.author { + color: var(--grey-dark); + font-weight: 100; + font-size: 13px; +} + +.closeButtonOrgPostCard { + position: relative; + bottom: 5rem; + right: 10px; + padding: 4px; + background-color: var(--red-delete-bg); + color: var(--white-color); + border: none; + cursor: pointer; +} + +.closeButtonP { + position: absolute; + top: 0px; + right: 0px; + background: transparent; + transform: scale(1.2); + cursor: pointer; + border: none; + color: var(--grey-dark); + font-weight: 600; + font-size: 16px; + cursor: pointer; +} + +.cardsOrgPostCard:hover::after { + opacity: 1; + mix-blend-mode: normal; +} + +.cardsOrgPostCard > p { + font-size: 14px; + margin-top: 0px; + margin-bottom: 7px; +} + +.cardsOrgPostCard a { + color: var(--grey-dark); + font-weight: 600; +} + +.cardsOrgPostCard a:hover { + color: var(--black-color); +} + +.infodiv { + margin-bottom: 7px; + width: 15rem; + text-align: justify; + word-wrap: break-word; +} + +.infodiv > p { + margin: 0; +} + +.cardsOrgPostCard:last-child:nth-last-child(odd) { + grid-column: auto / span 2; +} + +.cardsOrgPostCard:first-child:nth-last-child(even), +.cardsOrgPostCard:first-child:nth-last-child(even) ~ .box { + grid-column: auto / span 1; +} + +.toggleClickBtn { + color: var(--light-green); + cursor: pointer; + border: none; + font-size: 12px; + background-color: var(--white-color); +} + +.toggleClickBtnNone { + display: none; +} + +.menuContent { + display: flex; + align-items: center; + justify-content: center; + background-color: var(--white-color); + padding-top: 20px; + max-width: 700px; + max-height: 500px; + overflow: hidden; + position: relative; +} + +.menuOptions { + list-style-type: none; + padding: 0; + margin: 0; +} + +.menuOptions li { + padding: 10px; + border-bottom: 1px solid var(--grey-border); + padding-left: 100px; + padding-right: 100px; + cursor: pointer; +} + +.moreOptionsButton { + position: relative; + bottom: 5rem; + right: 10px; + padding: 2px; + background-color: transparent; + color: var(--black-color); + border: none; + cursor: pointer; +} + +.list { + color: var(--red-delete-text); + cursor: pointer; +} + +/* OrgActionItemCategories.tsx */ + +.iconOrgActionItemCategories { + transform: scale(1.5); + color: var(--bs-danger); + margin-bottom: 1rem; +} + +.btnsContainerOrgActionItemCategories { + display: flex; + margin: 0.5rem 0 1.5rem 0; +} + +.btnsContainerOrgActionItemCategories .input { + flex: 1; + min-width: 18rem; + position: relative; +} + +.btnsContainerOrgActionItemCategories input { + outline: 1px solid var(--bs-gray-400); +} + +.btnsContainerOrgActionItemCategories .input button { + width: 52px; +} + +/* CategoryModal.tsx */ + +.createModal { + margin-top: 20vh; + margin-left: 13vw; + max-width: 80vw; +}