Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat partner link #116

Merged
merged 4 commits into from
Aug 28, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions frontend/src/api/projects.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,10 @@ export const submitValidationTask = (projectId, payload, token, locale) => {
);
};

export const downloadAsCSV = (queryParamsString, token) => {
return api(token).get(`projects/?${queryParamsString}`);
};

export const useAvailableCountriesQuery = () => {
const fetchGeojsonData = () => {
return axios.get(`${UNDERPASS_URL}/availability`);
Expand Down Expand Up @@ -239,4 +243,7 @@ const backendToQueryConversion = {
stale: 'lastUpdatedTo',
createdFrom: 'createdFrom',
basedOnMyInterests: 'basedOnMyInterests',
partnerId: 'partnerId',
partnershipFrom: 'partnershipFrom',
partnershipTo: 'partnershipTo',
};
73 changes: 61 additions & 12 deletions frontend/src/components/projects/downloadAsCSV.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,77 @@
import { useState } from 'react';
import { FormattedMessage } from 'react-intl';
import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';
import toast from 'react-hot-toast';

import { API_URL } from '../../config';
import { stringify } from '../../hooks/UseProjectsQueryAPI';
import { DownloadIcon } from '../svgIcons';
import { downloadAsCSV } from '../../api/projects';
import { DownloadIcon, LoadingIcon } from '../svgIcons';
import messages from './messages';

export default function DownloadAsCSV({ allQueryParams }) {
const [isLoading, setIsLoading] = useState(false);
const token = useSelector((state) => state.auth.token);

const allQueryParamsCopy = { ...allQueryParams };
allQueryParamsCopy.downloadAsCSV = true;
allQueryParamsCopy.omitMapResults = undefined;
const downloadCSVLink = `${API_URL}projects/?${stringify(allQueryParamsCopy)}`;

const handleDownload = async () => {
setIsLoading(true);

try {
const response = await downloadAsCSV(stringify(allQueryParamsCopy), token);

// Get the filename from the Content-Disposition header, if available
const contentDisposition = response.headers.get('Content-Disposition');
let filename = 'projects_result.csv';
if (contentDisposition) {
const filenameMatch = contentDisposition.match(/filename="?(.+)"?/i);
if (filenameMatch) {
filename = filenameMatch[1];
}
}

// Create a Blob with the CSV content
const blob = new Blob([response.data], { type: 'text/csv;charset=utf-8;' });

// Create and click a temporary download link
const url = window.URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', filename);
document.body.appendChild(link);
link.click();
document.body.removeChild(link);

// Clean up the URL object
window.URL.revokeObjectURL(url);
} catch (error) {
toast.error(<FormattedMessage {...messages.downloadAsCSVError} />);
} finally {
setIsLoading(false);
}
};

return (
<a
href={downloadCSVLink}
className="ml3 lh-title f6 blue-dark inline-flex items-baseline"
download
<button
className={`ml3 lh-title f6 ${
isLoading ? 'gray' : 'blue-dark'
} inline-flex items-baseline b--none bg-white underline pointer`}
onClick={handleDownload}
disabled={isLoading}
>
<DownloadIcon className="mr2 self-center" />
<span className="underline">
<FormattedMessage {...messages.downloadAsCSV} />
</span>
</a>
{isLoading ? (
<LoadingIcon
className="mr2 self-center h1 w1 gray"
style={{ animation: 'spin 1s linear infinite' }}
/>
) : (
<DownloadIcon className="mr2 self-center" />
)}
<FormattedMessage {...messages.downloadAsCSV} />
</button>
);
}

Expand Down
18 changes: 14 additions & 4 deletions frontend/src/components/projects/exploreProjectsTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,13 +80,23 @@ const COLUMNS = [
<div>
<div data-tooltip-id={`project-${row.original.projectId}-progress`}>
<ProgressBar
firstBarValue={row.original.percentMapped}
secondBarValue={row.original.percentValidated}
firstBarValue={
row.original.percentMapped > 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}
/>
</div>
<Tooltip id={`project-${row.original.projectId}-progress`}>{tooltipContent}</Tooltip>
<Tooltip id={`project-${row.original.projectId}-progress`} className="z-3">
{tooltipContent}
</Tooltip>
</div>
);
},
Expand Down Expand Up @@ -126,7 +136,7 @@ const COLUMNS = [
cell: ({ row }) => {
const difficulty = row.original.difficulty;
if (difficulty === 'EASY') return <div className="i green">Easy</div>;
if (difficulty === 'MODERATE') return <div className="i orange">Medium</div>;
if (difficulty === 'MODERATE') return <div className="i orange">Moderate</div>;
if (difficulty === 'CHALLENGING') return <div className="i red">Challenging</div>;
},
},
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/components/projects/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -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.',
Expand Down
1 change: 1 addition & 0 deletions frontend/src/components/svgIcons/download.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export class DownloadIcon extends React.PureComponent {
>
<path
opacity="1"
fill="currentColor"
d="M288 32c0-17.7-14.3-32-32-32s-32 14.3-32 32V274.7l-73.4-73.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3l128 128c12.5 12.5 32.8 12.5 45.3 0l128-128c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L288 274.7V32zM64 352c-35.3 0-64 28.7-64 64v32c0 35.3 28.7 64 64 64H448c35.3 0 64-28.7 64-64V416c0-35.3-28.7-64-64-64H346.5l-45.3 45.3c-25 25-65.5 25-90.5 0L165.5 352H64zm368 56a24 24 0 1 1 0 48 24 24 0 1 1 0-48z"
/>
</svg>
Expand Down
Loading