From 0579892e87b09129809b64d48eb5d7978b6ab862 Mon Sep 17 00:00:00 2001 From: spwoodcock Date: Tue, 30 Apr 2024 17:42:52 +0100 Subject: [PATCH 001/186] ci: use hotosm/gh-workflows for container img builds --- .github/workflows/docker-image-push.yml | 58 +++++-------------------- 1 file changed, 11 insertions(+), 47 deletions(-) diff --git a/.github/workflows/docker-image-push.yml b/.github/workflows/docker-image-push.yml index c0f126144d..8cb09f6006 100644 --- a/.github/workflows/docker-image-push.yml +++ b/.github/workflows/docker-image-push.yml @@ -1,4 +1,3 @@ -# name: Build & publish TM backend container image on: @@ -19,50 +18,15 @@ on: - deployment/container-tasking-manager -env: - REGISTRY: ghcr.io - IMAGE_NAME: ${{ github.repository }} - - jobs: - build-and-push-image: - runs-on: ubuntu-latest - # Sets the permissions granted to the `GITHUB_TOKEN` for the actions in this job. - permissions: - contents: read - packages: write - - steps: - - name: Checkout repository - uses: actions/checkout@v4 - - - name: Log in to the Container registry - uses: docker/login-action@v3.0.0 - with: - registry: ${{ env.REGISTRY }} - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - # This step uses [docker/metadata-action](https://github.com/docker/metadata-action#about) to extract tags and labels that will be applied to the specified image. The `id` "meta" allows the output of this step to be referenced in a subsequent step. The `images` value provides the base name for the tags and labels. - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@v5.5.1 - with: - images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} - - tags: | - type=ref,event=pr - type=ref,event=tag - type=ref,event=branch - type=semver,pattern=raw - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} - type=sha - - - name: Build and push Docker image - uses: docker/build-push-action@v5.1.0 - with: - context: . - push: true - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} + backend-build: + uses: hotosm/gh-workflows/.github/workflows/image_build.yml@1.5.1 + with: + image_name: ghcr.io/${{ github.repository }}/backend + build_target: prod + + # frontend-build: + # uses: hotosm/gh-workflows/.github/workflows/image_build.yml@1.5.1 + # with: + # image_name: ghcr.io/${{ github.repository }}/backend + # dockerfile: scripts/docker/Dockerfile.frontend From 74a705a9c06668315b4b13c725fe46d588b93670 Mon Sep 17 00:00:00 2001 From: eternaltyro Date: Thu, 16 May 2024 22:03:13 +0530 Subject: [PATCH 002/186] Cleanup backend dockerfile - Upgrade pdm and pydebug versions - Reduce RUN layers for apt steps - Remove gunicorn workers parameter to allow for WEB_CONCURRENCY env Signed-off-by: eternaltyro <230743+eternaltyro@users.noreply.github.com> --- scripts/docker/Dockerfile.backend | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/scripts/docker/Dockerfile.backend b/scripts/docker/Dockerfile.backend index 11efc15c87..c9f5b46af5 100644 --- a/scripts/docker/Dockerfile.backend +++ b/scripts/docker/Dockerfile.backend @@ -25,7 +25,7 @@ FROM base as extract-deps RUN pip install --no-cache-dir --upgrade pip WORKDIR /opt/python COPY pyproject.toml pdm.lock README.md /opt/python/ -RUN pip install --no-cache-dir pdm==2.7.4 +RUN pip install --no-cache-dir pdm==2.8.0 RUN pdm export --prod --without-hashes > requirements.txt @@ -34,9 +34,8 @@ FROM base as build RUN pip install --no-cache-dir --upgrade pip WORKDIR /opt/python # Setup backend build-time dependencies -RUN apt-get update -RUN apt-get install --no-install-recommends -y build-essential -RUN apt-get install --no-install-recommends -y \ +RUN apt-get update && apt-get install --no-install-recommends -y \ + build-essential \ postgresql-server-dev-15 \ python3-dev \ libffi-dev \ @@ -79,7 +78,7 @@ COPY manage.py . FROM runtime as debug RUN pip install --user --no-warn-script-location \ - --no-cache-dir debugpy==1.6.7 + --no-cache-dir debugpy==1.8.1 CMD ["python", "-m", "debugpy", "--wait-for-client", "--listen", "0.0.0.0:5678", \ "-m", "gunicorn", "-c", "python:backend.gunicorn", "manage:application", \ "--reload", "--log-level", "error"] @@ -93,4 +92,4 @@ RUN python -c "import compileall; compileall.compile_path(maxlevels=10, quiet=1) RUN python -m compileall . USER appuser:appuser CMD ["gunicorn", "-c", "python:backend.gunicorn", "manage:application", \ - "--workers", "1", "--log-level", "error"] + "--log-level", "error"] From b02fafe05a2eb6b3f38be25ab752ce035ca7ca75 Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Thu, 13 Jun 2024 09:24:03 +0545 Subject: [PATCH 003/186] Fix mismatch value for language json file for Traditional Chinese - Related to #6456 --- frontend/src/utils/internationalization.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/utils/internationalization.js b/frontend/src/utils/internationalization.js index c9cbc2b3f3..bb136562e1 100644 --- a/frontend/src/utils/internationalization.js +++ b/frontend/src/utils/internationalization.js @@ -33,7 +33,7 @@ const supportedLocales = [ // { value: 'tl', label: 'Filipino (Tagalog)' }, { value: 'tr', label: 'Türkçe' }, { value: 'uk', label: 'Українська' }, - { value: 'zh', label: '繁體中文' }, + { value: 'zh_TW', label: '繁體中文' }, ]; function getSupportedLocale(locale) { From c64324893889d0bbceca42c6f405aa9eb644b5b1 Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Mon, 15 Jul 2024 11:58:18 +0545 Subject: [PATCH 004/186] Fix activity section loading forever on secondary hashtag empty issue - Related to #6496 --- frontend/src/components/partners/partnersActivity.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/components/partners/partnersActivity.js b/frontend/src/components/partners/partnersActivity.js index e0ffa15c57..c9a4792403 100644 --- a/frontend/src/components/partners/partnersActivity.js +++ b/frontend/src/components/partners/partnersActivity.js @@ -18,9 +18,9 @@ export const Activity = ({ partner }) => { primaryHashtag = primaryHashtag.toLowerCase(); const secondaryHashtags = partner.secondary_hashtag - .split(',') - .map((tag) => tag.trim().replace('#', '').toLowerCase()) - .join(','); + ?.split(',') + ?.map((tag) => tag.trim().replace('#', '').toLowerCase()) + ?.join(','); const response = await fetch( OHSOME_STATS_BASE_URL + `/stats/hashtags/${primaryHashtag},${secondaryHashtags}`, ); From 07f1a8b88c125fad898fa0e70ae1b7c8ddb27327 Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Mon, 15 Jul 2024 12:09:15 +0545 Subject: [PATCH 005/186] Display partner name in the banner when logo not present - Partners Statistics page - Related to #6497 --- frontend/src/views/partnersStats.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/src/views/partnersStats.js b/frontend/src/views/partnersStats.js index 0a990931f3..c2247b747d 100644 --- a/frontend/src/views/partnersStats.js +++ b/frontend/src/views/partnersStats.js @@ -60,7 +60,12 @@ export const PartnersStats = () => {
{/* logo */} - logo + {partner.logo_url ? ( + logo + ) : ( +

{partner.name}

+ )} + {/* new to mapping button */} ); } diff --git a/frontend/src/components/projects/messages.js b/frontend/src/components/projects/messages.js index 129ddbb711..4cc0f78de3 100644 --- a/frontend/src/components/projects/messages.js +++ b/frontend/src/components/projects/messages.js @@ -324,6 +324,10 @@ export default defineMessages({ id: 'project.table.downloadAsCSV', defaultMessage: 'Download CSV', }, + downloadAsCSVError: { + id: 'project.table.downloadAsCSV.error', + defaultMessage: 'Something went wrong. Could not download CSV.', + }, projectsTableEmpty: { id: 'project.table.empty', defaultMessage: 'No projects were found. Try updating the search term or filters if any.', From 5a57a3589ffbe87ac29c8c5669d56e5e77426b79 Mon Sep 17 00:00:00 2001 From: A Vinayak Rugvedi Date: Tue, 27 Aug 2024 18:22:40 +0530 Subject: [PATCH 162/186] Set minimum threshold width of progress bar --- .../src/components/projects/exploreProjectsTable.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/projects/exploreProjectsTable.js b/frontend/src/components/projects/exploreProjectsTable.js index 49e60b5b6f..5910938df3 100644 --- a/frontend/src/components/projects/exploreProjectsTable.js +++ b/frontend/src/components/projects/exploreProjectsTable.js @@ -80,8 +80,16 @@ const COLUMNS = [
0 + ? Math.max(8, row.original.percentMapped) + : row.original.percentMapped + } + secondBarValue={ + row.original.percentValidated > 0 + ? Math.max(8, row.original.percentValidated) + : row.original.percentValidated + } height="half" small={false} /> From 51c8c3b4ac4ddb642ebe722efc350a1e4ffe8001 Mon Sep 17 00:00:00 2001 From: A Vinayak Rugvedi Date: Thu, 29 Aug 2024 23:05:18 +0530 Subject: [PATCH 163/186] fix: remap query params to API spec while downloading as CSV --- frontend/src/api/projects.js | 15 +++++++++++++-- frontend/src/components/projects/downloadAsCSV.js | 4 ++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/frontend/src/api/projects.js b/frontend/src/api/projects.js index 6b2607018b..03b8af8af0 100644 --- a/frontend/src/api/projects.js +++ b/frontend/src/api/projects.js @@ -193,8 +193,19 @@ export const submitValidationTask = (projectId, payload, token, locale) => { ); }; -export const downloadAsCSV = (queryParamsString, token) => { - return api(token).get(`projects/?${queryParamsString}`); +export const downloadAsCSV = (allQueryParams, action, token) => { + const paramsRemapped = remapParamsToAPI(allQueryParams, backendToQueryConversion); + // it's needed in order to query by action + if (paramsRemapped.action === undefined && action) { + paramsRemapped.action = action; + } + + if (paramsRemapped.lastUpdatedTo) { + paramsRemapped.lastUpdatedTo = format(subMonths(Date.now(), 6), 'yyyy-MM-dd'); + } + return api(token).get('projects/', { + params: paramsRemapped, + }); }; export const useAvailableCountriesQuery = () => { diff --git a/frontend/src/components/projects/downloadAsCSV.js b/frontend/src/components/projects/downloadAsCSV.js index f772be7070..66bed73516 100644 --- a/frontend/src/components/projects/downloadAsCSV.js +++ b/frontend/src/components/projects/downloadAsCSV.js @@ -4,7 +4,6 @@ import PropTypes from 'prop-types'; import { useSelector } from 'react-redux'; import toast from 'react-hot-toast'; -import { stringify } from '../../hooks/UseProjectsQueryAPI'; import { downloadAsCSV } from '../../api/projects'; import { DownloadIcon, LoadingIcon } from '../svgIcons'; import messages from './messages'; @@ -12,6 +11,7 @@ import messages from './messages'; export default function DownloadAsCSV({ allQueryParams }) { const [isLoading, setIsLoading] = useState(false); const token = useSelector((state) => state.auth.token); + const action = useSelector((state) => state.preferences['action']); const allQueryParamsCopy = { ...allQueryParams }; allQueryParamsCopy.downloadAsCSV = true; @@ -21,7 +21,7 @@ export default function DownloadAsCSV({ allQueryParams }) { setIsLoading(true); try { - const response = await downloadAsCSV(stringify(allQueryParamsCopy), token); + const response = await downloadAsCSV(allQueryParamsCopy, action, token); // Get the filename from the Content-Disposition header, if available const contentDisposition = response.headers.get('Content-Disposition'); From 2571921f8d89a6543be9f0dfe6a12101ef65b58b Mon Sep 17 00:00:00 2001 From: bshankar Date: Mon, 2 Sep 2024 09:41:59 +0530 Subject: [PATCH 164/186] Fix: percent_mapped and validated calculation in table view --- backend/models/postgis/project.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/backend/models/postgis/project.py b/backend/models/postgis/project.py index ef27d6638b..fc85b69f42 100644 --- a/backend/models/postgis/project.py +++ b/backend/models/postgis/project.py @@ -204,11 +204,15 @@ class Project(db.Model): # Total tasks are always >= 1 @hybrid_property def percent_mapped(self): - return self.tasks_mapped / self.total_tasks + return ( + (self.tasks_mapped + self.tasks_validated) + / (self.total_tasks - self.tasks_bad_imagery) + * 100 + ) @hybrid_property def percent_validated(self): - return self.tasks_validated / self.total_tasks + return self.tasks_validated / (self.total_tasks - self.tasks_bad_imagery) * 100 # Mapped Objects tasks = db.relationship( From 28b61f3a98339dfe570ebbf1e99bdb03d588939b Mon Sep 17 00:00:00 2001 From: bshankar Date: Wed, 4 Sep 2024 10:21:29 +0530 Subject: [PATCH 165/186] Fix: CSV: Remove empty partnerNames column for non admins --- backend/services/project_search_service.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/backend/services/project_search_service.py b/backend/services/project_search_service.py index 7158ed04c7..94c2a2364d 100644 --- a/backend/services/project_search_service.py +++ b/backend/services/project_search_service.py @@ -202,27 +202,30 @@ def get_total_contributions(paginated_results): @cached(csv_download_cache) def search_projects_as_csv(search_dto: ProjectSearchDTO, user) -> str: all_results, _ = ProjectSearchService._filter_projects(search_dto, user) + is_user_admin = user is not None and user.role == UserRole.ADMIN.value results_as_dto = [ ProjectSearchService.create_result_dto( p, search_dto.preferred_locale, Project.get_project_total_contributions(p[0]), - with_partner_names=( - user is not None and user.role == UserRole.ADMIN.value - ), + with_partner_names=is_user_admin, with_author_name=False, ).to_primitive() for p in all_results ] df = pd.json_normalize(results_as_dto) + columns_to_drop = [ + "locale", + "shortDescription", + "organisationLogo", + "campaigns", + ] + if not is_user_admin: + columns_to_drop.append("partnerNames") + df.drop( - columns=[ - "locale", - "shortDescription", - "organisationLogo", - "campaigns", - ], + columns=columns_to_drop, inplace=True, axis=1, ) From 6bf7f2b4bfcb78c00dcbd8d8ab53bc6c0b999428 Mon Sep 17 00:00:00 2001 From: bshankar Date: Wed, 4 Sep 2024 10:27:35 +0530 Subject: [PATCH 166/186] Fix: CSV: Round total area in Sqkm to 3 decimal places --- backend/services/project_search_service.py | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/services/project_search_service.py b/backend/services/project_search_service.py index 94c2a2364d..ac4a34cdf3 100644 --- a/backend/services/project_search_service.py +++ b/backend/services/project_search_service.py @@ -172,6 +172,7 @@ def create_result_dto( list_dto.total_area = project_obj.query.with_entities( func.coalesce(func.sum(func.ST_Area(project_obj.geometry, True) / 1000000)) ).scalar() + list_dto.total_area = round(list_dto.total_area, 3) return list_dto From 6ae8c1c54b45fe919e3afb08b2f029d1d154f96c Mon Sep 17 00:00:00 2001 From: DK Benjamin Date: Mon, 9 Sep 2024 10:42:30 -0400 Subject: [PATCH 167/186] Temporarily disable automatic deployment of dev branch to servers for e2e testing --- .circleci/config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 1b9167a8a6..d636f6876f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -452,8 +452,8 @@ workflows: pattern: "^deployment/.*" value: << pipeline.git.branch >> - or: - - equal: [ develop, << pipeline.git.branch >> ] - - equal: [ fix/ci-deployment-ami-perms, << pipeline.git.branch >> ] # change this to the branch you wish to test + ## - equal: [ develop, << pipeline.git.branch >> ] # Disabled while we use dev setup for e2e testing + - equal: [ dev-switch-to-sandbox, << pipeline.git.branch >> ] jobs: - database-backup: name: Backup development database From 0eef46a88cf09d9ff772674725f772669244a93c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 9 Sep 2024 16:44:31 +0000 Subject: [PATCH 168/186] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.6.3 → v0.6.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.6.3...v0.6.4) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cd3cbf496f..f50a0f193f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -73,7 +73,7 @@ repos: # Lint / autoformat: Python code - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: "v0.6.3" + rev: "v0.6.4" hooks: # Run the linter - id: ruff From 5c07f40e713291c5f4e374762c10567de93cdd4b Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Tue, 10 Sep 2024 12:00:10 +0545 Subject: [PATCH 169/186] Add `...rest` props to Button component --- frontend/src/components/button.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/button.js b/frontend/src/components/button.js index af665a7a92..6cb1c7de41 100644 --- a/frontend/src/components/button.js +++ b/frontend/src/components/button.js @@ -10,7 +10,15 @@ export const AnimatedLoadingIcon = () => ( ); -export function Button({ onClick, children, icon, className, disabled, loading = false }: Object) { +export function Button({ + onClick, + children, + icon, + className, + disabled, + loading = false, + ...rest +}: Object) { return ( + + {/* dropdown list */} + {isActive && ( +
    + {data.map((option) => ( +
  • { + option?.onClick(option); + }} + > + {option.label} +
  • + ))} +
+ )} +
+ ); +}; From 557fa02ee129a9c56ff69809db736b2bedbe0f51 Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Tue, 10 Sep 2024 17:04:27 +0545 Subject: [PATCH 171/186] Move `Resources` section to banner in Partner Stats page --- .../components/partners/partnersResources.js | 28 +++++++++---------- frontend/src/views/partnersStats.js | 26 +++++++---------- 2 files changed, 24 insertions(+), 30 deletions(-) diff --git a/frontend/src/components/partners/partnersResources.js b/frontend/src/components/partners/partnersResources.js index 05a327fcc3..bb5e0371a4 100644 --- a/frontend/src/components/partners/partnersResources.js +++ b/frontend/src/components/partners/partnersResources.js @@ -1,4 +1,7 @@ -import { CustomButton } from '../button'; +import { FormattedMessage } from 'react-intl'; + +import { CustomDropdown } from './customDropdown'; +import messages from '../../views/messages'; export const Resources = ({ partner }) => { const renderWebsiteLinks = () => { @@ -11,20 +14,17 @@ export const Resources = ({ partner }) => { name: partner[nameKey], url: partner[urlKeys[index]], })); + + const resourcesData = websiteLinks.map((link) => ({ + ...link, + label: link.name, + onClick: (item) => { + window.open(item.url, '_blank'); + }, + })); + return ( -
- {websiteLinks.map((link, index) => ( - - {link.name} - - ))} -
+ } data={resourcesData} /> ); }; diff --git a/frontend/src/views/partnersStats.js b/frontend/src/views/partnersStats.js index 152abe8d09..f394b4fbdb 100644 --- a/frontend/src/views/partnersStats.js +++ b/frontend/src/views/partnersStats.js @@ -63,12 +63,16 @@ export const PartnersStats = () => { ) : (

{partner.name}

)} - {/* new to mapping button */} - - - +
+ {/* new to mapping button */} + + + + {/* resources button */} + +
{/* social logos */}
@@ -117,16 +121,6 @@ export const PartnersStats = () => { - {/* resources section */} - {Object.keys(partner).some((key) => key.includes('name_')) && ( -
-

- -

- -
- )} - {/* activity section */}

From 109eba15a2b85682569db4ecf5ab6b4e1f6f9ee2 Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Wed, 11 Sep 2024 16:26:03 +0545 Subject: [PATCH 172/186] Add style prop to button component --- frontend/src/components/button.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/components/button.js b/frontend/src/components/button.js index 6cb1c7de41..207c20bf42 100644 --- a/frontend/src/components/button.js +++ b/frontend/src/components/button.js @@ -17,6 +17,7 @@ export function Button({ className, disabled, loading = false, + style, ...rest }: Object) { return ( @@ -25,7 +26,7 @@ export function Button({ aria-pressed="false" focusindex="0" className={`${className || ''} br1 f5 bn ${disabled || loading ? 'o-50' : 'pointer'}`} - style={{ padding: '.75rem 1.5rem' }} + style={{ padding: '.75rem 1.5rem', ...style }} disabled={disabled || loading} {...rest} > From 8c31dde827c9667e3cec5530c471fd334c931cba Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Wed, 11 Sep 2024 16:42:06 +0545 Subject: [PATCH 173/186] Adjust icon size in `CustomDropdown` component --- frontend/src/components/partners/customDropdown.js | 11 ++++++++--- frontend/src/components/partners/partnersResources.js | 6 +++++- frontend/src/components/partners/styles.scss | 4 ++-- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/frontend/src/components/partners/customDropdown.js b/frontend/src/components/partners/customDropdown.js index 229e44ee4d..caf86ef59e 100644 --- a/frontend/src/components/partners/customDropdown.js +++ b/frontend/src/components/partners/customDropdown.js @@ -4,19 +4,24 @@ import { Button } from '../button'; import { ChevronDownIcon } from '../svgIcons/chevron-down'; import { ChevronUpIcon } from '../svgIcons/chevron-up'; -export const CustomDropdown = ({ title, data }) => { +export const CustomDropdown = ({ title, data, buttonClassname }) => { const [isActive, setIsActive] = useState(false); return (
{/* dropdown select */} {/* dropdown list */} diff --git a/frontend/src/components/partners/partnersResources.js b/frontend/src/components/partners/partnersResources.js index bb5e0371a4..248fd0d572 100644 --- a/frontend/src/components/partners/partnersResources.js +++ b/frontend/src/components/partners/partnersResources.js @@ -24,7 +24,11 @@ export const Resources = ({ partner }) => { })); return ( - } data={resourcesData} /> + } + data={resourcesData} + /> ); }; diff --git a/frontend/src/components/partners/styles.scss b/frontend/src/components/partners/styles.scss index fd14c119ad..67ab58c5d9 100644 --- a/frontend/src/components/partners/styles.scss +++ b/frontend/src/components/partners/styles.scss @@ -23,6 +23,6 @@ } .partners-social-icon { - height: 24px; - width: 24px; + height: 20px; + width: 20px; } From d97ca4ceae8a139b0f64a0c3fa31e2b116db785d Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Wed, 11 Sep 2024 16:48:37 +0545 Subject: [PATCH 174/186] Add tab switch feature in partners stats page - Add tabname param to partner stats route - Conditionally render tab content based selected tab - Separate Leaderboard section to a seperate component --- .../src/components/partners/leaderboard.js | 33 ++++ frontend/src/routes.js | 2 +- frontend/src/views/partnersStats.js | 159 ++++++++++-------- 3 files changed, 126 insertions(+), 68 deletions(-) create mode 100644 frontend/src/components/partners/leaderboard.js diff --git a/frontend/src/components/partners/leaderboard.js b/frontend/src/components/partners/leaderboard.js new file mode 100644 index 0000000000..6ce3b044dd --- /dev/null +++ b/frontend/src/components/partners/leaderboard.js @@ -0,0 +1,33 @@ +import { FormattedMessage } from 'react-intl'; +import messages from '../../views/messages'; + +import { StatsSection } from './partnersStats'; +import { Activity } from './partnersActivity'; +import { CurrentProjects } from './currentProjects'; + +export const Leaderboard = ({ partner, partnerStats }) => { + return ( +
+
+

+ {partner.primary_hashtag + ?.split(',') + ?.map((str) => `#${str}`) + ?.join(', ')} +

+
+ + + + + + {/* activity section */} +
+

+ +

+ +
+
+ ); +}; diff --git a/frontend/src/routes.js b/frontend/src/routes.js index 2ca317b374..7495186182 100644 --- a/frontend/src/routes.js +++ b/frontend/src/routes.js @@ -113,7 +113,7 @@ export const router = createBrowserRouter( }} /> { const { PartnersStats } = await import( './views/partnersStats' /* webpackChunkName: "partnersStats" */ diff --git a/frontend/src/views/partnersStats.js b/frontend/src/views/partnersStats.js index f394b4fbdb..4fc05eeed8 100644 --- a/frontend/src/views/partnersStats.js +++ b/frontend/src/views/partnersStats.js @@ -1,24 +1,32 @@ import React, { useEffect, useState } from 'react'; -import { Link, useParams } from 'react-router-dom'; +import { Link, useParams, useNavigate } from 'react-router-dom'; import ReactPlaceholder from 'react-placeholder'; import { FormattedMessage } from 'react-intl'; import messages from './messages'; import { NotFound } from './notFound'; import { useFetch } from '../hooks/UseFetch'; -import { StatsSection } from '../components/partners/partnersStats'; -import { Activity } from '../components/partners/partnersActivity'; -import { CurrentProjects } from '../components/partners/currentProjects'; +import { Leaderboard } from '../components/partners/leaderboard'; import { Resources } from '../components/partners/partnersResources'; import { OHSOME_STATS_BASE_URL } from '../config'; import { Button } from '../components/button'; import { TwitterIcon, FacebookIcon, InstagramIcon } from '../components/svgIcons'; +const tabData = [{ id: 'leaderboard', title: 'Leaderboard' }]; + export const PartnersStats = () => { - const { id } = useParams(); + const { id, tabname } = useParams(); + const navigate = useNavigate(); const [partnerStats, setPartnerStats] = useState(null); const [error, loading, partner] = useFetch(`partners/${id}/`); + // navigate to /leaderboard path when no tab param present + useEffect(() => { + if (!tabname) { + navigate('leaderboard'); + } + }, [navigate, tabname]); + const fetchData = async (name) => { try { let hashtag = name.trim(); @@ -45,6 +53,15 @@ export const PartnersStats = () => { } }, [partner]); + function getTabContent() { + switch (tabname) { + case 'leaderboard': + return ; + default: + return <>; + } + } + return ( { ) : (
-
+
{/* logo */} {partner.logo_url ? ( logo ) : ( -

{partner.name}

- )} -
- {/* new to mapping button */} - - - - {/* resources button */} - -
-
- {/* social logos */} -
-
-

- {partner.primary_hashtag - ?.split(',') - ?.map((str) => `#${str}`) - ?.join(', ')} +

+ {partner.name}

-
- {!!partner.link_x && ( - - - - )} - {!!partner.link_meta && ( - - - - )} - {!!partner.link_instagram && ( - + -
- - +
+ {/* new to mapping button */} + + + - + {/* resources button */} + - {/* activity section */} -
-

- -

- + {/* social logos */} +
+ {!!partner.link_x && ( + + + + )} + {!!partner.link_meta && ( + + + + )} + {!!partner.link_instagram && ( + + + + )} +
+
+ + {/* tab content */} + {getTabContent()}
)} From 2309f23f4c2f21ef7bf85b0fc6660d1cb018616e Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Wed, 11 Sep 2024 17:13:51 +0545 Subject: [PATCH 175/186] Refactor social icon render logic in `Partner Stats` page - Dynamically map the icons from api data --- frontend/src/views/partnersStats.js | 64 ++++++++++++++--------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/frontend/src/views/partnersStats.js b/frontend/src/views/partnersStats.js index 4fc05eeed8..f8c9611754 100644 --- a/frontend/src/views/partnersStats.js +++ b/frontend/src/views/partnersStats.js @@ -12,6 +12,20 @@ import { OHSOME_STATS_BASE_URL } from '../config'; import { Button } from '../components/button'; import { TwitterIcon, FacebookIcon, InstagramIcon } from '../components/svgIcons'; +function getSocialIcons(link) { + const socialName = link.split('_')?.[1]; + switch (socialName) { + case 'x': + return ; + case 'meta': + return ; + case 'instagram': + return ; + default: + return <>; + } +} + const tabData = [{ id: 'leaderboard', title: 'Leaderboard' }]; export const PartnersStats = () => { @@ -62,6 +76,10 @@ export const PartnersStats = () => { } } + const socialLinks = Object.keys(partner) + .filter((key) => key.startsWith('link')) + .filter((link) => partner[link]); + return ( { {/* social logos */} -
- {!!partner.link_x && ( - - - - )} - {!!partner.link_meta && ( - - - - )} - {!!partner.link_instagram && ( - - - - )} -
+ {!!socialLinks.length && ( +
+ {socialLinks.map((link) => ( + + {getSocialIcons(link)} + + ))} +
+ )}
From b222a2ed6f906877b0bbe3ae04e45a1a6a5d76e9 Mon Sep 17 00:00:00 2001 From: royallsilwallz Date: Wed, 11 Sep 2024 17:24:30 +0545 Subject: [PATCH 176/186] Adjust styling for `Resources` dropdown in `Partner Stats` --- frontend/src/components/partners/customDropdown.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/frontend/src/components/partners/customDropdown.js b/frontend/src/components/partners/customDropdown.js index caf86ef59e..b63b446e35 100644 --- a/frontend/src/components/partners/customDropdown.js +++ b/frontend/src/components/partners/customDropdown.js @@ -27,8 +27,12 @@ export const CustomDropdown = ({ title, data, buttonClassname }) => { {/* dropdown list */} {isActive && (