Skip to content

Commit

Permalink
Merge pull request #1183 from IFRCGo/release/v4.3.0
Browse files Browse the repository at this point in the history
Release/v4.3.0
  • Loading branch information
frozenhelium committed Apr 30, 2020
2 parents 2e02af0 + d67a76a commit ef49003
Show file tree
Hide file tree
Showing 65 changed files with 4,054 additions and 605 deletions.
40 changes: 40 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,43 @@
### Release 4.3.0

Frontend:

- Add **3w** tab to **Country** page ([#641](https://github.com/IFRCGo/go-frontend/issues/641))
- Create a 3w view with a map, some basic overview charts and the projects table
- Add basic filters to the view
- Add ability to add / edit 3w project for logged in user
- Add ability to export the all the 3w data
- Add 3w project form ([#640](https://github.com/IFRCGo/go-frontend/issues/640))
- Create a form to add a 3w project
- Create dynamic fields according to the values of `Operation type` and `Programme type`. The fields `Current IFRC Operation`, `Current Emergency Operation` and `Disaster type` will be conditionally displayed accordingly.
- Create dynamic schema and required conditions for different field (eg: People reached > Total is required only if project is marked as Completed)
- Add a separate tag for COVID-19 specifc project / activity
- Add **3w** tab to **Region** page ([#1019](https://github.com/IFRCGo/go-frontend/issues/1019))
- Create the view with 3w overview, movement activities and national society activities for all the countries in the region
- Add map to show the movement activities in the countries of the selected region
- Add ability to view projects within the countries of selected region
- Add sankey diagram to view the national society activities
- Add ability to add the 3w project from **Emergency** page ([#1066](https://github.com/IFRCGo/go-frontend/issues/1066))
- Add [`react-icons`](https://react-icons.netlify.com/#/) for easy usage of icons
- Add [`@togglecorp/fujs`](https://github.com/toggle-corp/fujs/) for a lot of utils
- Add [`@togglecorp/faram`](https://github.com/toggle-corp/fujs/) to implement dynamic forms
- Add some faram compatible wrapped inputs (`TextInput`, `SelectInput`, `FaramCheckbox`, `DateInput`, `NumberInput`) with existing input elements
- Add some components that use [Hooks](https://reactjs.org/docs/hooks-intro.html). Custom hooks are added to `/hooks/` directory
- Add selectors for common selection approach for the redux. Selectors are added to `/selectors/` directory
- Refactor map download code (break down into components and remove unnecessary codes).

API:
- Fetch FTS HPC Data using google sheet.
- Add visibility support for project. (Public, Login required, IFRC Only)
- New Programme Type `Domestic`
- Add Bulk Project Import in Admin Panel.
- Enable history for Project changes.
- Add Sector/SectorTag `Health (private)` and `COVID-19`.
- Add API for Project for region.
- Add Multiselect filters for Project API enumfields.
- Change Sector/SectorTag `Health` to `Health (public)`.


### Release 4.2.3

Frontend:
Expand Down
42 changes: 41 additions & 1 deletion app/assets/scripts/actions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
postJSON,
putJSON,
patchJSON,
deleteJSON,
withToken
} from '../utils/network';
import { countryIsoMapById } from '../utils/field-report-constants';
Expand Down Expand Up @@ -58,14 +59,48 @@ export const getMe = () => (
fetchJSON('api/v2/user/me/', GET_ME, withToken())
);

export const GET_REGIONAL_PROJECTS = 'GET_REGIONAL_PROJECTS';
export const getRegionalProjects = (regionId, filterValues) => {
const filters = {
region: regionId,
limit: 9999,
...filterValues
};
const query = buildAPIQS(filters, { arrayFormat: 'comma' });
return fetchJSON(`api/v2/project/?${query}`, GET_REGIONAL_PROJECTS, withToken());
};

export const GET_REGIONAL_PROJECTS_OVERVIEW = 'GET_REGIONAL_PROJECTS_OVERVIEW';
export function getRegionalProjectsOverview (regionId) {
return fetchJSON(`api/v2/region-project/${regionId}/overview/`, GET_REGIONAL_PROJECTS_OVERVIEW, withToken());
}

export const GET_REGIONAL_MOVEMENT_ACTIVITIES = 'GET_REGIONAL_MOVEMENT_ACTIVITIES';
export function getRegionalMovementActivities (regionId, filters) {
const query = buildAPIQS(filters, { arrayFormat: 'comma' });
return fetchJSON(`api/v2/region-project/${regionId}/movement-activities/?${query}`, GET_REGIONAL_MOVEMENT_ACTIVITIES, withToken());
}

export const GET_NATIONAL_SOCIETY_ACTIVITIES = 'GET_NATIONAL_SOCIETY_ACTIVITIES';
export function getNationalSocietyActivities (regionId, filters) {
const query = buildAPIQS(filters, { arrayFormat: 'comma' });

return fetchJSON(`api/v2/region-project/${regionId}/national-society-activities/?${query}`, GET_NATIONAL_SOCIETY_ACTIVITIES, withToken());
}

export const GET_NATIONAL_SOCIETY_ACTIVITIES_WO_FILTERS = 'GET_NATIONAL_SOCIETY_ACTIVITIES_WO_FILTERS';
export function getNationalSocietyActivitiesWoFilters (regionId) {
return fetchJSON(`api/v2/region-project/${regionId}/national-society-activities/`, GET_NATIONAL_SOCIETY_ACTIVITIES_WO_FILTERS, withToken());
}

export const GET_PROJECTS = 'GET_PROJECTS';
export function getProjects (countryId, filterValues) {
const filters = {
country: countryIsoMapById[countryId],
...filterValues
};
const f = buildAPIQS(filters);
return fetchJSON(`api/v2/project/?${f}`, GET_PROJECTS, withToken());
return fetchJSON(`api/v2/project/?${f}`, GET_PROJECTS, withToken(), { countryId });
}

export const POST_PROJECT = 'POST_PROJECT';
Expand All @@ -82,6 +117,11 @@ export function postProject (data) {
return postJSON('api/v2/project/', POST_PROJECT, data, withToken());
}

export const DELETE_PROJECT = 'DELETE_PROJECT';
export function deleteProject (projectId) {
return deleteJSON(`api/v2/project/${projectId}/`, DELETE_PROJECT, withToken());
}

export const GET_COUNTRY_OVERVIEW = 'GET_COUNTRY_OVERVIEW';
export const getCountryOverview = (countryIso) => {
return fetchJSON(`api/v2/data-bank/country-overview/${countryIso}`, GET_COUNTRY_OVERVIEW, withToken());
Expand Down
25 changes: 25 additions & 0 deletions app/assets/scripts/components/backdrop.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import React from 'react';
import Portal from './portal';
import _cs from 'classnames';

function Backdrop (props) {
React.useEffect(() => {
const html = document.getElementsByTagName('html')[0];
const prevValue = html.style.overflow;
html.style.overflow = 'hidden';

return () => {
html.style.overflow = prevValue;
};
});

return (
<Portal>
<div className={_cs(props.className, 'tc-backdrop')}>
{ props.children }
</div>
</Portal>
);
}

export default Backdrop;
93 changes: 93 additions & 0 deletions app/assets/scripts/components/dropdown-menu.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React from 'react';
import { _cs } from '@togglecorp/fujs';

import {
useBlurEffect,
useFloatPlacement,
} from '../hooks';

import Portal from './portal';

// import styles from './styles.css';

/*
interface DropdownProps {
className?: string;
parentRef: React.RefObject<HTMLElement>;
elementRef: React.RefObject<HTMLDivElement>;
children: React.ReactNode;
}
*/

function Dropdown (props) {
const {
parentRef,
elementRef,
children,
className,
} = props;

const placement = useFloatPlacement(parentRef);

return (
<div
ref={elementRef}
style={placement}
className={_cs('tc-dropdown-container', className)}
>
{ children }
</div>
);
}

/*
interface Props {
className?: string;
dropdownContainerClassName?: string;
children: React.ReactNode;
label: string | undefined;
}
*/

function DropdownMenu (props) {
const {
className,
dropdownContainerClassName,
children,
label,
} = props;

const buttonRef = React.useRef(null);
const dropdownRef = React.useRef(null);
const [showDropdown, setShowDropdown] = React.useState(false);
const handleMenuClick = React.useCallback(() => {
setShowDropdown(true);
}, [setShowDropdown]);

useBlurEffect(showDropdown, setShowDropdown, dropdownRef, buttonRef);

return (
<React.Fragment>
<button
className={_cs(className, 'tc-dropdown-menu')}
ref={buttonRef}
onClick={handleMenuClick}
>
{ label }
</button>
{ showDropdown && (
<Portal>
<Dropdown
elementRef={dropdownRef}
className={dropdownContainerClassName}
parentRef={buttonRef}
>
{ children }
</Dropdown>
</Portal>
)}
</React.Fragment>
);
}

export default DropdownMenu;
3 changes: 2 additions & 1 deletion app/assets/scripts/components/footer.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ import { api } from '../config';

class Footer extends React.PureComponent {
render () {
const stagingBanner = process.env.NODE_ENV !== 'production'
const { NODE_ENV: currentEnv } = process.env;
const stagingBanner = currentEnv !== 'production' && currentEnv !== 'development'
? (
<div className='sticky-banner staging-footer'>
{process.env.NODE_ENV === 'staging' ? 'STAGING' : 'TESTING (SURGE)'} SITE
Expand Down
45 changes: 45 additions & 0 deletions app/assets/scripts/components/form-elements/faram-checkbox.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';
import { randomString } from '@togglecorp/fujs';
import { FaramInputElement } from '@togglecorp/faram';

class FaramCheckbox extends React.PureComponent {
inputId = randomString(8);

handleChange = (e) => {
const {
onChange,
value,
} = this.props;

if (onChange) {
onChange(!value);
}
}

render () {
const {
value,
label,
} = this.props;

return (
<label
htmlFor={this.inputId}
className='tc-faram-checkbox'
>
<input
id={this.inputId}
className='tc-faram-checkbox-input'
type="checkbox"
onChange={this.handleChange}
checked={value}
/>
<div className='tc-faram-checkbox-label'>
{ label }
</div>
</label>
);
}
}

export default FaramInputElement(FaramCheckbox);
4 changes: 3 additions & 1 deletion app/assets/scripts/components/form-elements/raw-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,11 @@ class RawInput extends React.PureComponent {
value = '',
type,
error,
disabled,
} = this.props;

return (
<div className={_cs(className, 'tc-raw-input')}>
<div className={_cs(className, 'tc-raw-input', disabled && 'tc-raw-input-disabled')}>
{ label && (
<div className='tc-raw-input-label'>
{ label }
Expand All @@ -39,6 +40,7 @@ class RawInput extends React.PureComponent {
onChange={this.handleChange}
placeholder={placeholder || 'Enter text'}
value={value}
disabled={disabled}
/>
{ error && (
<div className='tc-raw-input-error'>
Expand Down
7 changes: 5 additions & 2 deletions app/assets/scripts/components/formatted-date.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React from 'react';
import _cs from 'classnames';

import { padStart } from '@togglecorp/fujs';
import { padStart as p } from '@togglecorp/fujs';

const FormattedDate = ({
value,
Expand All @@ -13,7 +13,10 @@ const FormattedDate = ({
const date = new Date(value);

if (date && !(isNaN(date.getTime()))) {
dateString = `${date.getFullYear()}-${padStart(date.getMonth() + 1, 2)}-${padStart(date.getDay(), 2)}`;
const mm = p(date.getMonth() + 1, 2);
const dd = p(date.getDate(), 2);
const yyyy = date.getFullYear();
dateString = `${yyyy}-${mm}-${dd}`;
}
}

Expand Down
3 changes: 2 additions & 1 deletion app/assets/scripts/components/formatted-number.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ const FormattedNumber = ({
if (addSeparator) {
displayNumber = addCommaSeparator(displayNumber);
} else if (fixedTo) {
displayNumber = Number.parseFloat(displayNumber).toFixed(fixedTo);
const shouldFix = (displayNumber - Math.floor(displayNumber)) !== 0;
displayNumber = Number.parseFloat(displayNumber).toFixed(shouldFix ? fixedTo : 0);
}
}

Expand Down
Loading

0 comments on commit ef49003

Please sign in to comment.