diff --git a/app/eslint.config.ts b/app/eslint.config.ts index 61f298f1b5..c717fe4401 100644 --- a/app/eslint.config.ts +++ b/app/eslint.config.ts @@ -1,12 +1,11 @@ -// @ts-expect-error: @eslint/eslintrc has no types import { FlatCompat } from '@eslint/eslintrc'; import js from '@eslint/js'; import json from "@eslint/json"; import tseslint from "typescript-eslint"; import process from 'process'; +import { Linter } from 'eslint'; import i18nUsage from './scripts/eslint/i18n-usage'; -import { Linter } from 'eslint'; const dirname = process.cwd(); @@ -166,7 +165,7 @@ const jsonConfig: Linter.Config = { // }, // }; -const config: Linter.Config[] = [ +const config = tseslint.config( { plugins: { json, @@ -178,6 +177,6 @@ const config: Linter.Config[] = [ jsonConfig, // i18nJsonConfig, ...tseslint.configs.recommended -]; +); export default config; diff --git a/app/src/App/PageError/index.tsx b/app/src/App/PageError/index.tsx index 6a10d7acb6..8c6d836bc7 100644 --- a/app/src/App/PageError/index.tsx +++ b/app/src/App/PageError/index.tsx @@ -58,7 +58,7 @@ function PageError() { @@ -79,7 +79,8 @@ function PageError() { {strings.errorPageGoBack} diff --git a/app/src/App/index.tsx b/app/src/App/index.tsx index 4ac4fa950a..53242d3b2c 100644 --- a/app/src/App/index.tsx +++ b/app/src/App/index.tsx @@ -239,11 +239,11 @@ function Application() { ); return ( - - - - - + + + + + )} /> - - - - - + + + + + ); } diff --git a/app/src/App/routes/CountryRoutes.tsx b/app/src/App/routes/CountryRoutes.tsx index ec04b860e8..76838c346a 100644 --- a/app/src/App/routes/CountryRoutes.tsx +++ b/app/src/App/routes/CountryRoutes.tsx @@ -145,19 +145,6 @@ const countryOngoingActivitiesEmergencies = customWrapRoute({ }, }); -const countryOngoingActivitiesThreeWActivities = customWrapRoute({ - parent: countryOngoingActivitiesLayout, - path: 'three-w/activities', - component: { - render: () => import('#views/CountryOngoingActivitiesThreeWActivities'), - props: {}, - }, - context: { - title: 'Country 3W Activities', - visibility: 'anything', - }, -}); - const countryOngoingActivitiesThreeWProjects = customWrapRoute({ parent: countryOngoingActivitiesLayout, path: 'three-w/projects', @@ -484,7 +471,6 @@ export default { countryOngoingActivitiesLayout, countryOngoingActivitiesIndex, countryOngoingActivitiesEmergencies, - countryOngoingActivitiesThreeWActivities, countryOngoingActivitiesThreeWProjects, countryNsOverviewLayout, diff --git a/app/src/components/CatalogueInfoCard/index.tsx b/app/src/components/CatalogueInfoCard/index.tsx index 1ddef83253..c0bbe6a0be 100644 --- a/app/src/components/CatalogueInfoCard/index.tsx +++ b/app/src/components/CatalogueInfoCard/index.tsx @@ -1,14 +1,12 @@ import { useCallback } from 'react'; import { Container, - List, + ListView, + RawList, } from '@ifrc-go/ui'; -import { _cs } from '@togglecorp/fujs'; import Link, { type Props as LinkProps } from '#components/Link'; -import styles from './styles.module.css'; - export type LinkData = LinkProps & { title: string; } @@ -19,7 +17,6 @@ interface Props { title: string; data: LinkData[]; description?: string; - descriptionClassName?: string; } function CatalogueInfoCard(props: Props) { @@ -28,7 +25,6 @@ function CatalogueInfoCard(props: Props) { title, data, description, - descriptionClassName, } = props; const rendererParams = useCallback( @@ -56,26 +52,27 @@ function CatalogueInfoCard(props: Props) { return ( - + + + ); } diff --git a/app/src/components/CatalogueInfoCard/styles.module.css b/app/src/components/CatalogueInfoCard/styles.module.css deleted file mode 100644 index ae165866ae..0000000000 --- a/app/src/components/CatalogueInfoCard/styles.module.css +++ /dev/null @@ -1,10 +0,0 @@ -.catalogue-info-card { - border-radius: var(--go-ui-border-radius-md); - box-shadow: var(--go-ui-box-shadow-md); - - .list { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-sm); - } -} diff --git a/app/src/components/DropdownMenuItem/index.tsx b/app/src/components/DropdownMenuItem/index.tsx index 32647b00ff..80766b4490 100644 --- a/app/src/components/DropdownMenuItem/index.tsx +++ b/app/src/components/DropdownMenuItem/index.tsx @@ -15,6 +15,7 @@ import Link, { type Props as LinkProps } from '#components/Link'; type CommonProp = { persist?: boolean; + withoutFullWidth?: boolean; } type ButtonTypeProps = Omit, 'type'> & { @@ -23,20 +24,25 @@ type ButtonTypeProps = Omit, 'type'> & { type LinkTypeProps = LinkProps & { type: 'link'; + onClick?: never; } type ConfirmButtonTypeProps = Omit, 'type'> & { type: 'confirm-button', } -type Props = CommonProp & (ButtonTypeProps | LinkTypeProps | ConfirmButtonTypeProps); +type Props = CommonProp & ( + ButtonTypeProps | LinkTypeProps | ConfirmButtonTypeProps +); function DropdownMenuItem(props: Props) { const { - type, - onClick, persist = false, + onClick, + withoutFullWidth, + ...remainingProps } = props; + const { setShowDropdown } = useContext(DropdownMenuContext); const handleLinkClick = useCallback( @@ -51,72 +57,81 @@ function DropdownMenuItem(props: Props) { const handleButtonClick = useCallback( (name: NAME, e: React.MouseEvent) => { - if (!persist) { - setShowDropdown(false); - } - if (isDefined(onClick) && type !== 'link') { - onClick(name, e); + if (remainingProps.type !== 'link') { + if (!persist) { + setShowDropdown(false); + } + + if (isDefined(onClick)) { + onClick(name, e); + } } }, - [setShowDropdown, type, onClick, persist], + [setShowDropdown, persist, onClick, remainingProps.type], ); - if (type === 'link') { + if (remainingProps.type === 'link') { const { // eslint-disable-next-line @typescript-eslint/no-unused-vars type: _, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - persist: __, - variant = 'dropdown-item', + styleVariant = 'transparent', + colorVariant = 'text', + children, ...otherProps - } = props; + } = remainingProps; return ( + withFullWidth={!withoutFullWidth} + > + {children} + ); } - if (type === 'button') { + if (remainingProps.type === 'button') { const { // eslint-disable-next-line @typescript-eslint/no-unused-vars type: _, - // eslint-disable-next-line @typescript-eslint/no-unused-vars - persist: __, - variant = 'dropdown-item', + styleVariant = 'transparent', + colorVariant = 'text', ...otherProps - } = props; + } = remainingProps; return ( + + + + + + )} + {presentationMode && ( + + + + )} + {printMode && ( + + {strings.downloadHeaderLogoAltText} + + )} + + )} + spacing={presentationMode ? 'xl' : 'none'} + withPadding={presentationMode} + > + + {presentationMode && presentationModeAdditionalBeforeContent} +
+ + + + + {mapSources} + + + + {strings.copyrightMapbox} + + + {strings.copyrightOSM} + + + {strings.improveMapLabel} + + + + )} + /> + {withPresentationMode && !printMode && !presentationMode && ( + + )} + {!printMode && !presentationMode && !withoutDownloadButton && ( + + + + )} +
+ {children} +
+
+ {footer && ( + + {footer} + + )} + {presentationMode && presentationModeAdditionalAfterContent} +
+ + ); +} + +export default GoMapContainer; diff --git a/app/src/components/GoMapContainer/styles.module.css b/app/src/components/GoMapContainer/styles.module.css new file mode 100644 index 0000000000..05411bc4cc --- /dev/null +++ b/app/src/components/GoMapContainer/styles.module.css @@ -0,0 +1,75 @@ +.go-map-container { + .go-icon { + height: var(--go-ui-height-compact-status-icon); + } + + .relative-wrapper { + position: relative; + isolation: isolate; + + .map { + height: var(--go-ui-height-map-md); + } + + .download-button { + position: absolute; + top: 5rem; + /* NOTE: Exactly as mapbox */ + right: 10px; + border: var(--go-ui-width-separator-md) solid var(--go-ui-color-separator); + border-radius: var(--go-ui-border-radius-md); + background-color: var(--go-ui-color-foreground); + padding: 0 var(--go-ui-spacing-2xs); + font-size: var(--go-ui-height-icon-multiplier); + } + + .map-disclaimer { + position: absolute; + bottom: var(--go-ui-spacing-xs); + left: calc(var(--mapbox-icon-width) + var(--go-ui-spacing-sm)); + background-color: var(--go-ui-color-white); + padding: 0 var(--go-ui-spacing-2xs); + font-size: var(--go-ui-font-size-sm); + } + + .presentation-mode-button { + position: absolute; + top: var(--go-ui-spacing-sm); + left: var(--go-ui-spacing-sm); + } + + .content { + position: absolute; + bottom: calc(1.5rem + 2 * var(--go-ui-spacing-xs)); + left: var(--go-ui-spacing-sm); + } + } + + &.print-mode { + position: relative; + border: var(--go-ui-width-separator-thin) solid var(--go-ui-color-separator); + + .relative-wrapper { + border-top: var(--go-ui-width-separator-lg) solid var(--go-ui-color-primary-red); + + .map { + height: calc(var(--go-ui-width-separator-lg) + var(--go-ui-height-map-md)); + } + } + + .floating-actions { + position: absolute; + top: 0; + right: 0; + transform: translateY(-100%); + background-color: var(--go-ui-color-foreground); + } + } + + &.presentation-mode { + background-color: var(--go-ui-color-background); + width: 100vw; + height: 100vh; + overflow: auto; + } +} diff --git a/app/src/components/GradientBar/index.tsx b/app/src/components/GradientBar/index.tsx new file mode 100644 index 0000000000..696ec1e818 --- /dev/null +++ b/app/src/components/GradientBar/index.tsx @@ -0,0 +1,36 @@ +import { type RefObject } from 'react'; +import { _cs } from '@togglecorp/fujs'; + +import styles from './styles.module.css'; + +interface Props extends Omit, 'ref' | 'size'> { + startColor: string; + endColor: string; + elementRef?: RefObject; +} + +function GradientBar(props: Props) { + const { + startColor, + endColor, + elementRef, + style, + className, + ...otherProps + } = props; + + return ( +
+ ); +} + +export default GradientBar; diff --git a/app/src/components/GradientBar/styles.module.css b/app/src/components/GradientBar/styles.module.css new file mode 100644 index 0000000000..2df3000b37 --- /dev/null +++ b/app/src/components/GradientBar/styles.module.css @@ -0,0 +1,4 @@ +.gradient-bar { + width: min(30cqi, 10rem); + height: 0.5rem; +} diff --git a/app/src/components/Link/index.tsx b/app/src/components/Link/index.tsx index d15c957b1d..1f483f8da5 100644 --- a/app/src/components/Link/index.tsx +++ b/app/src/components/Link/index.tsx @@ -1,291 +1,174 @@ import { - useContext, - useMemo, -} from 'react'; -import { - generatePath, - Link as InternalLink, + Link as RouterLink, type LinkProps as RouterLinkProps, } from 'react-router-dom'; import { ChevronRightLineIcon, ExternalLinkLineIcon, } from '@ifrc-go/icons'; -import type { ButtonFeatureProps } from '@ifrc-go/ui'; -import { useButtonFeatures } from '@ifrc-go/ui/hooks'; +import { + ButtonLayout, + type ButtonLayoutProps, +} from '@ifrc-go/ui'; import { _cs, - isDefined, isFalsyString, - isNotDefined, } from '@togglecorp/fujs'; -import RouteContext from '#contexts/route'; -import useAuth from '#hooks/domain/useAuth'; -import usePermissions from '#hooks/domain/usePermissions'; +import useLink from '#hooks/domain/useLink'; +import { type UrlParams } from '#utils/domain/link'; import { type WrappedRoutes } from '../../App/routes'; import styles from './styles.module.css'; -export interface UrlParams { - [key: string]: string | number | null | undefined; -} - -// eslint-disable-next-line react-refresh/only-export-components -export function resolvePath( - to: keyof WrappedRoutes, - routes: WrappedRoutes, - urlParams: UrlParams | undefined, -) { - const route = routes[to]; - try { - const resolvedPath = generatePath(route.absoluteForwardPath, urlParams); - return { - ...route, - resolvedPath, - }; - } catch { - return { - ...route, - resolvedPath: undefined, - }; - } -} - -// eslint-disable-next-line react-refresh/only-export-components -export function useLink(props: { - external: true, - href: string | undefined | null, - to?: never, - urlParams?: never, -} | { - external: false | undefined, - to: keyof WrappedRoutes | undefined | null, - urlParams?: UrlParams, - href?: never, -}) { - const { isAuthenticated } = useAuth(); - const routes = useContext(RouteContext); - const perms = usePermissions(); - - if (props.external) { - if (isNotDefined(props.href)) { - return { disabled: true, to: undefined }; - } - return { disabled: false, to: props.href }; - } - - if (isNotDefined(props.to)) { - return { disabled: true, to: undefined }; - } - - const route = resolvePath(props.to, routes, props.urlParams); - const { resolvedPath } = route; - - if (isNotDefined(resolvedPath)) { - return { disabled: true, to: undefined }; - } - - const disabled = (route.visibility === 'is-authenticated' && !isAuthenticated) - || (route.visibility === 'is-not-authenticated' && isAuthenticated) - || (route.permissions && !route.permissions(perms, props.urlParams)); - - return { - disabled, - to: resolvedPath, - }; -} - -export type CommonLinkProps = Omit & -Omit<{ - actions?: React.ReactNode; - actionsContainerClassName?: string; - disabled?: boolean; - icons?: React.ReactNode; - iconsContainerClassName?: string; - linkElementClassName?: string; - // to?: RouterLinkProps['to']; - variant?: ButtonFeatureProps['variant']; +type PickedButtonLayoutProps = + | 'className' + | 'colorVariant' + | 'styleVariant' + | 'spacing' + | 'spacingOffset' + | 'withoutPadding' + | 'withFullWidth' + | 'children' + | 'before' + | 'after' + | 'textSize' + | 'disabled'; + +export type CommonLinkProps = Pick & { + withEllipsizedContent?: boolean; withLinkIcon?: boolean; withUnderline?: boolean; - ellipsize?: boolean; - spacing?: ButtonFeatureProps['spacing']; -}, OMISSION> +}; -type InternalLinkProps = { +interface InternalLinkProps extends Omit { external?: never; to: keyof WrappedRoutes | undefined | null; + href?: never; urlParams?: UrlParams; urlSearch?: string; urlHash?: string; - href?: never; } -export type ExternalLinkProps = { +export interface ExternalLinkProps extends Omit, 'href'> { external: true; href: string | undefined | null; + to?: never; urlParams?: never; urlSearch?: never; urlHash?: never; - to?: never; } -export type Props = CommonLinkProps - & (InternalLinkProps | ExternalLinkProps) +export type Props = CommonLinkProps & (InternalLinkProps | ExternalLinkProps); function Link(props: Props) { const { - actions, - actionsContainerClassName, - children: childrenFromProps, className, - disabled: disabledFromProps, - icons, - iconsContainerClassName, - linkElementClassName, - withUnderline, - withLinkIcon, - variant = 'tertiary', - ellipsize, + colorVariant = 'secondary', + styleVariant = 'action', spacing, + spacingOffset = -3, + withoutPadding, + withFullWidth, + children, + before, + after, + textSize, + disabled: disabledFromProps, external, - // eslint-disable-next-line @typescript-eslint/no-unused-vars to, - // eslint-disable-next-line @typescript-eslint/no-unused-vars + href, urlParams, - // eslint-disable-next-line @typescript-eslint/no-unused-vars urlSearch, - // eslint-disable-next-line @typescript-eslint/no-unused-vars urlHash, - ...otherProps + + withEllipsizedContent, + withLinkIcon, + withUnderline, + + ...linkProps } = props; const { disabled: disabledLink, to: toLink, } = useLink( - // eslint-disable-next-line react/destructuring-assignment - props.external - // eslint-disable-next-line react/destructuring-assignment - ? { href: props.href, external: true } - // eslint-disable-next-line react/destructuring-assignment - : { to: props.to, external: false, urlParams: props.urlParams }, + external + ? { href, external: true } + : { to, external: false, urlParams }, ); const disabled = disabledFromProps || disabledLink; - const nonLink = isFalsyString(toLink); - const { - children: content, - className: containerClassName, - } = useButtonFeatures({ - className: styles.content, - icons, - children: childrenFromProps, - variant, - ellipsize, - disabled, - spacing, - actions: (isDefined(actions) || withLinkIcon) ? ( - <> - {actions} - {withLinkIcon && external && ( - - )} - {withLinkIcon && !external && ( - - )} - - ) : null, - iconsContainerClassName, - actionsContainerClassName, - }); - - const children = useMemo( - () => { - if (isNotDefined(toLink)) { - return ( -
- {content} -
- ); - } - // eslint-disable-next-line react/destructuring-assignment - if (props.external) { - return ( - - {content} - - ); - } - - return ( - + {after} + {withLinkIcon && external && ( + + )} + {withLinkIcon && !external && ( + )} - to={{ - pathname: toLink, - // eslint-disable-next-line react/destructuring-assignment - search: props.urlSearch, - // eslint-disable-next-line react/destructuring-assignment - hash: props.urlHash, - }} - > - {content} - - ); - }, - [ - linkElementClassName, - containerClassName, - content, - otherProps, - toLink, - // eslint-disable-next-line react/destructuring-assignment - props.urlSearch, - // eslint-disable-next-line react/destructuring-assignment - props.urlHash, - // eslint-disable-next-line react/destructuring-assignment - props.external, - ], + + )} + > + {children} + ); + if (nonLink) { + return ( +
+ {content} +
+ ); + } + + if (external) { + return ( + + {content} + + ); + } + return ( -
- {children} -
+ {content} + ); } export default Link; diff --git a/app/src/components/Link/styles.module.css b/app/src/components/Link/styles.module.css index 5e8a0e3b82..6fb6a898c7 100644 --- a/app/src/components/Link/styles.module.css +++ b/app/src/components/Link/styles.module.css @@ -1,57 +1,9 @@ .link { - --decoration: none; + display: contents; - display: inline-flex; - align-items: flex-start; - flex-wrap: nowrap; - width: fit-content; - - &.ellipsized { - width: 100%; - overflow: auto; - } - - &.dropdown-item { - width: 100%; - } - - &:not(.non-link) { - font-weight: var(--go-ui-font-weight-medium); - - &.underline { - --decoration: underline; - } - } - - &:not(.tertiary):not(.dropdown-item) { - text-align: center; - } - - &:not(.disabled):not(.non-link) { - cursor: pointer; - - &:hover { - --decoration: underline; - } - } - - &.disabled { - pointer-events: none; - } - - .link-element { - display: inline-flex; - align-items: center; - flex-grow: 1; - text-decoration: var(--decoration); - - &:focus-visible { - outline: var(--go-ui-width-separator-thin) dashed var(--go-ui-color-gray-40); + .layout { + &.with-underline { + text-decoration: underline; } } - - .forward-icon { - font-size: var(--go-ui-height-icon-multiplier); - margin-inline-start: -0.3em; - } } diff --git a/app/src/components/MapContainerWithDisclaimer/index.tsx b/app/src/components/MapContainerWithDisclaimer/index.tsx deleted file mode 100644 index ff97dce321..0000000000 --- a/app/src/components/MapContainerWithDisclaimer/index.tsx +++ /dev/null @@ -1,230 +0,0 @@ -import { - useCallback, - useRef, -} from 'react'; -import { - CloseFillIcon, - DownloadTwoLineIcon, -} from '@ifrc-go/icons'; -import { - Button, - DateOutput, - Header, - IconButton, - InfoPopup, - RawButton, -} from '@ifrc-go/ui'; -import { - useBooleanState, - useTranslation, -} from '@ifrc-go/ui/hooks'; -import { resolveToComponent } from '@ifrc-go/ui/utils'; -import { _cs } from '@togglecorp/fujs'; -import { MapContainer } from '@togglecorp/re-map'; -import FileSaver from 'file-saver'; -import { toPng } from 'html-to-image'; - -import goLogo from '#assets/icons/go-logo-2020.svg'; -import Link from '#components/Link'; -import { mbtoken } from '#config'; -import useAlert from '#hooks/useAlert'; - -import i18n from './i18n.json'; -import styles from './styles.module.css'; - -interface Props { - className?: string; - title?: string; - footer?: React.ReactNode; - withoutDownloadButton?: boolean; -} - -function MapContainerWithDisclaimer(props: Props) { - const { - className, - title = 'Map', - footer, - withoutDownloadButton = false, - } = props; - - const strings = useTranslation(i18n); - - const mapSources = resolveToComponent( - strings.mapSourcesLabel, - { - uncodsLink: ( - - {strings.mapSourceUNCODsLabel} - - ), - }, - ); - - const [ - printMode, - { - setTrue: enterPrintMode, - setFalse: exitPrintMode, - }, - ] = useBooleanState(false); - - const containerRef = useRef(null); - - const alert = useAlert(); - const handleDownloadClick = useCallback(() => { - if (!containerRef?.current) { - alert.show( - strings.failureToDownloadMessage, - { variant: 'danger' }, - ); - exitPrintMode(); - return; - } - toPng(containerRef.current, { - skipAutoScale: false, - }) - .then((data) => FileSaver.saveAs(data, title)) - .finally(exitPrintMode); - }, [ - exitPrintMode, - title, - alert, - strings.failureToDownloadMessage, - ]); - - return ( -
- {printMode && ( -
- - - - - - )} - /> - )} -
- {printMode && ( -
- {title} - - - )} - actions={( - {strings.downloadHeaderLogoAltText} - )} - /> - )} -
- - -
- {strings.mapDisclaimer} -
-
- {mapSources} -
-
- - {strings.copyrightMapbox} - - - {strings.copyrightOSM} - - - {strings.improveMapLabel} - -
-
- )} - /> -
- {!printMode && !withoutDownloadButton && ( - - - - )} - {footer} -
-
- ); -} - -export default MapContainerWithDisclaimer; diff --git a/app/src/components/MapContainerWithDisclaimer/styles.module.css b/app/src/components/MapContainerWithDisclaimer/styles.module.css deleted file mode 100644 index bdfa18e4a5..0000000000 --- a/app/src/components/MapContainerWithDisclaimer/styles.module.css +++ /dev/null @@ -1,94 +0,0 @@ -.map-container { - display: flex; - flex-direction: column; - flex-grow: 1; - - .download-header { - border-bottom: var(--go-ui-width-separator-lg) solid var(--go-ui-color-primary-red); - background-color: var(--go-ui-color-background); - padding: var(--go-ui-spacing-sm); - - .download-heading { - align-items: baseline; - gap: var(--go-ui-spacing-xs); - color: var(--go-ui-color-primary-red); - - .header-date { - font-size: var(--go-ui-font-size-xs); - } - } - - .go-icon { - height: var(--go-ui-height-compact-status-icon); - } -} - -.map-container-with-disclaimer { - display: flex; - position: relative; - flex-direction: column; - z-index: 0; - - &.print-mode { - border: var(--go-ui-width-separator-sm) solid var(--go-ui-color-separator); - } - - .map-wrapper { - display: flex; - position: relative; - flex-direction: column; - flex-grow: 1; - - .container { - flex-grow: 1; - } - } - - .map-disclaimer { - position: absolute; - bottom: var(--go-ui-spacing-xs); - left: calc(var(--mapbox-icon-width) + var(--go-ui-spacing-sm)); - background-color: var(--go-ui-color-white); - padding: 0 var(--go-ui-spacing-2xs); - font-size: var(--go-ui-font-size-sm); - } - - .download-button { - position: absolute; - top: 5rem; - /* NOTE: Exactly as mapbox */ - right: calc(10px - var(--go-ui-width-separator-md)); - border: var(--go-ui-width-separator-md) solid var(--go-ui-color-separator); - border-radius: var(--go-ui-border-radius-md); - background-color: var(--go-ui-color-foreground); - padding: 0 var(--go-ui-spacing-2xs); - font-size: var(--go-ui-height-icon-multiplier); - - &:hover { - background-color: var(--go-ui-color-background); - } - } -} - -.disclaimer-popup-content { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-sm); - - .attribution { - display: flex; - flex-wrap: wrap; - gap: var(--go-ui-spacing-2xs) var(--go-ui-spacing-sm); - } -} - -.header { - background-color: var(--go-ui-color-background); - padding: var(--go-ui-spacing-md); - - .actions { - align-items: center; - } -} - -} diff --git a/app/src/components/MapPopup/index.tsx b/app/src/components/MapPopup/index.tsx index 8d1b6c7932..81a68bc9c1 100644 --- a/app/src/components/MapPopup/index.tsx +++ b/app/src/components/MapPopup/index.tsx @@ -24,8 +24,7 @@ function MapPopup(props: Props) { children, coordinates, onCloseButtonClick, - actions, - childrenContainerClassName, + headerActions, popupClassName, ...containerProps } = props; @@ -52,17 +51,17 @@ function MapPopup(props: Props) { // eslint-disable-next-line react/jsx-props-no-spreading {...containerProps} className={styles.container} - withoutWrapInHeading - childrenContainerClassName={_cs(styles.content, childrenContainerClassName)} withHeaderBorder - withInternalPadding - actions={( + withoutWrapInHeader + withPadding + headerActions={( <> - {actions} + {headerActions} - + )} - actions={!presentationMode && ( + headerActions={!presentationMode && ( )} > - - + + <> -
+ {legendOptions.map((legendItem) => ( ))} -
- + + )} /> )} - childrenContainerClassName={styles.popupContent} + withPadding + empty={isNotDefined(popupDetails) || popupDetails.length === 0} + emptyMessage={strings.operationPopoverEmpty} > {popupDetails?.map( (appeal) => ( - - - + + + + + ), )} - {(isNotDefined(popupDetails) || popupDetails.length === 0) && ( -
- {strings.operationPopoverEmpty} -
- )} )} {isDefined(bbox) && ( @@ -539,17 +556,6 @@ function ActiveOperationMap(props: Props) { /> )}
- {onPresentationModeButtonClick && !presentationMode && ( - - )} ); } diff --git a/app/src/components/domain/ActiveOperationMap/styles.module.css b/app/src/components/domain/ActiveOperationMap/styles.module.css deleted file mode 100644 index 77ed664f02..0000000000 --- a/app/src/components/domain/ActiveOperationMap/styles.module.css +++ /dev/null @@ -1,57 +0,0 @@ -.active-operation-map { - .clear-button { - display: flex; - flex-direction: column; - justify-content: flex-end; - } - .content { - position: relative; - - .presentation-mode-button { - position: absolute; - top: var(--go-ui-spacing-md); - left: var(--go-ui-spacing-md); - } - } - - .map-container { - height: min(50rem, 70vh); - min-height: 20rem; - } - - .footer { - display: flex; - align-items: flex-end; - flex-wrap: wrap; - justify-content: space-between; - background-color: var(--go-ui-color-background); - padding: var(--go-ui-spacing-lg); - gap: var(--go-ui-spacing-md); - - .legend { - display: flex; - flex-wrap: wrap; - gap: var(--go-ui-spacing-xs) var(--go-ui-spacing-md); - - .legend-item { - font-size: var(--go-ui-font-size-md); - } - } - } -} - -.popup-content { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-md); - - .popup-appeal { - gap: var(--go-ui-spacing-xs); - - .popup-appeal-detail { - display: flex; - flex-direction: column; - font-size: var(--go-ui-font-size-sm); - } - } -} diff --git a/app/src/components/domain/AppealsOverYearsChart/MonthlyChart/index.tsx b/app/src/components/domain/AppealsOverYearsChart/MonthlyChart/index.tsx index 34daa9e92e..f18223cc63 100644 --- a/app/src/components/domain/AppealsOverYearsChart/MonthlyChart/index.tsx +++ b/app/src/components/domain/AppealsOverYearsChart/MonthlyChart/index.tsx @@ -4,9 +4,9 @@ import { useState, } from 'react'; import { - BlockLoading, Button, Container, + ListView, TimeSeriesChart, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; @@ -17,6 +17,7 @@ import { } from '@ifrc-go/ui/utils'; import { encodeDate, + isDefined, isNotDefined, listToMap, } from '@togglecorp/fujs'; @@ -98,6 +99,7 @@ function MonthlyChart(props: Props) { const { pending: monthlyEmergencyAppealPending, response: monthlyEmergencyAppealResponse, + error: monthlyEmergencyAppealError, } = useRequest({ url: '/api/v1/aggregate/', query: { @@ -110,6 +112,7 @@ function MonthlyChart(props: Props) { const { response: monthlyDrefResponse, pending: monthlyDrefPending, + error: monthlyDrefError, } = useRequest({ url: '/api/v1/aggregate/', query: { @@ -180,38 +183,40 @@ function MonthlyChart(props: Props) { return ( - {pending && } - {!pending && ( - <> - - - {strings.homeMonthlyChartBackButtonLabel} - - )} - /> - - )} + + + + {strings.homeMonthlyChartBackButtonLabel} + + )} + /> + ); } diff --git a/app/src/components/domain/AppealsOverYearsChart/MonthlyChart/styles.module.css b/app/src/components/domain/AppealsOverYearsChart/MonthlyChart/styles.module.css index 366ffb417b..9f51b2f3b1 100644 --- a/app/src/components/domain/AppealsOverYearsChart/MonthlyChart/styles.module.css +++ b/app/src/components/domain/AppealsOverYearsChart/MonthlyChart/styles.module.css @@ -3,39 +3,24 @@ --color-emergency-appeal: var(--go-ui-color-primary-red); min-height: 24rem; - .chart-container { - display: flex; - position: relative; - flex-wrap: wrap; - gap: var(--go-ui-spacing-md); + .timeline-chart { + width: 100%; + height: 22rem; + grid-column: span 2; + --path-stroke-width: 1pt; - .loading { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; + .dref { + color: var(--color-dref); + stroke: var(--color-dref); + stroke-width: var(--path-stroke-width); + fill: none; } - .timeline-chart { - flex-basis: 40rem; - flex-grow: 2; - height: 22rem; - --path-stroke-width: 1pt; - - .dref { - stroke: var(--color-dref); - stroke-width: var(--path-stroke-width); - fill: none; - color: var(--color-dref); - } - - .emergency-appeal { - stroke: var(--color-emergency-appeal); - stroke-width: var(--path-stroke-width); - fill: none; - color: var(--color-emergency-appeal); - } + .emergency-appeal { + color: var(--color-emergency-appeal); + stroke: var(--color-emergency-appeal); + stroke-width: var(--path-stroke-width); + fill: none; } } } diff --git a/app/src/components/domain/AppealsOverYearsChart/PointDetails/index.tsx b/app/src/components/domain/AppealsOverYearsChart/PointDetails/index.tsx index 621a1674b0..e492a9d68b 100644 --- a/app/src/components/domain/AppealsOverYearsChart/PointDetails/index.tsx +++ b/app/src/components/domain/AppealsOverYearsChart/PointDetails/index.tsx @@ -1,5 +1,6 @@ import { Container, + ListView, TextOutput, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; @@ -36,61 +37,72 @@ function PointDetails(props: Props) { return ( - {data && ( - <> -
- } - label={strings.timelineChartEmergencyAppealLabel} - value={data.emergencyAppeal?.count ?? 0} - valueType="number" - strongValue - strongLabel - /> - - -
-
- } - label={strings.timelineChartDrefLabel} - value={data.dref?.count ?? 0} - valueType="number" - strongValue - strongLabel - /> - - -
- - )} + + + } + label={strings.timelineChartEmergencyAppealLabel} + value={data?.emergencyAppeal?.count ?? 0} + valueType="number" + strongValue + strongLabel + /> + + + + + } + label={strings.timelineChartDrefLabel} + value={data?.dref?.count ?? 0} + valueType="number" + strongValue + strongLabel + /> + + + +
); } diff --git a/app/src/components/domain/AppealsOverYearsChart/PointDetails/styles.module.css b/app/src/components/domain/AppealsOverYearsChart/PointDetails/styles.module.css index c52d36e048..ed64227a69 100644 --- a/app/src/components/domain/AppealsOverYearsChart/PointDetails/styles.module.css +++ b/app/src/components/domain/AppealsOverYearsChart/PointDetails/styles.module.css @@ -2,40 +2,22 @@ --color-dref: var(--go-ui-color-primary-blue); --color-emergency-appeal: var(--go-ui-color-primary-red); - flex-basis: 16rem; - flex-grow: 1; background-color: var(--go-ui-color-background); - .content { - display: flex; - align-content: flex-start; - align-items: flex-start; - flex-wrap: wrap; - gap: var(--go-ui-spacing-lg); - - .emergency-appeal-details { - flex-basis: 16rem; - } - - .dref-details { - flex-basis: 16rem; - } - - .emergency-appeal-point-icon, - .dref-point-icon { - align-self: center; - flex-shrink: 0; - border-radius: 50%; - width: 0.7em; - height: 0.7em; - } + .emergency-appeal-point-icon, + .dref-point-icon { + align-self: center; + flex-shrink: 0; + border-radius: 50%; + width: 0.7em; + height: 0.7em; + } - .dref-point-icon { - background-color: var(--color-dref); - } + .dref-point-icon { + background-color: var(--color-dref); + } - .emergency-appeal-point-icon { - background-color: var(--color-emergency-appeal); - } + .emergency-appeal-point-icon { + background-color: var(--color-emergency-appeal); } } diff --git a/app/src/components/domain/AppealsOverYearsChart/YearlyChart/index.tsx b/app/src/components/domain/AppealsOverYearsChart/YearlyChart/index.tsx index c678e198bc..d73e5404b4 100644 --- a/app/src/components/domain/AppealsOverYearsChart/YearlyChart/index.tsx +++ b/app/src/components/domain/AppealsOverYearsChart/YearlyChart/index.tsx @@ -4,10 +4,9 @@ import { useState, } from 'react'; import { - BlockLoading, Button, Container, - Message, + ListView, TimeSeriesChart, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; @@ -97,6 +96,7 @@ function YearlyChart(props: Props) { const { response: monthlyDrefResponse, pending: monthlyDrefPending, + error: monthlyDrefError, } = useRequest({ url: '/api/v1/aggregate/', query: { @@ -152,48 +152,45 @@ function YearlyChart(props: Props) { [combinedData], ); - const shouldHideChart = pending && isDefined(appealResponseError); - return ( - {pending && } - {isDefined(appealResponseError) && ( - + + + {strings.yearlyAppealChartViewMonthlyLabel} + + )} /> - )} - {!shouldHideChart && !appealResponseError && ( - <> - - - {strings.yearlyAppealChartViewMonthlyLabel} - - )} - /> - - )} + ); } diff --git a/app/src/components/domain/AppealsOverYearsChart/YearlyChart/styles.module.css b/app/src/components/domain/AppealsOverYearsChart/YearlyChart/styles.module.css index 419fed986f..b845aa435b 100644 --- a/app/src/components/domain/AppealsOverYearsChart/YearlyChart/styles.module.css +++ b/app/src/components/domain/AppealsOverYearsChart/YearlyChart/styles.module.css @@ -3,39 +3,24 @@ --color-emergency-appeal: var(--go-ui-color-primary-red); min-height: 24rem; - .chart-container { - display: flex; - position: relative; - flex-wrap: wrap; - gap: var(--go-ui-spacing-md); + .timeline-chart { + width: 100%; + height: 22rem; + grid-column: span 2; + --path-stroke-width: 1pt; - .loading { - position: absolute; - top: 0; - left: 0; - width: 100%; - height: 100%; + .dref { + color: var(--color-dref); + stroke: var(--color-dref); + stroke-width: var(--path-stroke-width); + fill: none; } - .timeline-chart { - flex-basis: 40rem; - flex-grow: 2; - height: 22rem; - --path-stroke-width: 1pt; - - .dref { - stroke: var(--color-dref); - stroke-width: var(--path-stroke-width); - fill: none; - color: var(--color-dref); - } - - .emergency-appeal { - stroke: var(--color-emergency-appeal); - stroke-width: var(--path-stroke-width); - fill: none; - color: var(--color-emergency-appeal); - } + .emergency-appeal { + color: var(--color-emergency-appeal); + stroke: var(--color-emergency-appeal); + stroke-width: var(--path-stroke-width); + fill: none; } } } diff --git a/app/src/components/domain/AppealsTable/index.tsx b/app/src/components/domain/AppealsTable/index.tsx index 83e91eaad4..08c71f4df5 100644 --- a/app/src/components/domain/AppealsTable/index.tsx +++ b/app/src/components/domain/AppealsTable/index.tsx @@ -284,7 +284,6 @@ function AppealsTable(props: Props) { return ( -
- -
+ )} footerActions={( @@ -350,7 +346,6 @@ function AppealsTable(props: Props) { onActivePageChange={setPage} /> )} - contentViewType="vertical" > extends BaseMapProps { showChanges?: boolean; showPreviousValue?: boolean; diffWrapperClassName?: string; - latitudeInputSectionClassName?: string; - longitudeInputSectionClassName?: string; } function BaseMapPointInput(props: Props) { @@ -85,8 +84,6 @@ function BaseMapPointInput(props: Props) { showChanges = false, showPreviousValue = false, diffWrapperClassName, - latitudeInputSectionClassName, - longitudeInputSectionClassName, ...otherProps } = props; @@ -203,7 +200,7 @@ function BaseMapPointInput(props: Props) { className={diffWrapperClassName} > (props: Props) { className={diffWrapperClassName} > ( name={undefined} onClick={handleSelectAllClick} disabled={isNotDefined(countryId) || pendingSelectAll} - variant="tertiary" + styleVariant="action" title={strings.selectAll} > diff --git a/app/src/components/domain/DrefExportModal/index.tsx b/app/src/components/domain/DrefExportModal/index.tsx index 51c1928f9d..0bcebcca03 100644 --- a/app/src/components/domain/DrefExportModal/index.tsx +++ b/app/src/components/domain/DrefExportModal/index.tsx @@ -213,9 +213,10 @@ function DrefExportModal(props: Props) { description={strings.drefClickDownloadLink} actions={( } + before={} external > {strings.drefDownloadPDF} diff --git a/app/src/components/domain/DrefShareModal/UserItem/index.tsx b/app/src/components/domain/DrefShareModal/UserItem/index.tsx index 5e8f936688..20d38c16d8 100644 --- a/app/src/components/domain/DrefShareModal/UserItem/index.tsx +++ b/app/src/components/domain/DrefShareModal/UserItem/index.tsx @@ -1,20 +1,17 @@ import { useMemo } from 'react'; import { DeleteBinFillIcon } from '@ifrc-go/icons'; -import { Button } from '@ifrc-go/ui'; -import { useTranslation } from '@ifrc-go/ui/hooks'; import { - _cs, - isDefined, -} from '@togglecorp/fujs'; + Button, + ButtonLayout, +} from '@ifrc-go/ui'; +import { useTranslation } from '@ifrc-go/ui/hooks'; import { type User } from '#components/domain/UserSearchMultiSelectInput'; import { getUserName } from '#utils/domain/user'; import i18n from './i18n.json'; -import styles from './styles.module.css'; interface Props { - className?: string; userId: number; user: User; onUserRemove?: (item: number) => void; @@ -22,7 +19,6 @@ interface Props { function UserItem(props: Props) { const { - className, userId, user, onUserRemove, @@ -36,22 +32,23 @@ function UserItem(props: Props) { ); return ( -
-
- {userName} -
- {isDefined(onUserRemove) && ( + )} -
+ styleVariant="translucent" + > + {userName} + ); } diff --git a/app/src/components/domain/DrefShareModal/UserItem/styles.module.css b/app/src/components/domain/DrefShareModal/UserItem/styles.module.css deleted file mode 100644 index 096d6d490d..0000000000 --- a/app/src/components/domain/DrefShareModal/UserItem/styles.module.css +++ /dev/null @@ -1,23 +0,0 @@ -.user { - display: flex; - border-radius: var(--go-ui-border-radius-full); - background-color: var(--go-ui-color-background-hover); - padding: var(--go-ui-spacing-xs) var(--go-ui-spacing-md); - font-weight: var(--go-ui-font-weight-medium); - gap: var(--go-ui-spacing-xs); - - .name { - flex-grow: 1; - } - .remove-button { - flex-shrink: 0; - opacity: 0; - } - - &:hover { - background-color: var(--go-ui-color-background-hover); - .remove-button { - opacity: 1; - } - } -} diff --git a/app/src/components/domain/DrefShareModal/index.tsx b/app/src/components/domain/DrefShareModal/index.tsx index ee35cb26bd..46fba1fa92 100644 --- a/app/src/components/domain/DrefShareModal/index.tsx +++ b/app/src/components/domain/DrefShareModal/index.tsx @@ -4,8 +4,10 @@ import { } from 'react'; import { Button, - List, + Container, + ListView, Modal, + RawList, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; import { @@ -24,7 +26,6 @@ import { import UserItem from './UserItem'; import i18n from './i18n.json'; -import styles from './styles.module.css'; interface Props { drefId: number; @@ -102,9 +103,6 @@ function DrefShareModal(props: Props) { return ( {strings.drefShareUpdate} )} size="md" - childrenContainerClassName={styles.content} + withHeaderBorder > - - + + + + + + + + ); } diff --git a/app/src/components/domain/DrefShareModal/styles.module.css b/app/src/components/domain/DrefShareModal/styles.module.css deleted file mode 100644 index edae78aac0..0000000000 --- a/app/src/components/domain/DrefShareModal/styles.module.css +++ /dev/null @@ -1,29 +0,0 @@ -.overlay { - display: flex; - - .modal-container { - display: flex; - - .dref-share-modal { - display: flex; - flex-direction: column; - min-height: 25rem; - - .content { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-lg); - - .user-list { - display: flex; - flex-wrap: wrap; - gap: var(--go-ui-spacing-xs); - } - - .message { - flex-grow: 1; - } - } - } - } -} diff --git a/app/src/components/domain/ExportButton/index.tsx b/app/src/components/domain/ExportButton/index.tsx index 8f845f4ce5..13070a18af 100644 --- a/app/src/components/domain/ExportButton/index.tsx +++ b/app/src/components/domain/ExportButton/index.tsx @@ -57,9 +57,8 @@ function ExportButton(props: Props) { diff --git a/app/src/components/domain/GoMultiFileInput/index.tsx b/app/src/components/domain/GoMultiFileInput/index.tsx index 78eb052d30..933aa3ff3b 100644 --- a/app/src/components/domain/GoMultiFileInput/index.tsx +++ b/app/src/components/domain/GoMultiFileInput/index.tsx @@ -1,19 +1,25 @@ import React, { useCallback, + useMemo, useRef, } from 'react'; -import { DeleteBinFillIcon } from '@ifrc-go/icons'; +import { + DeleteBinFillIcon, + DeleteBinLineIcon, +} from '@ifrc-go/icons'; import { Button, - type ButtonVariant, + type CommonRawFileInputProps, + Description, + IconButton, + InlineLayout, InputError, + ListView, type NameType, RawFileInput, - type RawFileInputProps, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; import { - _cs, isDefined, isNotDefined, } from '@togglecorp/fujs'; @@ -25,7 +31,6 @@ import { useLazyRequest } from '#utils/restRequest'; import { transformObjectError } from '#utils/restRequest/error'; import i18n from './i18n.json'; -import styles from './styles.module.css'; export type SupportedPaths = '/api/v2/per-file/multiple/' | '/api/v2/dref-files/multiple/' | '/api/v2/flash-update-file/multiple/'; @@ -47,44 +52,43 @@ function getFileNameFromUrl(urlString: string | undefined) { return splits[splits.length - 1]; } -type Props = Omit, 'multiple' | 'value' | 'onChange' | 'children' | 'inputRef'> & { - actions?: React.ReactNode; - children?: React.ReactNode; - className?: string; +type Props = Omit, 'value'> & { + name: NAME; clearable?: boolean; - icons?: React.ReactNode; - onChange: (value: number[] | undefined, name: T) => void; + description?: React.ReactNode; + error?: React.ReactNode; + errorOnTooltip?: boolean; fileIdToUrlMap: Record; + onChange: (value: number[] | undefined, name: NAME) => void; setFileIdToUrlMap?: React.Dispatch>>; url: SupportedPaths; value: number[] | undefined | null; - variant?: ButtonVariant; withoutPreview?: boolean; - error?: React.ReactNode; - description?: React.ReactNode; } function GoMultiFileInput(props: Props) { const { accept, - actions: actionsFromProps, + after: afterFromProps, + before, children, className, clearable, + colorVariant = 'primary', + description, disabled: disabledFromProps, - icons, + error, + errorOnTooltip, + fileIdToUrlMap, inputProps, name, onChange, readOnly, - fileIdToUrlMap, setFileIdToUrlMap, + styleVariant = 'outline', url, value, - variant = 'secondary', withoutPreview, - error, - description, } = props; const strings = useTranslation(i18n); @@ -159,12 +163,55 @@ function GoMultiFileInput(props: Props) { } }, [triggerFileUpload]); + const handleClearButtonClick = useCallback(() => { + onChange(undefined, name); + }, [onChange, name]); + const disabled = disabledFromProps || pending || readOnly; - const actions = (clearable && value && !readOnly && !disabled ? actionsFromProps : null); const valueUrls = isDefined(value) ? ( value.map((fileId) => ({ id: fileId, url: fileIdToUrlMap?.[fileId] })) ) : undefined; + const after = useMemo(() => { + if (readOnly || disabled) { + return null; + } + + if (!clearable || !value) { + return afterFromProps; + } + + return ( + + {after} + {clearable && value && ( + + + + )} + + ); + }, [ + afterFromProps, + clearable, + disabled, + handleClearButtonClick, + readOnly, + // strings.removeFileButtonTitle, + value, + ]); + const handleFileRemove = useCallback( (id: number) => { if (isNotDefined(value)) { @@ -182,7 +229,11 @@ function GoMultiFileInput(props: Props) { ); return ( -
+ (props: Props) { readOnly={readOnly} inputProps={inputProps} inputRef={inputRef} - variant={variant} - icons={icons} - actions={actions} + colorVariant={colorVariant} + styleVariant={styleVariant} + before={before} + after={after} multiple > {children} {!withoutPreview && isDefined(valueUrls) && valueUrls.length > 0 && ( -
+ {valueUrls.map( (valueUrl) => ( -
+ + + )} > (props: Props) { > {getFileNameFromUrl(valueUrl.url)} - -
+ ), )} -
+
)} {description && ( -
+ {description} -
+ + )} + {error && ( + + {error} + )} - - {error} - -
+ ); } export default GoMultiFileInput; diff --git a/app/src/components/domain/GoMultiFileInput/styles.module.css b/app/src/components/domain/GoMultiFileInput/styles.module.css deleted file mode 100644 index e49087fbe5..0000000000 --- a/app/src/components/domain/GoMultiFileInput/styles.module.css +++ /dev/null @@ -1,16 +0,0 @@ -.go-file-input { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-md); - - .selected-files { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-xs); - - .file { - display: flex; - gap: var(--go-ui-spacing-xs); - } - } -} diff --git a/app/src/components/domain/GoSingleFileInput/index.tsx b/app/src/components/domain/GoSingleFileInput/index.tsx index 7458b29b7f..eaff4b4492 100644 --- a/app/src/components/domain/GoSingleFileInput/index.tsx +++ b/app/src/components/domain/GoSingleFileInput/index.tsx @@ -1,16 +1,19 @@ -import React, { useCallback } from 'react'; +import { + useCallback, + useMemo, +} from 'react'; import { DeleteBinLineIcon } from '@ifrc-go/icons'; import { - type ButtonVariant, + type CommonRawFileInputProps, + Description, IconButton, InputError, - type NameType, + ListView, RawFileInput, - type RawFileInputProps, + type SingleRawFileInputProps, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; import { - _cs, isDefined, isNotDefined, } from '@togglecorp/fujs'; @@ -22,55 +25,53 @@ import { useLazyRequest } from '#utils/restRequest'; import { transformObjectError } from '#utils/restRequest/error'; import i18n from './i18n.json'; -import styles from './styles.module.css'; export type SupportedPaths = '/api/v2/per-file/' | '/api/v2/dref-files/' | '/api/v2/flash-update-file/' | '/api/v2/per-document-upload/'; -type Props = Omit, 'multiple' | 'value' | 'onChange' | 'children'| 'inputRef'> & { - actions?: React.ReactNode; - children?: React.ReactNode; - className?: string; +type Props = Omit, 'value'> & { + name: NAME; clearable?: boolean; - icons?: React.ReactNode; - onChange: (value: number | undefined, name: T) => void; + description?: React.ReactNode; + error?: React.ReactNode; + errorOnTooltip?: boolean; fileIdToUrlMap: Record; + onSuccess?: () => void; + requestBody?: Record; setFileIdToUrlMap?: React.Dispatch>>; url: SupportedPaths; urlQuery?: Record; - requestBody?: Record; value: number | undefined | null; - variant?: ButtonVariant; + onChange: (value: number | undefined, name: NAME) => void; withoutPreview?: boolean; - error?: React.ReactNode; - description?: React.ReactNode; - onSuccess?: () => void; withoutStatus?: boolean; -} +}; -function GoSingleFileInput(props: Props) { +function GoSingleFileInput(props: Props) { const { accept, - actions: actionsFromProps, + after: afterFromProps, + before, children, className, clearable, + colorVariant = 'primary', + description, disabled: disabledFromProps, - icons, + error, + errorOnTooltip, + fileIdToUrlMap, inputProps, name, onChange, + onSuccess, readOnly, - fileIdToUrlMap, + requestBody, setFileIdToUrlMap, + styleVariant = 'outline', url, urlQuery, value, - variant = 'secondary', withoutPreview, - error, - description, - requestBody, - onSuccess, withoutStatus, } = props; @@ -128,7 +129,7 @@ function GoSingleFileInput(props: Props) { }, }); - const handleChange = useCallback((file: File | undefined) => { + const handleChange = useCallback['onChange']>((file) => { if (isNotDefined(file)) { return; } @@ -145,45 +146,68 @@ function GoSingleFileInput(props: Props) { triggerFileUpload({ file }); }, [triggerFileUpload, requestBody]); - const disabled = disabledFromProps || pending || readOnly; - const actions = (!readOnly && !disabled ? actionsFromProps : null); - const selectedFileUrl = isDefined(value) ? fileIdToUrlMap?.[value] : undefined; - const handleClearButtonClick = useCallback(() => { onChange(undefined, name); }, [onChange, name]); - return ( -
-
- - {children} - + const disabled = disabledFromProps || pending || readOnly; + const selectedFileUrl = isDefined(value) ? fileIdToUrlMap?.[value] : undefined; + const after = useMemo(() => { + if (readOnly || disabled) { + return null; + } + + if (!clearable || !value) { + return afterFromProps; + } + + return ( + + {after} {clearable && value && ( )} -
+ + ); + }, [ + afterFromProps, + clearable, + disabled, + handleClearButtonClick, + readOnly, + strings.removeFileButtonTitle, + value, + ]); + + return ( + + + {children} + {!withoutPreview && isDefined(selectedFileUrl) && ( (props: Props) { )} {isNotDefined(selectedFileUrl) && !withoutStatus && ( -
+ {strings.noFileSelected} -
+ )} {description && ( -
+ {description} -
+ + )} + {error && ( + + {error} + )} - - {error} - -
+ ); } diff --git a/app/src/components/domain/GoSingleFileInput/styles.module.css b/app/src/components/domain/GoSingleFileInput/styles.module.css deleted file mode 100644 index 4976034f2c..0000000000 --- a/app/src/components/domain/GoSingleFileInput/styles.module.css +++ /dev/null @@ -1,15 +0,0 @@ -.go-single-file-input { - display: flex; - position: relative; - flex-direction: column; - gap: var(--go-ui-spacing-sm); - - .input-container { - display: flex; - gap: var(--go-ui-spacing-xs); - } - - .empty-message { - color: var(--go-ui-color-gray-50); - } -} diff --git a/app/src/components/domain/HighlightedOperations/OperationCard/i18n.json b/app/src/components/domain/HighlightedOperations/OperationCard/i18n.json index 2008576342..170fab523b 100644 --- a/app/src/components/domain/HighlightedOperations/OperationCard/i18n.json +++ b/app/src/components/domain/HighlightedOperations/OperationCard/i18n.json @@ -4,10 +4,10 @@ "operationCardLastUpdated": "Last updated", "operationCardTargetedPopulation": "Targeted Population", "operationCardFunding": "Funding Requirements", - "operationCardFundingCoverage": "{coverage}% received", + "operationCardFundingCoverage": "Funding coverage", "operationCardFollow": "Follow", "operationCardUnfollow": "Unfollow", "operationCardInvolvesMultipleCountries": "Involves multiple countries", "operationCardNoCountryInvolved": "No Country Involved" } -} \ No newline at end of file +} diff --git a/app/src/components/domain/HighlightedOperations/OperationCard/index.tsx b/app/src/components/domain/HighlightedOperations/OperationCard/index.tsx index 44601706bc..bd8401ec5d 100644 --- a/app/src/components/domain/HighlightedOperations/OperationCard/index.tsx +++ b/app/src/components/domain/HighlightedOperations/OperationCard/index.tsx @@ -2,21 +2,17 @@ import { useContext } from 'react'; import { FocusLineIcon } from '@ifrc-go/icons'; import { Button, + ButtonLayout, Container, KeyFigure, - NumberOutput, + ListView, + ProgressBar, TextOutput, Tooltip, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; -import { - resolveToComponent, - sumSafe, -} from '@ifrc-go/ui/utils'; -import { - _cs, - isNotDefined, -} from '@togglecorp/fujs'; +import { sumSafe } from '@ifrc-go/ui/utils'; +import { isNotDefined } from '@togglecorp/fujs'; import SeverityIndicator from '#components/domain/SeverityIndicator'; import Link from '#components/Link'; @@ -102,12 +98,9 @@ function OperationCard(props: Props) { const amountRequested = sumSafe(appeals.map((appeal) => appeal.amount_requested)); const amountFunded = sumSafe(appeals.map((appeal) => appeal.amount_funded)); - const coverage = getPercent(amountFunded, amountRequested); + const appealTypes = appeals.map((appeal) => appeal.atype_display); - const fundingCoverageDescription = resolveToComponent( - strings.operationCardFundingCoverage, - { coverage: }, - ); + const coverage = getPercent(amountFunded, amountRequested); let countriesInfoDisplay = strings.operationCardNoCountryInvolved; if (countries.length === 1) { @@ -118,24 +111,27 @@ function OperationCard(props: Props) { return ( {name} )} - headingLevel={4} - withInternalPadding + headingLevel={6} withHeaderBorder - withoutWrapInHeading - icons={ifrc_severity_level ? ( + headerIcons={ifrc_severity_level ? ( <> ) : undefined} - actions={isAuthenticated && ( + headerActions={isAuthenticated && ( )} headerDescription={( - + + {appealTypes.join(', ')} + + + + )} + footer={( + + )} /> )} - childrenContainerClassName={styles.figures} + withFooterBorder > - - {strings.operationCardTargetedPopulation} - - )} - compactValue - /> -
- {/* FIXME This keyFigure should route to emergencies/id/report */} - - {strings.operationCardFunding} - - )} - compactValue - progress={coverage} - progressDescription={fundingCoverageDescription} - /> + + + {strings.operationCardTargetedPopulation} + + )} + value={targetedPopulation} + valueType="number" + valueOptions={{ compact: true }} + /> + + {strings.operationCardFunding} + + )} + valueType="number" + valueOptions={{ compact: true }} + /> + ); } diff --git a/app/src/components/domain/HighlightedOperations/OperationCard/styles.module.css b/app/src/components/domain/HighlightedOperations/OperationCard/styles.module.css index ae60155d20..7892a14773 100644 --- a/app/src/components/domain/HighlightedOperations/OperationCard/styles.module.css +++ b/app/src/components/domain/HighlightedOperations/OperationCard/styles.module.css @@ -1,19 +1,4 @@ .operation-card { - border-radius: var(--go-ui-border-radius-lg); - box-shadow: var(--go-ui-box-shadow-md); - width: 100%; - overflow: auto; - - .heading-container { - width: 100%; - overflow: auto; - } - - .heading { - width: 100%; - overflow: auto; - } - .severity-indicator { font-size: var(--go-ui-font-size-xl); } diff --git a/app/src/components/domain/HighlightedOperations/index.tsx b/app/src/components/domain/HighlightedOperations/index.tsx index 2dd5853643..7340775541 100644 --- a/app/src/components/domain/HighlightedOperations/index.tsx +++ b/app/src/components/domain/HighlightedOperations/index.tsx @@ -4,7 +4,8 @@ import { } from 'react'; import { Container, - Grid, + ListView, + RawList, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; import { @@ -159,7 +160,7 @@ function HighlightedOperations(props: Props) { className={className} withHeaderBorder heading={variant === 'country' ? strings.highlightedOperationsCountryTitle : strings.highlightedOperationsTitle} - actions={( + headerActions={( )} + pending={featuredEmergencyPending} + errored={isDefined(featuredEmergencyResponseError)} + filtered={false} + empty={!featuredEmergencies?.length} + withoutSpacingOpticalCorrection > - + + + ); } diff --git a/app/src/components/domain/ImageWithCaptionInput/index.tsx b/app/src/components/domain/ImageWithCaptionInput/index.tsx index 406a54690a..681a62d92e 100644 --- a/app/src/components/domain/ImageWithCaptionInput/index.tsx +++ b/app/src/components/domain/ImageWithCaptionInput/index.tsx @@ -1,8 +1,11 @@ import { useCallback } from 'react'; -import { TextInput } from '@ifrc-go/ui'; +import { + Image, + ListView, + TextInput, +} from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; import { - _cs, isDefined, randomString, } from '@togglecorp/fujs'; @@ -17,7 +20,6 @@ import GoSingleFileInput, { type SupportedPaths } from '#components/domain/GoSin import NonFieldError from '#components/NonFieldError'; import i18n from './i18n.json'; -import styles from './styles.module.css'; type Value = { id?: number | undefined; @@ -35,8 +37,8 @@ interface Props { fileIdToUrlMap: Record; setFileIdToUrlMap?: React.Dispatch>>; label: React.ReactNode; - icons?: React.ReactNode; - actions?: React.ReactNode; + before?: React.ReactNode; + after?: React.ReactNode; disabled?: boolean; } @@ -52,8 +54,8 @@ function ImageWithCaptionInput(props: Props) onChange, error: formError, label, - icons, - actions, + before, + after, disabled, } = props; @@ -84,7 +86,11 @@ function ImageWithCaptionInput(props: Props) ]); return ( -
+ @@ -96,15 +102,15 @@ function ImageWithCaptionInput(props: Props) url={url} fileIdToUrlMap={fileIdToUrlMap} setFileIdToUrlMap={setFileIdToUrlMap} - icons={icons} - actions={actions} + before={before} + after={after} disabled={disabled} // FIXME: Make Go single file input with preview description={isDefined(fileUrl) ? ( - {strings.imageWithCaptionPreview} ) : undefined} clearable @@ -113,7 +119,6 @@ function ImageWithCaptionInput(props: Props) {value?.id && isDefined(fileUrl) && ( (props: Props) disabled={disabled} /> )} -
+ ); } diff --git a/app/src/components/domain/ImageWithCaptionInput/styles.module.css b/app/src/components/domain/ImageWithCaptionInput/styles.module.css deleted file mode 100644 index cd382dbe4a..0000000000 --- a/app/src/components/domain/ImageWithCaptionInput/styles.module.css +++ /dev/null @@ -1,11 +0,0 @@ -.image-with-caption-input { - display: flex; - flex-direction: column; - justify-content: center; - gap: var(--go-ui-spacing-md); - - .preview { - width: 10rem; - height: 10rem; - } -} diff --git a/app/src/components/domain/ImminentEventListItem/index.tsx b/app/src/components/domain/ImminentEventListItem/index.tsx new file mode 100644 index 0000000000..c5128338a3 --- /dev/null +++ b/app/src/components/domain/ImminentEventListItem/index.tsx @@ -0,0 +1,85 @@ +import { + useEffect, + useRef, +} from 'react'; +import { + ChevronDownLineIcon, + ChevronUpLineIcon, +} from '@ifrc-go/icons'; +import { + Button, + Container, +} from '@ifrc-go/ui'; + +interface Props { + className?: string; + eventId: number | string; + heading: React.ReactNode; + description: React.ReactNode; + expanded: boolean; + onExpandClick: (eventId: number | string) => void; + children?: React.ReactNode; +} + +function ImminentEventListItem(props: Props) { + const { + eventId, + className, + heading, + description, + expanded, + onExpandClick, + children, + } = props; + + const elementRef = useRef(null); + + useEffect( + () => { + if (expanded && elementRef.current) { + const y = window.scrollY; + const x = window.scrollX; + elementRef.current.scrollIntoView({ + behavior: 'instant', + block: 'start', + }); + // NOTE: We need to scroll back because scrollIntoView also + // scrolls the parent container + window.scroll(x, y); + } + }, + [expanded], + ); + + return ( + + {expanded + ? + : } + + )} + headerDescription={description} + spacing="sm" + withBackground + withPadding + withoutSpacingOpticalCorrection + withContentWell + > + {children} + + ); +} + +export default ImminentEventListItem; diff --git a/app/src/components/domain/MultiImageWithCaptionInput/index.tsx b/app/src/components/domain/MultiImageWithCaptionInput/index.tsx index 9e7ba273a1..ccc96bb54f 100644 --- a/app/src/components/domain/MultiImageWithCaptionInput/index.tsx +++ b/app/src/components/domain/MultiImageWithCaptionInput/index.tsx @@ -5,11 +5,12 @@ import { import { DeleteBinLineIcon } from '@ifrc-go/icons'; import { IconButton, + Image, + ListView, TextInput, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; import { - _cs, isDefined, isNotDefined, randomString, @@ -25,7 +26,6 @@ import GoMultiFileInput, { type SupportedPaths } from '#components/domain/GoMult import NonFieldError from '#components/NonFieldError'; import i18n from './i18n.json'; -import styles from './styles.module.css'; type Value = { client_id: string; @@ -43,8 +43,8 @@ interface Props { fileIdToUrlMap: Record; setFileIdToUrlMap?: React.Dispatch>>; label: React.ReactNode; - icons?: React.ReactNode; - actions?: React.ReactNode; + before?: React.ReactNode; + after?: React.ReactNode; disabled?: boolean; } @@ -60,8 +60,8 @@ function MultiImageWithCaptionInput(props: Prop onChange, error: formError, label, - icons, - actions, + before, + after, disabled, } = props; @@ -126,7 +126,11 @@ function MultiImageWithCaptionInput(props: Prop ), [value]); return ( -
+ (props: Prop url={url} fileIdToUrlMap={fileIdToUrlMap} setFileIdToUrlMap={setFileIdToUrlMap} - icons={icons} - actions={actions} + before={before} + after={after} withoutPreview disabled={disabled} > {label} {value && value.length > 0 && ( -
+ {value?.map((fileValue, index) => { // NOTE: Not sure why this is here, need to // TODO: talk with @frozenhelium @@ -155,13 +159,13 @@ function MultiImageWithCaptionInput(props: Prop const imageError = getErrorObject(error?.[fileValue.client_id]); return ( -
(props: Prop - {strings.imagePreviewAlt} (props: Prop placeholder={strings.enterCaptionPlaceholder} disabled={disabled} /> -
+
); })} -
+
)} -
+ ); } diff --git a/app/src/components/domain/MultiImageWithCaptionInput/styles.module.css b/app/src/components/domain/MultiImageWithCaptionInput/styles.module.css deleted file mode 100644 index 89b646fa7c..0000000000 --- a/app/src/components/domain/MultiImageWithCaptionInput/styles.module.css +++ /dev/null @@ -1,40 +0,0 @@ -.multi-image-with-caption-input { - display: flex; - flex-direction: column; - justify-content: center; - gap: var(--go-ui-spacing-md); - - .file-list { - display: flex; - flex-wrap: wrap; - gap: var(--go-ui-spacing-lg); - - .preview-and-caption { - display: flex; - position: relative; - flex-direction: column; - gap: var(--go-ui-spacing-xs); - - .remove-button { - position: absolute; - right: 0; - transform: translateX(50%) translateY(-50%); - z-index: 111; - font-size: var(--go-ui-font-size-md); - } - - .preview { - background-color: var(--go-ui-color-background); - width: 10rem; - height: 10rem; - object-fit: contain; - object-position: center center; - } - - .caption-input { - align-self: stretch; - width: 10rem; - } - } - } -} diff --git a/app/src/components/domain/OperationListItem/index.tsx b/app/src/components/domain/OperationListItem/index.tsx index 985c6c69c7..9b9389fcea 100644 --- a/app/src/components/domain/OperationListItem/index.tsx +++ b/app/src/components/domain/OperationListItem/index.tsx @@ -1,6 +1,6 @@ import { Button, - Header, + Container, TextOutput, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; @@ -11,7 +11,6 @@ import { } from '#utils/restRequest'; import i18n from './i18n.json'; -import styles from './styles.module.css'; type EventGet = GoApiResponse<'/api/v2/event/'>; type EventResponseItem = NonNullable[number]; @@ -20,7 +19,6 @@ export interface Props { className?: string; eventItem: EventResponseItem; updateSubscribedEvents: () => void; - isLastItem: boolean; } function OperationInfoCard(props: Props) { @@ -32,7 +30,6 @@ function OperationInfoCard(props: Props) { updated_at, }, updateSubscribedEvents, - isLastItem, } = props; const strings = useTranslation(i18n); @@ -52,34 +49,30 @@ function OperationInfoCard(props: Props) { const subscriptionPending = removeSubscriptionPending; return ( - <> -
- {strings.operationUnfollowButtonLabel} - - )} - > - -
- {!isLastItem && ( -
+ + {strings.operationUnfollowButtonLabel} + )} - + withPadding + withDarkBackground + > + + ); } diff --git a/app/src/components/domain/OperationListItem/styles.module.css b/app/src/components/domain/OperationListItem/styles.module.css deleted file mode 100644 index f919b3c22d..0000000000 --- a/app/src/components/domain/OperationListItem/styles.module.css +++ /dev/null @@ -1,3 +0,0 @@ -.separator { - border-bottom: var(--go-ui-width-separator-thin) solid var(--go-ui-color-separator); -} diff --git a/app/src/components/domain/PerAssessmentSummary/index.tsx b/app/src/components/domain/PerAssessmentSummary/index.tsx index 1df01d8d0e..4fed14e507 100644 --- a/app/src/components/domain/PerAssessmentSummary/index.tsx +++ b/app/src/components/domain/PerAssessmentSummary/index.tsx @@ -1,6 +1,7 @@ import { ExpandableContainer, - NumberOutput, + Label, + ListView, ProgressBar, StackedProgressBar, TextOutput, @@ -47,8 +48,6 @@ interface Props { areaIdToTitleMap: Record; } -const progressBarColor = 'var(--go-ui-color-dark-blue-40)'; - function numberOfComponentsSelector({ components } : { components: unknown[]}) { return components.length; } @@ -208,13 +207,19 @@ function PerAssessmentSummary(props: Props) { className={_cs(styles.perAssessmentSummary, className)} heading={strings.perAssessmentSummaryHeading} headerDescription={description} - childrenContainerClassName={styles.content} withHeaderBorder - spacing="comfortable" + withPadding + withBackground + spacing="lg" > -
+ + {groupedResponseList.map( (groupedResponse) => ( ), )} -
+ )} /> -
- -
- {averageRatingByAreaList.map( - (rating) => ( -
- -
-
+ + {averageRatingByAreaList.map( + (rating) => ( + + -
-
- {rating.areaDisplay} -
-
- ), - )} -
+
+
+
+ + + ), + )} + + ); } diff --git a/app/src/components/domain/PerAssessmentSummary/styles.module.css b/app/src/components/domain/PerAssessmentSummary/styles.module.css index e5a30c76f8..143cd0c167 100644 --- a/app/src/components/domain/PerAssessmentSummary/styles.module.css +++ b/app/src/components/domain/PerAssessmentSummary/styles.module.css @@ -1,48 +1,16 @@ -.per-assessment-summary { - .content { - display: grid; - grid-gap: var(--go-ui-spacing-2xl); - grid-template-columns: repeat(auto-fit, minmax(18rem, 1fr)); +.rating { + align-items: center; - .total-progress { - .answer-counts { - display: flex; - color: var(--go-ui-color-dark-blue-40); - gap: var(--go-ui-spacing-lg); - } - } - - .component-rating { - grid-column: auto / span 2; - } - - .avg-component-rating { - display: flex; - gap: var(--go-ui-spacing-sm); - - .area-rating { - display: flex; - align-items: center; - flex-direction: column; - - .rating-value { - font-size: var(--go-ui-font-size-sm); - font-weight: var(--go-ui-font-weight-semibold); - } - - .bar-container { - display: flex; - align-items: flex-end; - background-color: var(--go-ui-color-separator); - width: 1rem; - height: 4rem; + .bar-container { + display: flex; + align-items: flex-end; + background-color: var(--go-ui-color-separator); + width: 1rem; + height: 4rem; - .filled-bar { - background-color: var(--go-ui-color-dark-blue-40); - width: 100%; - } - } - } + .filled-bar { + background-color: var(--go-ui-color-dark-blue-40); + width: 100%; } } } diff --git a/app/src/components/domain/RegionKeyFigures/index.tsx b/app/src/components/domain/RegionKeyFigures/index.tsx index f8eef414b1..307d3e8281 100644 --- a/app/src/components/domain/RegionKeyFigures/index.tsx +++ b/app/src/components/domain/RegionKeyFigures/index.tsx @@ -8,7 +8,8 @@ import { } from '@ifrc-go/icons'; import { InfoPopup, - KeyFigure, + KeyFigureView, + ListView, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; import { getPercentage } from '@ifrc-go/ui/utils'; @@ -18,7 +19,6 @@ import type { GoApiResponse } from '#utils/restRequest'; import { useRequest } from '#utils/restRequest'; import i18n from './i18n.json'; -import styles from './styles.module.css'; type RegionResponse = GoApiResponse<'/api/v2/region/{id}/'>; @@ -51,11 +51,14 @@ function RegionKeyFigures(props: Props) { } return ( - <> - + } - className={styles.keyFigure} value={aggregatedAppealResponse.active_drefs} + valueType="number" info={( )} label={strings.regionKeyFiguresActiveDrefs} + size="lg" /> - } - className={styles.keyFigure} value={aggregatedAppealResponse.active_appeals} + valueType="number" info={( )} label={strings.regionKeyFiguresActiveAppeals} + size="lg" /> - } - className={styles.keyFigure} value={aggregatedAppealResponse.amount_requested_dref_included} - compactValue + valueType="number" + size="lg" + valueOptions={{ compact: true }} label={strings.regionKeyFiguresBudget} /> - } - className={styles.keyFigure} value={getPercentage( aggregatedAppealResponse?.amount_funded_dref_included, aggregatedAppealResponse?.amount_requested_dref_included, )} - suffix="%" - compactValue + valueType="number" + valueOptions={{ + compact: true, + suffix: '%', + }} + size="lg" label={strings.regionKeyFiguresAppealsFunding} /> - } - className={styles.keyFigure} value={aggregatedAppealResponse.target_population} - compactValue + valueType="number" + size="lg" + valueOptions={{ compact: true }} label={strings.regionKeyFiguresTargetPop} /> - } - className={styles.keyFigure} value={regionResponse.country_plan_count} - compactValue + valueType="number" + size="lg" + valueOptions={{ compact: true }} label={strings.regionKeyFiguresCountryPlan} /> - + ); } diff --git a/app/src/components/domain/RegionKeyFigures/styles.module.css b/app/src/components/domain/RegionKeyFigures/styles.module.css deleted file mode 100644 index 4dc4177fa1..0000000000 --- a/app/src/components/domain/RegionKeyFigures/styles.module.css +++ /dev/null @@ -1,5 +0,0 @@ -.key-figure { - border-radius: var(--go-ui-border-radius-lg); - background-color: var(--go-ui-color-white); - height: 100%; -} diff --git a/app/src/components/domain/RiskImminentEventMap/LayerOptions/index.tsx b/app/src/components/domain/RiskImminentEventMap/LayerOptions/index.tsx index 65ce95b229..ce7496d8c0 100644 --- a/app/src/components/domain/RiskImminentEventMap/LayerOptions/index.tsx +++ b/app/src/components/domain/RiskImminentEventMap/LayerOptions/index.tsx @@ -1,7 +1,7 @@ import { useMemo } from 'react'; import { - Container, Legend, + ListView, Switch, } from '@ifrc-go/ui'; @@ -15,8 +15,6 @@ import { import { type RiskLayerSeverity } from '../utils'; -import styles from './styles.module.css'; - export interface LayerOptionsValue { showStormPosition: boolean; showForecastUncertainty: boolean; @@ -83,10 +81,9 @@ function LayerOptions(props: Props) { ]), []); return ( - {!exposureAreaControlHidden && ( -
+ {value.showExposedArea && ( )} -
+ )} -
+ ); } diff --git a/app/src/components/domain/RiskImminentEventMap/LayerOptions/styles.module.css b/app/src/components/domain/RiskImminentEventMap/LayerOptions/styles.module.css deleted file mode 100644 index 3de1362016..0000000000 --- a/app/src/components/domain/RiskImminentEventMap/LayerOptions/styles.module.css +++ /dev/null @@ -1,21 +0,0 @@ -.layer-options { - .exposed-area-input-wrapper { - display: flex; - gap: var(--go-ui-spacing-sm); - flex-direction: column; - background-color: var(--go-ui-color-background); - padding: var(--go-ui-spacing-sm); - - .exposed-area-legend { - display: flex; - flex-direction: column; - gap: unset; - - .legend-label { - color: var(--go-ui-color-text-light); - font-size: var(--go-ui-font-size-sm); - font-weight: var(--go-ui-font-weight-medium); - } - } - } -} diff --git a/app/src/components/domain/RiskImminentEventMap/index.tsx b/app/src/components/domain/RiskImminentEventMap/index.tsx index 2a58a3e070..fa580127fe 100644 --- a/app/src/components/domain/RiskImminentEventMap/index.tsx +++ b/app/src/components/domain/RiskImminentEventMap/index.tsx @@ -5,7 +5,8 @@ import { } from 'react'; import { Container, - List, + ListView, + RawList, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; import { @@ -30,7 +31,7 @@ import type { } from 'mapbox-gl'; import GlobalMap from '#components/domain/GlobalMap'; -import MapContainerWithDisclaimer from '#components/MapContainerWithDisclaimer'; +import GoMapContainer from '#components/GoMapContainer'; import { type components } from '#generated/riskTypes'; import useDebouncedValue from '#hooks/useDebouncedValue'; import { @@ -350,9 +351,9 @@ function RiskImminentEventMap< - {hazardKeys.map((key) => { const url = hazardKeyToIconMap[key]; @@ -471,24 +472,30 @@ function RiskImminentEventMap< )} - + + +
); diff --git a/app/src/components/domain/RiskImminentEventMap/styles.module.css b/app/src/components/domain/RiskImminentEventMap/styles.module.css index 15a3d78a63..0315c29d73 100644 --- a/app/src/components/domain/RiskImminentEventMap/styles.module.css +++ b/app/src/components/domain/RiskImminentEventMap/styles.module.css @@ -1,72 +1,14 @@ .risk-imminent-event-map { display: flex; gap: var(--go-ui-spacing-md); - height: 40rem; - overflow: auto; .side-panel { flex-basis: calc(14vw + 16rem); - margin: var(--go-ui-spacing-sm) var(--go-ui-spacing-sm) var(--go-ui-spacing-sm) 0; - border-radius: var(--go-ui-border-radius-md); - box-shadow: var(--go-ui-box-shadow-sm); - - .icon { - font-size: var(--go-ui-height-icon-multiplier); - } - - .content { - overflow: auto; - - .event-list { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-xs); - - .risk-event-list-item { - border: var(--go-ui-width-separator-sm) solid transparent; - background-color: var(--go-ui-color-background); - padding: var(--go-ui-spacing-sm); - - &:hover { - border-color: var(--go-ui-color-separator); - } - } - } - } + height: var(--go-ui-height-map-md); } .map-container { flex-grow: 1; - - .legend { - display: flex; - flex-wrap: wrap; - gap: var(--go-ui-spacing-xs) var(--go-ui-spacing-md); - background-color: var(--go-ui-color-white); - - .legend-item { - display: flex; - align-items: center; - gap: var(--go-ui-spacing-xs); - - .icon-container { - display: flex; - align-items: center; - justify-content: center; - border-radius: 50%; - width: var(--go-ui-font-size-2xl); - height: var(--go-ui-font-size-2xl); - - .icon { - color: var(--go-ui-color-white); - } - - .wildfire-icon { - height: 0.8rem; - } - } - } - } } @media screen and (max-width: 50rem) { @@ -81,9 +23,5 @@ max-height: 70vh; overflow: auto; } - - .map-container { - height: min(40rem, 60vh); - } } } diff --git a/app/src/components/domain/RiskImminentEvents/Gdacs/EventDetails/index.tsx b/app/src/components/domain/RiskImminentEvents/Gdacs/EventDetails/index.tsx index c8d6a488d2..c92d2cba86 100644 --- a/app/src/components/domain/RiskImminentEvents/Gdacs/EventDetails/index.tsx +++ b/app/src/components/domain/RiskImminentEvents/Gdacs/EventDetails/index.tsx @@ -1,5 +1,7 @@ import { Container, + InlineLayout, + ListView, TextOutput, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; @@ -83,22 +85,17 @@ function EventDetails(props: Props) { const eventDetails = event_details as GdacsEventDetails | undefined; return ( - - + {isDefined(eventDetails?.source) && ( )} {isDefined(populationExposure?.death) && ( @@ -109,7 +106,7 @@ function EventDetails(props: Props) { compact valueType="number" strongValue - withBackground + withLightBackground /> )} {isDefined(populationExposure?.displaced) && ( @@ -120,7 +117,7 @@ function EventDetails(props: Props) { compact valueType="number" strongValue - withBackground + withLightBackground /> )} {isDefined(populationExposure?.exposed_population) && ( @@ -128,7 +125,7 @@ function EventDetails(props: Props) { label={strings.eventPopulationLabel} value={populationExposure?.exposed_population} strongValue - withBackground + withLightBackground /> )} {isDefined(populationExposure?.people_affected) && ( @@ -136,7 +133,7 @@ function EventDetails(props: Props) { label={strings.eventPeopleAffectedLabel} value={populationExposure?.people_affected} strongValue - withBackground + withLightBackground /> )} {isDefined(populationExposure?.impact) && ( @@ -144,7 +141,7 @@ function EventDetails(props: Props) { label={strings.eventImpactLabel} value={populationExposure?.impact} strongValue - withBackground + withLightBackground /> )} {isDefined(eventDetails?.severitydata) @@ -153,7 +150,7 @@ function EventDetails(props: Props) { label={strings.eventSeverityLabel} value={eventDetails?.severitydata?.severitytext} strongValue - withBackground + withLightBackground /> )} {isDefined(eventDetails?.alertlevel) && ( @@ -161,25 +158,29 @@ function EventDetails(props: Props) { label={strings.eventAlertType} value={eventDetails?.alertlevel} strongValue - withBackground + withLightBackground /> )} - - {isDefined(eventDetails) - && isDefined(eventDetails.url) - && isDefined(eventDetails.url.report) - && ( - - {strings.eventMoreDetailsLink} - - )} - {/* NOTE: Intentional additional div to maintain gap */} - {children &&
} - {children} + {isDefined(eventDetails) + && isDefined(eventDetails.url) + && isDefined(eventDetails.url.report) + && ( + + {strings.eventMoreDetailsLink} + + )} + /> + )} + {/* NOTE: Intentional additional div to maintain gap */} + {children &&
} + {children} + ); } diff --git a/app/src/components/domain/RiskImminentEvents/Gdacs/EventListItem/i18n.json b/app/src/components/domain/RiskImminentEvents/Gdacs/EventListItem/i18n.json index be230b82ff..2c935f922d 100644 --- a/app/src/components/domain/RiskImminentEvents/Gdacs/EventListItem/i18n.json +++ b/app/src/components/domain/RiskImminentEvents/Gdacs/EventListItem/i18n.json @@ -1,7 +1,6 @@ { "namespace": "riskImminentEvents", "strings": { - "gdacsEventViewDetails": "View / Hide Details", "gdacsEventStartedOn": "Started On" } } \ No newline at end of file diff --git a/app/src/components/domain/RiskImminentEvents/Gdacs/EventListItem/index.tsx b/app/src/components/domain/RiskImminentEvents/Gdacs/EventListItem/index.tsx index 6fb117d2ca..f3cb2b4f45 100644 --- a/app/src/components/domain/RiskImminentEvents/Gdacs/EventListItem/index.tsx +++ b/app/src/components/domain/RiskImminentEvents/Gdacs/EventListItem/index.tsx @@ -1,24 +1,11 @@ -import { - useEffect, - useRef, -} from 'react'; -import { - ChevronDownLineIcon, - ChevronUpLineIcon, -} from '@ifrc-go/icons'; -import { - Button, - Header, - TextOutput, -} from '@ifrc-go/ui'; +import { TextOutput } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; -import { _cs } from '@togglecorp/fujs'; +import ImminentEventListItem from '#components/domain/ImminentEventListItem'; import { type RiskEventListItemProps } from '#components/domain/RiskImminentEventMap'; import { type RiskApiResponse } from '#utils/restRequest'; import i18n from './i18n.json'; -import styles from './styles.module.css'; type ImminentEventResponse = RiskApiResponse<'/api/v1/gdacs/'>; type GdacsItem = NonNullable[number]; @@ -40,54 +27,24 @@ function EventListItem(props: Props) { const strings = useTranslation(i18n); - const elementRef = useRef(null); - - useEffect( - () => { - if (expanded && elementRef.current) { - const y = window.scrollY; - const x = window.scrollX; - elementRef.current.scrollIntoView({ - behavior: 'instant', - block: 'start', - }); - // NOTE: We need to scroll back because scrollIntoView also - // scrolls the parent container - window.scroll(x, y); - } - }, - [expanded], - ); - return ( - <> -
- {expanded - ? - : } - - )} - spacing="cozy" - > + -
+ )} + > {children} - + ); } diff --git a/app/src/components/domain/RiskImminentEvents/Gdacs/EventListItem/styles.module.css b/app/src/components/domain/RiskImminentEvents/Gdacs/EventListItem/styles.module.css deleted file mode 100644 index e543c0160d..0000000000 --- a/app/src/components/domain/RiskImminentEvents/Gdacs/EventListItem/styles.module.css +++ /dev/null @@ -1,28 +0,0 @@ -.event-list-item { - gap: 0; - - .icon { - font-size: var(--go-ui-height-icon-multiplier); - } - - &:hover { - .icon { - animation: wiggle var(--go-ui-duration-transition-slow) ease-in-out; - } - } -} - -@keyframes wiggle { - 0% { - transform: translateX(0); - } - 25% { - transform: translateX(-0.1rem); - } - 50% { - transform: translateX(0.1rem); - } - 100% { - transform: translateX(0); - } -} diff --git a/app/src/components/domain/RiskImminentEvents/MeteoSwiss/EventDetails/index.tsx b/app/src/components/domain/RiskImminentEvents/MeteoSwiss/EventDetails/index.tsx index a1c8db79d2..1351fdfcd9 100644 --- a/app/src/components/domain/RiskImminentEvents/MeteoSwiss/EventDetails/index.tsx +++ b/app/src/components/domain/RiskImminentEvents/MeteoSwiss/EventDetails/index.tsx @@ -3,9 +3,10 @@ import { useMemo, } from 'react'; import { - BlockLoading, Container, DateOutput, + Description, + ListView, NumberOutput, TextOutput, } from '@ifrc-go/ui'; @@ -24,7 +25,6 @@ import Link from '#components/Link'; import { type RiskApiResponse } from '#utils/restRequest'; import i18n from './i18n.json'; -import styles from './styles.module.css'; type MeteoSwissResponse = RiskApiResponse<'/api/v1/meteoswiss/'>; type MeteoSwissItem = NonNullable[number]; @@ -167,107 +167,99 @@ function EventDetails(props: Props) { // TODO: add exposure details return ( - {pending && } - {!pending && ( - <> - - {impactList.map((impact) => ( - {strings.beta}, - }, - )} - valueClassName={styles.impactValue} - value={resolveToComponent( - strings.meteoSwissImpactValue, - { - value: ( - - ), - fivePercent: ( - - ), - ninetyFivePercent: ( - - ), - unit: impact.unit, - }, - )} - strongValue + + + {impactList.map((impact) => ( + {strings.beta}, + }, + )} + value={resolveToComponent( + strings.meteoSwissImpactValue, + { + value: ( + + ), + fivePercent: ( + + ), + ninetyFivePercent: ( + + ), + unit: impact.unit, + }, + )} + strongValue + /> + ))} + + {strings.meteoSwissEstimatesNote} + + + +
+ {resolveToComponent( + strings.meteoSwissEventDescription, + { + model: model_name ?? '--', + updatedAt: ( + - ))} -
- {strings.meteoSwissEstimatesNote} -
- -
- {resolveToComponent( - strings.meteoSwissEventDescription, - { - model: model_name ?? '--', - updatedAt: ( - - ), - eventName: hazard_name, - countryName: country_details?.name ?? '--', - eventDate: , - }, - )} -
-
- {resolveToComponent( - strings.meteoSwissAuthoritativeMessage, - { - link: ( - - {strings.meteoSwissAuthoritativeLinkLabel} - - ), - classificationLink: ( - - {strings.meteoSwissTropicalStorm} - - ), - }, - )} -
- - )} + ), + eventName: hazard_name, + countryName: country_details?.name ?? '--', + eventDate: , + }, + )} +
+
+ {resolveToComponent( + strings.meteoSwissAuthoritativeMessage, + { + link: ( + + {strings.meteoSwissAuthoritativeLinkLabel} + + ), + classificationLink: ( + + {strings.meteoSwissTropicalStorm} + + ), + }, + )} +
); } diff --git a/app/src/components/domain/RiskImminentEvents/MeteoSwiss/EventDetails/styles.module.css b/app/src/components/domain/RiskImminentEvents/MeteoSwiss/EventDetails/styles.module.css deleted file mode 100644 index 8aec27b6a6..0000000000 --- a/app/src/components/domain/RiskImminentEvents/MeteoSwiss/EventDetails/styles.module.css +++ /dev/null @@ -1,17 +0,0 @@ -.event-details { - .impact-value { - gap: var(--go-ui-spacing-4xs); - } - - .beta { - padding: 0 var(--go-ui-spacing-2xs); - vertical-align: super; - color: var(--go-ui-color-gray-80); - font-size: var(--go-ui-font-size-2xs); - } - - .estimation-note { - color: var(--go-ui-color-text-light); - font-size: var(--go-ui-font-size-sm); - } -} diff --git a/app/src/components/domain/RiskImminentEvents/MeteoSwiss/EventListItem/i18n.json b/app/src/components/domain/RiskImminentEvents/MeteoSwiss/EventListItem/i18n.json index 02f97d3a01..368da35e03 100644 --- a/app/src/components/domain/RiskImminentEvents/MeteoSwiss/EventListItem/i18n.json +++ b/app/src/components/domain/RiskImminentEvents/MeteoSwiss/EventListItem/i18n.json @@ -1,7 +1,6 @@ { "namespace": "riskImminentEvents", "strings": { - "meteoSwissEventListViewDetails": "View / Hide Details", "meteoSwissEventListStartedOn": "Started On" } -} \ No newline at end of file +} diff --git a/app/src/components/domain/RiskImminentEvents/MeteoSwiss/EventListItem/index.tsx b/app/src/components/domain/RiskImminentEvents/MeteoSwiss/EventListItem/index.tsx index fd454a252e..0e3f42ec6e 100644 --- a/app/src/components/domain/RiskImminentEvents/MeteoSwiss/EventListItem/index.tsx +++ b/app/src/components/domain/RiskImminentEvents/MeteoSwiss/EventListItem/index.tsx @@ -2,23 +2,14 @@ import { useEffect, useRef, } from 'react'; -import { - ChevronDownLineIcon, - ChevronUpLineIcon, -} from '@ifrc-go/icons'; -import { - Button, - Header, - TextOutput, -} from '@ifrc-go/ui'; +import { TextOutput } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; -import { _cs } from '@togglecorp/fujs'; +import ImminentEventListItem from '#components/domain/ImminentEventListItem'; import { type RiskEventListItemProps } from '#components/domain/RiskImminentEventMap'; import { type RiskApiResponse } from '#utils/restRequest'; import i18n from './i18n.json'; -import styles from './styles.module.css'; type ImminentEventResponse = RiskApiResponse<'/api/v1/meteoswiss/'>; type EventItem = NonNullable[number]; @@ -64,34 +55,22 @@ function EventListItem(props: Props) { ); return ( - <> -
- {expanded - ? - : } - - )} - spacing="condensed" - > + -
+ )} + > {children} - + ); } diff --git a/app/src/components/domain/RiskImminentEvents/MeteoSwiss/EventListItem/styles.module.css b/app/src/components/domain/RiskImminentEvents/MeteoSwiss/EventListItem/styles.module.css deleted file mode 100644 index e543c0160d..0000000000 --- a/app/src/components/domain/RiskImminentEvents/MeteoSwiss/EventListItem/styles.module.css +++ /dev/null @@ -1,28 +0,0 @@ -.event-list-item { - gap: 0; - - .icon { - font-size: var(--go-ui-height-icon-multiplier); - } - - &:hover { - .icon { - animation: wiggle var(--go-ui-duration-transition-slow) ease-in-out; - } - } -} - -@keyframes wiggle { - 0% { - transform: translateX(0); - } - 25% { - transform: translateX(-0.1rem); - } - 50% { - transform: translateX(0.1rem); - } - 100% { - transform: translateX(0); - } -} diff --git a/app/src/components/domain/RiskImminentEvents/Pdc/EventDetails/index.tsx b/app/src/components/domain/RiskImminentEvents/Pdc/EventDetails/index.tsx index 83afc3ea4e..33d74aae64 100644 --- a/app/src/components/domain/RiskImminentEvents/Pdc/EventDetails/index.tsx +++ b/app/src/components/domain/RiskImminentEvents/Pdc/EventDetails/index.tsx @@ -1,5 +1,6 @@ import { Container, + ListView, TextOutput, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; @@ -49,73 +50,68 @@ function EventDetails(props: Props) { } | null; return ( - - + - - - {children} + + {children} + ); } diff --git a/app/src/components/domain/RiskImminentEvents/Pdc/EventListItem/i18n.json b/app/src/components/domain/RiskImminentEvents/Pdc/EventListItem/i18n.json index bdfa33d596..cbca88c517 100644 --- a/app/src/components/domain/RiskImminentEvents/Pdc/EventListItem/i18n.json +++ b/app/src/components/domain/RiskImminentEvents/Pdc/EventListItem/i18n.json @@ -1,7 +1,6 @@ { "namespace": "riskImminentEvents", "strings": { - "eventListViewDetails": "View / Hide Details", "eventListStartedOn": "Started on" } } \ No newline at end of file diff --git a/app/src/components/domain/RiskImminentEvents/Pdc/EventListItem/index.tsx b/app/src/components/domain/RiskImminentEvents/Pdc/EventListItem/index.tsx index 91f6e4cef5..787e2a921b 100644 --- a/app/src/components/domain/RiskImminentEvents/Pdc/EventListItem/index.tsx +++ b/app/src/components/domain/RiskImminentEvents/Pdc/EventListItem/index.tsx @@ -1,24 +1,11 @@ -import { - useEffect, - useRef, -} from 'react'; -import { - ChevronDownLineIcon, - ChevronUpLineIcon, -} from '@ifrc-go/icons'; -import { - Button, - Header, - TextOutput, -} from '@ifrc-go/ui'; +import { TextOutput } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; -import { _cs } from '@togglecorp/fujs'; +import ImminentEventListItem from '#components/domain/ImminentEventListItem'; import { type RiskEventListItemProps } from '#components/domain/RiskImminentEventMap'; import { type RiskApiResponse } from '#utils/restRequest'; import i18n from './i18n.json'; -import styles from './styles.module.css'; type ImminentEventResponse = RiskApiResponse<'/api/v1/pdc/'>; type EventItem = NonNullable[number]; @@ -40,54 +27,23 @@ function EventListItem(props: Props) { const strings = useTranslation(i18n); - const elementRef = useRef(null); - - useEffect( - () => { - if (expanded && elementRef.current) { - const y = window.scrollY; - const x = window.scrollX; - elementRef.current.scrollIntoView({ - behavior: 'instant', - block: 'start', - }); - // NOTE: We need to scroll back because scrollIntoView also - // scrolls the parent container - window.scroll(x, y); - } - }, - [expanded], - ); - return ( - <> -
- {expanded - ? - : } - - )} - spacing="cozy" - > + -
+ )} + expanded={expanded} + eventId={id} + onExpandClick={onExpandClick} + > {children} - + ); } diff --git a/app/src/components/domain/RiskImminentEvents/Pdc/EventListItem/styles.module.css b/app/src/components/domain/RiskImminentEvents/Pdc/EventListItem/styles.module.css deleted file mode 100644 index e543c0160d..0000000000 --- a/app/src/components/domain/RiskImminentEvents/Pdc/EventListItem/styles.module.css +++ /dev/null @@ -1,28 +0,0 @@ -.event-list-item { - gap: 0; - - .icon { - font-size: var(--go-ui-height-icon-multiplier); - } - - &:hover { - .icon { - animation: wiggle var(--go-ui-duration-transition-slow) ease-in-out; - } - } -} - -@keyframes wiggle { - 0% { - transform: translateX(0); - } - 25% { - transform: translateX(-0.1rem); - } - 50% { - transform: translateX(0.1rem); - } - 100% { - transform: translateX(0); - } -} diff --git a/app/src/components/domain/RiskImminentEvents/WfpAdam/EventDetails/index.tsx b/app/src/components/domain/RiskImminentEvents/WfpAdam/EventDetails/index.tsx index a7a70d47cb..b4584a98c6 100644 --- a/app/src/components/domain/RiskImminentEvents/WfpAdam/EventDetails/index.tsx +++ b/app/src/components/domain/RiskImminentEvents/WfpAdam/EventDetails/index.tsx @@ -1,6 +1,7 @@ import { useMemo } from 'react'; import { Container, + ListView, TextOutput, Tooltip, } from '@ifrc-go/ui'; @@ -158,225 +159,228 @@ function EventDetails(props: Props) { return ( - {stormPoints && stormPoints.length > 0 && isDefined(maxWindSpeed) && ( - /* TODO: use proper svg charts */ -
-
- {stormPoints.map( - (point) => ( -
- + + {stormPoints && stormPoints.length > 0 && isDefined(maxWindSpeed) && ( + /* TODO: use proper svg charts */ +
+
+ {stormPoints.map( + (point) => (
-
- ), - )} -
-
- {strings.wfpChartLabel} + key={point.id} + className={styles.barContainer} + > + +
+
+ ), + )} +
+
+ {strings.wfpChartLabel} +
-
- )} - {isDefined(eventDetails) - && (isDefined(eventDetails.url) || isDefined(eventDetails.dashboard_url)) && ( - - {isDefined(dashboardUrl) && ( - + - {strings.wfpDashboard} - - )} - {isDefined(eventDetails?.url) && ( - <> - {isDefined(eventDetails.url.shakemap) && ( + {isDefined(dashboardUrl) && ( - {strings.wfpShakemap} + {strings.wfpDashboard} )} - {isDefined(eventDetails.url.population) && ( - - {strings.wfpPopulationTable} - + {isDefined(eventDetails?.url) && ( + <> + {isDefined(eventDetails.url.shakemap) && ( + + {strings.wfpShakemap} + + )} + {isDefined(eventDetails.url.population) && ( + + {strings.wfpPopulationTable} + + )} + {isDefined(eventDetails.url.wind) && ( + + {strings.wfpWind} + + )} + {isDefined(eventDetails.url.rainfall) && ( + + {strings.wfpRainfall} + + )} + {isDefined(eventDetails.url.shapefile) && ( + + {strings.wfpShapefile} + + )} + )} - {isDefined(eventDetails.url.wind) && ( - - {strings.wfpWind} - - )} - {isDefined(eventDetails.url.rainfall) && ( - - {strings.wfpRainfall} - - )} - {isDefined(eventDetails.url.shapefile) && ( - - {strings.wfpShapefile} - - )} - - )} - - )} -
- {isDefined(eventDetails?.wind_speed) && ( - - )} - {isDefined(populationImpact) && ( - + + )} -
-
- {isDefined(eventDetails?.source) && ( - - )} - {isDefined(eventDetails?.sitrep) && ( - - )} - {isDefined(eventDetails?.mag) && ( - - )} - {isDefined(eventDetails?.depth) && ( - - )} - {isDefined(eventDetails?.alert_level) && ( - - )} - {isDefined(eventDetails?.effective_date) && ( - - )} - {isDefined(eventDetails?.from_date) && ( - - )} - {isDefined(eventDetails?.to_date) && ( - - )} -
-
- {isDefined(populationExposure?.exposure_60_kmh) && ( - - )} - {isDefined(populationExposure?.exposure_90_kmh) && ( - - )} - {isDefined(populationExposure?.exposure_120_kmh) && ( - - )} - {isDefined(eventDetails?.flood_area) && ( - - )} - {isDefined(eventDetails?.fl_croplnd) && ( - - )} -
- {children} +
+ {isDefined(eventDetails?.wind_speed) && ( + + )} + {isDefined(populationImpact) && ( + + )} +
+
+ {isDefined(eventDetails?.source) && ( + + )} + {isDefined(eventDetails?.sitrep) && ( + + )} + {isDefined(eventDetails?.mag) && ( + + )} + {isDefined(eventDetails?.depth) && ( + + )} + {isDefined(eventDetails?.alert_level) && ( + + )} + {isDefined(eventDetails?.effective_date) && ( + + )} + {isDefined(eventDetails?.from_date) && ( + + )} + {isDefined(eventDetails?.to_date) && ( + + )} +
+
+ {isDefined(populationExposure?.exposure_60_kmh) && ( + + )} + {isDefined(populationExposure?.exposure_90_kmh) && ( + + )} + {isDefined(populationExposure?.exposure_120_kmh) && ( + + )} + {isDefined(eventDetails?.flood_area) && ( + + )} + {isDefined(eventDetails?.fl_croplnd) && ( + + )} +
+ {children} + ); } diff --git a/app/src/components/domain/RiskImminentEvents/WfpAdam/EventListItem/i18n.json b/app/src/components/domain/RiskImminentEvents/WfpAdam/EventListItem/i18n.json index c01a896a11..f1e4d25ff8 100644 --- a/app/src/components/domain/RiskImminentEvents/WfpAdam/EventListItem/i18n.json +++ b/app/src/components/domain/RiskImminentEvents/WfpAdam/EventListItem/i18n.json @@ -1,7 +1,6 @@ { "namespace": "riskImminentEvents", "strings": { - "wfpEventListViewDetails": "View / Hide Details", "wfpEventListPublishedOn": "Published on" } -} \ No newline at end of file +} diff --git a/app/src/components/domain/RiskImminentEvents/WfpAdam/EventListItem/index.tsx b/app/src/components/domain/RiskImminentEvents/WfpAdam/EventListItem/index.tsx index e3e5e69d23..6351e1134f 100644 --- a/app/src/components/domain/RiskImminentEvents/WfpAdam/EventListItem/index.tsx +++ b/app/src/components/domain/RiskImminentEvents/WfpAdam/EventListItem/index.tsx @@ -2,23 +2,14 @@ import { useEffect, useRef, } from 'react'; -import { - ChevronDownLineIcon, - ChevronUpLineIcon, -} from '@ifrc-go/icons'; -import { - Button, - Header, - TextOutput, -} from '@ifrc-go/ui'; +import { TextOutput } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; -import { _cs } from '@togglecorp/fujs'; +import ImminentEventListItem from '#components/domain/ImminentEventListItem'; import { type RiskEventListItemProps } from '#components/domain/RiskImminentEventMap'; import { type RiskApiResponse } from '#utils/restRequest'; import i18n from './i18n.json'; -import styles from './styles.module.css'; type ImminentEventResponse = RiskApiResponse<'/api/v1/adam-exposure/'>; type EventItem = NonNullable[number]; @@ -60,34 +51,22 @@ function EventListItem(props: Props) { ); return ( - <> -
- {expanded - ? - : } - - )} - spacing="cozy" - > + -
+ )} + > {children} - + ); } diff --git a/app/src/components/domain/RiskImminentEvents/WfpAdam/EventListItem/styles.module.css b/app/src/components/domain/RiskImminentEvents/WfpAdam/EventListItem/styles.module.css deleted file mode 100644 index e543c0160d..0000000000 --- a/app/src/components/domain/RiskImminentEvents/WfpAdam/EventListItem/styles.module.css +++ /dev/null @@ -1,28 +0,0 @@ -.event-list-item { - gap: 0; - - .icon { - font-size: var(--go-ui-height-icon-multiplier); - } - - &:hover { - .icon { - animation: wiggle var(--go-ui-duration-transition-slow) ease-in-out; - } - } -} - -@keyframes wiggle { - 0% { - transform: translateX(0); - } - 25% { - transform: translateX(-0.1rem); - } - 50% { - transform: translateX(0.1rem); - } - 100% { - transform: translateX(0); - } -} diff --git a/app/src/components/domain/RiskImminentEvents/index.tsx b/app/src/components/domain/RiskImminentEvents/index.tsx index 9df883b898..12282dd4a5 100644 --- a/app/src/components/domain/RiskImminentEvents/index.tsx +++ b/app/src/components/domain/RiskImminentEvents/index.tsx @@ -13,11 +13,12 @@ import { import { Container, InfoPopup, + LegendItem, + ListView, Radio, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; import { resolveToComponent } from '@ifrc-go/ui/utils'; -import { _cs } from '@togglecorp/fujs'; import type { LngLatBoundsLike } from 'mapbox-gl'; import Link from '#components/Link'; @@ -32,7 +33,6 @@ import Pdc from './Pdc'; import WfpAdam from './WfpAdam'; import i18n from './i18n.json'; -import styles from './styles.module.css'; export type ImminentEventSource = 'pdc' | 'wfpAdam' | 'gdacs' | 'meteoSwiss'; type HazardType = components<'read'>['schemas']['CommonHazardTypeEnumKey']; @@ -64,29 +64,6 @@ function RiskImminentEvents(props: Props) { const strings = useTranslation(i18n); - const CurrentView = useMemo( - () => { - if (activeView === 'pdc') { - return Pdc; - } - - if (activeView === 'wfpAdam') { - return WfpAdam; - } - - if (activeView === 'gdacs') { - return Gdacs; - } - - if (activeView === 'meteoSwiss') { - return MeteoSwiss; - } - - return null; - }, - [activeView], - ); - const handleRadioClick = useCallback((key: ImminentEventSource) => { setActiveView(key); }, []); @@ -100,27 +77,27 @@ function RiskImminentEvents(props: Props) { { key: 'FL', label: strings.imminentEventsFlood, - icon: , + icon: , }, { key: 'TC', label: strings.imminentEventsStorm, - icon: , + icon: , }, { key: 'EQ', label: strings.imminentEventsEarthquake, - icon: , + icon: , }, { key: 'DR', label: strings.imminentEventsDrought, - icon: , + icon: , }, { key: 'WF', label: strings.imminentEventsWildfire, - icon: , + icon: , }, ], [ @@ -134,112 +111,55 @@ function RiskImminentEvents(props: Props) { return ( )} - footerContent={( -
- {riskHazards.map((hazard) => ( -
-
- {hazard.icon} -
-
- {hazard.label} -
-
- ))} -
- )} - footerActionsContainerClassName={styles.footerActions} - footerActions={( - <> - - {strings.here} - - ), - }, - )} - /> - )} - /> - - {strings.here} - - ), - }, - )} + footer={( + + + {riskHazards.map((hazard) => ( + - )} - /> - {environment !== 'production' && ( + ))} + + {strings.here} @@ -249,52 +169,124 @@ function RiskImminentEvents(props: Props) { )} /> )} - /> - )} - {environment !== 'production' && ( + > + {strings.imminentEventsSourceGdacsLabel} + -
- {strings.meteoSwissDescriptionOne} -
-
- {resolveToComponent( - strings.meteoSwissDescriptionTwo, - { - here: ( - - {strings.here} - - ), - }, - )} -
-
+ title={strings.pdcTooltipTitle} + description={resolveToComponent( + strings.pdcTooltipDescription, + { + here: ( + + {strings.here} + + ), + }, )} /> )} - /> - )} - + > + {strings.imminentEventsSourcePdcLabel} + + {environment !== 'production' && ( + + {strings.here} + + ), + }, + )} + /> + )} + > + {strings.imminentEventsSourceWfpAdamLabel} + + )} + {environment !== 'production' && ( + +
+ {strings.meteoSwissDescriptionOne} +
+
+ {resolveToComponent( + strings.meteoSwissDescriptionTwo, + { + here: ( + + {strings.here} + + ), + }, + )} +
+ + )} + /> + )} + > + {strings.imminentEventsSourceMeteoSwissLabel} +
+ )} + + )} - headingLevel={2} > - {CurrentView && ( - + )} + {activeView === 'wfpAdam' && ( + + )} + {activeView === 'gdacs' && ( + + )} + {activeView === 'meteoSwiss' && ( + diff --git a/app/src/components/domain/RiskImminentEvents/styles.module.css b/app/src/components/domain/RiskImminentEvents/styles.module.css deleted file mode 100644 index 75ccddae01..0000000000 --- a/app/src/components/domain/RiskImminentEvents/styles.module.css +++ /dev/null @@ -1,53 +0,0 @@ -.risk-imminent-events { - .wiki-icon { - font-size: var(--go-ui-font-size-3xl); - } - - .legend { - display: flex; - flex-wrap: wrap; - gap: var(--go-ui-spacing-xs) var(--go-ui-spacing-md); - - .legend-item { - display: flex; - align-items: center; - gap: var(--go-ui-spacing-xs); - - .icon-container { - display: flex; - align-items: center; - justify-content: center; - border-radius: 50%; - width: var(--go-ui-font-size-2xl); - height: var(--go-ui-font-size-2xl); - - .icon { - color: var(--go-ui-color-white); - } - - .wildfire-icon { - height: 0.8rem; - } - } - } - } - - .footer-actions { - flex-shrink: unset; - flex-wrap: wrap; - } -} - -.popup { - .description { - display: inline; - - .description-content { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-xs); - } - } -} - - diff --git a/app/src/components/domain/RiskSeasonalMap/CountryListItem/index.tsx b/app/src/components/domain/RiskSeasonalMap/CountryListItem/index.tsx new file mode 100644 index 0000000000..4deba1f72f --- /dev/null +++ b/app/src/components/domain/RiskSeasonalMap/CountryListItem/index.tsx @@ -0,0 +1,104 @@ +import { + Container, + ListView, + Tooltip, +} from '@ifrc-go/ui'; + +import Link from '#components/Link'; +import { CATEGORY_RISK_VERY_HIGH } from '#utils/constants'; +import { + type HazardType, + hazardTypeToColorMap, + type RiskMetric, +} from '#utils/domain/risk'; + +import TooltipContent from '../TooltipContent'; + +import styles from './styles.module.css'; + +const MAX_RISK_SCORE = CATEGORY_RISK_VERY_HIGH; + +interface Props { + countryId?: number; + countryName?: string; + hazardList: { + value: number; + riskCategory: number; + hazard_type: HazardType; + hazard_type_display: string | undefined; + }[]; + numHazardTypes: number; + riskMetric: RiskMetric; +} + +function CountryListItem(props: Props) { + const { + countryId, + countryName, + hazardList, + numHazardTypes, + riskMetric, + } = props; + + return ( +
+ + {countryName} + + )} + spacing="sm" + withPadding + withDarkBackground + withoutSpacingOpticalCorrection + > + + {hazardList.map( + ({ + hazard_type, + riskCategory, + }) => { + // eslint-disable-next-line max-len + const percentage = (100 * riskCategory) / (MAX_RISK_SCORE * numHazardTypes); + + if (percentage < 1) { + return null; + } + + return ( +
+ ); + }, + )} + + + + )} + /> +
+ ); +} + +export default CountryListItem; diff --git a/app/src/components/domain/RiskSeasonalMap/CountryListItem/styles.module.css b/app/src/components/domain/RiskSeasonalMap/CountryListItem/styles.module.css new file mode 100644 index 0000000000..9544e8307a --- /dev/null +++ b/app/src/components/domain/RiskSeasonalMap/CountryListItem/styles.module.css @@ -0,0 +1,20 @@ +.country-list-item { + .bar-track { + border-radius: 0.25rem; + background-color: color-mix(in srgb, var(--go-ui-color-primary-blue) 5%, transparent); + + .bar { + height: 0.5rem; + + &:first-child { + border-top-left-radius: 0.25rem; + border-bottom-left-radius: 0.25rem; + } + + &:last-child { + border-top-right-radius: 0.25rem; + border-bottom-right-radius: 0.25rem; + } + } + } +} diff --git a/app/src/components/domain/RiskSeasonalMap/TooltipContent/i18n.json b/app/src/components/domain/RiskSeasonalMap/TooltipContent/i18n.json new file mode 100644 index 0000000000..963be493c1 --- /dev/null +++ b/app/src/components/domain/RiskSeasonalMap/TooltipContent/i18n.json @@ -0,0 +1,13 @@ +{ + "namespace": "riskSeasonalMap", + "strings": { + "peopleExposedLabel": "People Exposed", + "peopleAtRiskLabel": "People at Risk of Displacement", + "riskScoreLabel": "Risk Score", + "riskCategoryVeryLow": "Very Low", + "riskCategoryLow": "Low", + "riskCategoryMedium": "Medium", + "riskCategoryHigh": "High", + "riskCategoryVeryHigh": "Very High" + } +} diff --git a/app/src/components/domain/RiskSeasonalMap/TooltipContent/index.tsx b/app/src/components/domain/RiskSeasonalMap/TooltipContent/index.tsx new file mode 100644 index 0000000000..9230712619 --- /dev/null +++ b/app/src/components/domain/RiskSeasonalMap/TooltipContent/index.tsx @@ -0,0 +1,102 @@ +import { useMemo } from 'react'; +import { + ColorPreview, + Container, + TextOutput, +} from '@ifrc-go/ui'; +import { useTranslation } from '@ifrc-go/ui/hooks'; +import { formatNumber } from '@ifrc-go/ui/utils'; + +import { + CATEGORY_RISK_HIGH, + CATEGORY_RISK_LOW, + CATEGORY_RISK_MEDIUM, + CATEGORY_RISK_VERY_HIGH, + CATEGORY_RISK_VERY_LOW, +} from '#utils/constants'; +import { + type HazardType, + hazardTypeToColorMap, + type RiskMetric, +} from '#utils/domain/risk'; + +import i18n from './i18n.json'; + +interface Props { + selectedRiskMetric: RiskMetric, + valueListByHazard: { + value: number; + riskCategory: number; + hazard_type: HazardType; + hazard_type_display: string | undefined; + }[]; +} + +function TooltipContent(props: Props) { + const { + selectedRiskMetric, + valueListByHazard, + } = props; + + const strings = useTranslation(i18n); + const riskCategoryToLabelMap: Record = useMemo( + () => ({ + [CATEGORY_RISK_VERY_LOW]: strings.riskCategoryVeryLow, + [CATEGORY_RISK_LOW]: strings.riskCategoryLow, + [CATEGORY_RISK_MEDIUM]: strings.riskCategoryMedium, + [CATEGORY_RISK_HIGH]: strings.riskCategoryHigh, + [CATEGORY_RISK_VERY_HIGH]: strings.riskCategoryVeryHigh, + }), + [ + strings.riskCategoryVeryLow, + strings.riskCategoryLow, + strings.riskCategoryMedium, + strings.riskCategoryHigh, + strings.riskCategoryVeryHigh, + ], + ); + + const riskMetricLabelMap: Record = { + riskScore: strings.riskScoreLabel, + displacement: strings.peopleAtRiskLabel, + exposure: strings.peopleExposedLabel, + }; + + return valueListByHazard.map( + ({ + hazard_type_display, + hazard_type, + riskCategory, + value, + }) => ( + + )} + spacing="sm" + > + + {selectedRiskMetric !== 'riskScore' && ( + + )} + + ), + ); +} + +export default TooltipContent; diff --git a/app/src/components/domain/RiskSeasonalMap/i18n.json b/app/src/components/domain/RiskSeasonalMap/i18n.json index 7f739720cd..3fed300e8c 100644 --- a/app/src/components/domain/RiskSeasonalMap/i18n.json +++ b/app/src/components/domain/RiskSeasonalMap/i18n.json @@ -10,13 +10,7 @@ "peopleExposedOptionLabel": "People Exposed", "peopleAtRiskOptionLabel": "People at Risk of Displacement", "riskScoreOptionLabel": "Risk Score", - "riskCategoryVeryLow": "Very Low", - "riskCategoryLow": "Low", - "riskCategoryMedium": "Medium", - "riskCategoryHigh": "High", - "riskCategoryVeryHigh": "Very High", "riskSeasonalMapHeading": "Risk Map", - "riskSeasonalCountriesByRiskHeading": "Countries by Risk", - "riskDataNotAvailable": "Data not available for selected filters" + "riskSeasonalCountriesByRiskHeading": "Countries by Risk" } -} \ No newline at end of file +} diff --git a/app/src/components/domain/RiskSeasonalMap/index.tsx b/app/src/components/domain/RiskSeasonalMap/index.tsx index 8dc8aaf47c..30c7158723 100644 --- a/app/src/components/domain/RiskSeasonalMap/index.tsx +++ b/app/src/components/domain/RiskSeasonalMap/index.tsx @@ -5,21 +5,18 @@ import { useState, } from 'react'; import { - BlockLoading, Container, + InlineLayout, LegendItem, - Message, + ListView, TextOutput, - Tooltip, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; import { - formatNumber, maxSafe, sumSafe, } from '@ifrc-go/ui/utils'; import { - _cs, compareNumber, isDefined, isFalsyString, @@ -37,16 +34,14 @@ import { } from 'mapbox-gl'; import GlobalMap, { type AdminZeroFeatureProperties } from '#components/domain/GlobalMap'; +import GoMapContainer from '#components/GoMapContainer'; +import GradientBar from '#components/GradientBar'; import Link from '#components/Link'; -import MapContainerWithDisclaimer from '#components/MapContainerWithDisclaimer'; import MapPopup from '#components/MapPopup'; import WikiLink from '#components/WikiLink'; import useCountry from '#hooks/domain/useCountry'; import useInputState from '#hooks/useInputState'; import { - CATEGORY_RISK_HIGH, - CATEGORY_RISK_LOW, - CATEGORY_RISK_MEDIUM, CATEGORY_RISK_VERY_HIGH, CATEGORY_RISK_VERY_LOW, COLOR_DARK_GREY, @@ -74,7 +69,9 @@ import { } from '#utils/domain/risk'; import { useRiskRequest } from '#utils/restRequest'; +import CountryListItem from './CountryListItem'; import Filters, { type FilterValue } from './Filters'; +import TooltipContent from './TooltipContent'; import i18n from './i18n.json'; import styles from './styles.module.css'; @@ -88,84 +85,6 @@ const defaultFilterValue: FilterValue = { includeCopingCapacity: false, }; -interface TooltipContentProps { - selectedRiskMetric: RiskMetric, - valueListByHazard: { - value: number; - riskCategory: number; - hazard_type: HazardType; - hazard_type_display: string | undefined; - }[]; -} - -function TooltipContent(props: TooltipContentProps) { - const { - selectedRiskMetric, - valueListByHazard, - } = props; - - const strings = useTranslation(i18n); - const riskCategoryToLabelMap: Record = useMemo( - () => ({ - [CATEGORY_RISK_VERY_LOW]: strings.riskCategoryVeryLow, - [CATEGORY_RISK_LOW]: strings.riskCategoryLow, - [CATEGORY_RISK_MEDIUM]: strings.riskCategoryMedium, - [CATEGORY_RISK_HIGH]: strings.riskCategoryHigh, - [CATEGORY_RISK_VERY_HIGH]: strings.riskCategoryVeryHigh, - }), - [ - strings.riskCategoryVeryLow, - strings.riskCategoryLow, - strings.riskCategoryMedium, - strings.riskCategoryHigh, - strings.riskCategoryVeryHigh, - ], - ); - - const riskMetricLabelMap: Record = { - riskScore: strings.riskScoreOptionLabel, - displacement: strings.peopleAtRiskOptionLabel, - exposure: strings.peopleExposedOptionLabel, - }; - - return valueListByHazard.map( - ({ - hazard_type_display, - hazard_type, - riskCategory, - value, - }) => ( - -
-
- )} - > - - {selectedRiskMetric !== 'riskScore' && ( - - )} -
- ), - ); -} - const RISK_LOW_COLOR = '#c7d3e0'; const RISK_HIGH_COLOR = '#f5333f'; @@ -797,8 +716,6 @@ function RiskSeasonalMap(props: Props) { [data, filters, mappings], ); - const MAX_RISK_SCORE = CATEGORY_RISK_VERY_HIGH; - // NOTE: we need to generate the layerOptions because we cannot use MapState // The id in the vector tile does not match the id in GO // We also cannot use promoteId as it is a non-managed mapbox source @@ -868,7 +785,7 @@ function RiskSeasonalMap(props: Props) { return ( )} - headerDescriptionContainerClassName={styles.headerDescription} headerDescription={( - <> +
{strings.seasonalEventsDescriptionOne}
{strings.seasonalEventsDescriptionTwo}
- +
)} - actions={( + headerActions={( )} - childrenContainerClassName={styles.mainContent} withHeaderBorder - footerClassName={styles.footer} - footerContent={( -
-
{strings.severityLegendLabel}
-
-
-
-
- {strings.severityLowLabel} -
-
- {strings.severityHighLabel} -
-
-
-
- )} - footerActionsContainerClassName={styles.footerActions} - footerActions={( -
-
- {strings.hazardsTypeLegendLabel} -
-
- {hazardTypeOptions.map((hazard) => ( - - ))} -
-
- )} - > - - - - {clickedPointProperties?.lngLat && riskPopupValue && ( - + - {clickedPointProperties.properties.name} - + + + )} - contentViewType="vertical" - childrenContainerClassName={styles.popupContent} - > - - - )} - - - {dataPending && } - {!dataPending && (isNotDefined(filteredData) || filteredData?.length === 0) && ( - - )} - {/* FIXME: use List */} - {!dataPending && filteredData?.map( - (dataItem) => { - const totalValuePercentage = 100 * dataItem.normalizedValue; - if (totalValuePercentage < 1) { - return null; - } - - const countryId = countryIso3ToIdMap[dataItem.country_details.iso3]; - - return ( -
+ {hazardTypeOptions.map((hazard) => ( + + ))} + + )} + /> + + )} + > + + + + + {clickedPointProperties?.lngLat && riskPopupValue && ( + - {dataItem.country_details.name} + {clickedPointProperties.properties.name} -
- {dataItem.valueListByHazard.map( - ({ - hazard_type, - riskCategory, - }) => { - // eslint-disable-next-line max-len - const percentage = (100 * riskCategory) / (MAX_RISK_SCORE * filters.hazardTypes.length); - - if (percentage < 1) { - return null; - } - - return ( -
- ); - }, - )} -
- - )} + )} + > + + -
- ); - }, - )} - +
+ + )} + + + + {filteredData?.map( + (dataItem) => { + const totalValuePercentage = 100 * dataItem.normalizedValue; + if (totalValuePercentage < 1) { + return null; + } + + const countryId = countryIso3ToIdMap[dataItem.country_details.iso3]; + + return ( + + ); + }, + )} + + + ); } diff --git a/app/src/components/domain/RiskSeasonalMap/styles.module.css b/app/src/components/domain/RiskSeasonalMap/styles.module.css index 99a601a476..033db3cfce 100644 --- a/app/src/components/domain/RiskSeasonalMap/styles.module.css +++ b/app/src/components/domain/RiskSeasonalMap/styles.module.css @@ -1,122 +1,3 @@ -.risk-seasonal-map-container { - display: flex; - flex-direction: column; - - .wiki-link { - font-size: var(--go-ui-font-size-3xl); - } - - .header-description { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-sm); - } - - .footer { - background-color: var(--go-ui-color-background); - padding: var(--go-ui-spacing-md); - } - - .footer-actions { - flex-shrink: unset; - } - - .legend-label { - font-size: var(--go-ui-font-size-sm); - font-weight: var(--go-ui-font-weight-medium); - } - - .severity-legend { - display: flex; - flex-wrap: wrap; - gap: var(--go-ui-spacing-xs) var(--go-ui-spacing-md); - - .legend-content { - .severity-gradient { - width: 10rem; - height: 0.5rem; - } - - .label-list { - display: flex; - justify-content: space-between; - font-size: var(--go-ui-font-size-xs); - font-weight: var(--go-ui-font-weight-medium); - } - } - } - - .type-of-hazard-legend { - display: flex; - flex-wrap: wrap; - gap: var(--go-ui-spacing-xs) var(--go-ui-spacing-md); - - .legend-content { - display: flex; - flex-wrap: wrap; - gap: var(--go-ui-spacing-xs) var(--go-ui-spacing-sm); - } - } - - .main-content { - display: flex; - height: 40rem; - gap: var(--go-ui-spacing-md); - - .map-container { - flex-grow: 1; - } - - .country-list { - flex-basis: calc(14vw + 16rem); - background-color: var(--go-ui-color-background); - - .content { - overflow: auto; - - .country { - .name { - font-size: var(--go-ui-font-size-sm); - } - - .track { - display: flex; - background-color: var(--go-ui-color-separator); - height: 0.5rem; - - .bar { - height: 100%; - } - } - } - } - } - - @media screen and (max-width: 50rem) { - flex-direction: column; - height: initial; - - .map-container { - height: min(40rem, 60vh); - } - - .country-list { - flex-basis: unset; - } - } - } -} - -.tooltip-hazard-indicator { - display: flex; - align-items: center; - width: 1rem; - height: 1.2rem; - - .color { - flex-shrink: 0; - border-radius: 0.3rem; - width: 0.6rem; - height: 0.6rem; - } +.country-list { + height: var(--go-ui-height-map-md); } diff --git a/app/src/components/domain/SeverityIndicator/index.tsx b/app/src/components/domain/SeverityIndicator/index.tsx index ee28d97762..753498c337 100644 --- a/app/src/components/domain/SeverityIndicator/index.tsx +++ b/app/src/components/domain/SeverityIndicator/index.tsx @@ -1,12 +1,10 @@ import { - _cs, - isNotDefined, -} from '@togglecorp/fujs'; + ColorPreview, + type ColorPreviewProps, +} from '@ifrc-go/ui'; +import { isNotDefined } from '@togglecorp/fujs'; -import styles from './styles.module.css'; - -interface Props { - className?: string; +interface Props extends Omit { level: number | undefined | null; title?: string; } @@ -15,26 +13,32 @@ function SeverityIndicator(props: Props) { const { level, title, - className, + ...otherProps } = props; - const classNameMap: Record = { - 0: styles.yellow, - 1: styles.orange, - 2: styles.red, + const colorMap: Record = { + 0: 'var(--go-ui-color-yellow)', + 1: 'var(--go-ui-color-orange)', + 2: 'var(--go-ui-color-red)', }; if (isNotDefined(level)) { return null; } + const value = colorMap[level]; + + if (isNotDefined(value)) { + return null; + } + return ( -
-
-
+ value={value} + /> ); } diff --git a/app/src/components/domain/SeverityIndicator/styles.module.css b/app/src/components/domain/SeverityIndicator/styles.module.css deleted file mode 100644 index eba10c1f46..0000000000 --- a/app/src/components/domain/SeverityIndicator/styles.module.css +++ /dev/null @@ -1,27 +0,0 @@ -.severity-indicator { - display: inline-flex; - align-items: center; - justify-content: center; - width: 1em; - height: 1.25em; - overflow: hidden; - line-height: 0; - - .icon { - border-radius: 1em; - width: 0.75em; - height: 0.75em; - - &.yellow { - background-color: var(--go-ui-color-yellow); - } - - &.red { - background-color: var(--go-ui-color-red); - } - - &.orange { - background-color: var(--go-ui-color-orange); - } - } -} diff --git a/app/src/components/domain/SourceInformationInput/index.tsx b/app/src/components/domain/SourceInformationInput/index.tsx index 8ee3a02713..f7a97f1eb7 100644 --- a/app/src/components/domain/SourceInformationInput/index.tsx +++ b/app/src/components/domain/SourceInformationInput/index.tsx @@ -107,7 +107,7 @@ function SourceInformationInput(props: Props) { className={styles.removeButton} name={index} onClick={onRemove} - variant="tertiary" + styleVariant="action" disabled={disabled} title={strings.sourceInformationDeleteButton} > diff --git a/app/src/components/domain/SurgeCardContainer/index.tsx b/app/src/components/domain/SurgeCardContainer/index.tsx index 9a91fe5203..8d23d53acc 100644 --- a/app/src/components/domain/SurgeCardContainer/index.tsx +++ b/app/src/components/domain/SurgeCardContainer/index.tsx @@ -1,6 +1,7 @@ -import { Container } from '@ifrc-go/ui'; - -import styles from './styles.module.css'; +import { + Container, + ListView, +} from '@ifrc-go/ui'; interface Props { heading: React.ReactNode; @@ -15,12 +16,17 @@ function SurgeCardContainer(props: Props) { return ( - {children} + + {children} + ); } diff --git a/app/src/components/domain/SurgeCardContainer/styles.module.css b/app/src/components/domain/SurgeCardContainer/styles.module.css deleted file mode 100644 index c5f3501a89..0000000000 --- a/app/src/components/domain/SurgeCardContainer/styles.module.css +++ /dev/null @@ -1,11 +0,0 @@ -.surge-card-container { - .content { - display: grid; - grid-gap: var(--go-ui-spacing-md); - grid-template-columns: repeat(auto-fill, minmax(20rem, 1fr)); - - @media screen and (max-width: 40rem) { - grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)); - } - } -} diff --git a/app/src/components/domain/SurgeCatalogueContainer/index.tsx b/app/src/components/domain/SurgeCatalogueContainer/index.tsx index 9ab0098c18..f91c1316a2 100644 --- a/app/src/components/domain/SurgeCatalogueContainer/index.tsx +++ b/app/src/components/domain/SurgeCatalogueContainer/index.tsx @@ -4,6 +4,7 @@ import { Button, Container, Image, + ListView, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; import { isDefined } from '@togglecorp/fujs'; @@ -13,7 +14,6 @@ import useRouting from '#hooks/useRouting'; import { type WrappedRoutes } from '../../../App/routes'; import i18n from './i18n.json'; -import styles from './styles.module.css'; interface ImageListItem { src: string; @@ -49,35 +49,43 @@ function SurgeCatalogueContainer(props: Props) { return ( + {description} + + )} filters={imageList?.map( (image) => ( ), )} - icons={isDefined(goBackFallbackLink) && ( + headerIcons={isDefined(goBackFallbackLink) && ( )} + spacing="lg" > - {children} + + {children} + ); } diff --git a/app/src/components/domain/SurgeCatalogueContainer/styles.module.css b/app/src/components/domain/SurgeCatalogueContainer/styles.module.css deleted file mode 100644 index 207636db28..0000000000 --- a/app/src/components/domain/SurgeCatalogueContainer/styles.module.css +++ /dev/null @@ -1,23 +0,0 @@ -.surge-catalogue-container { - .back-icon { - transform: scale(1.2); - font-size: var(--go-ui-font-size-2xl); - } - - .image { - height: 12rem; - } - - .description { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-sm); - } - - .content { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-xl); - padding: var(--go-ui-spacing-lg) 0; - } -} diff --git a/app/src/components/domain/SurgeContentContainer/index.tsx b/app/src/components/domain/SurgeContentContainer/index.tsx index 1017cef0c8..3673f79361 100644 --- a/app/src/components/domain/SurgeContentContainer/index.tsx +++ b/app/src/components/domain/SurgeContentContainer/index.tsx @@ -1,6 +1,7 @@ -import { Container } from '@ifrc-go/ui'; - -import styles from './styles.module.css'; +import { + Container, + ListView, +} from '@ifrc-go/ui'; interface Props { heading: React.ReactNode; @@ -15,12 +16,15 @@ function SurgeContentContainer(props: Props) { return ( - {children} + + {children} + ); } diff --git a/app/src/components/domain/SurgeContentContainer/styles.module.css b/app/src/components/domain/SurgeContentContainer/styles.module.css deleted file mode 100644 index b9d3f0dc83..0000000000 --- a/app/src/components/domain/SurgeContentContainer/styles.module.css +++ /dev/null @@ -1,7 +0,0 @@ -.surge-content-container { - .content { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-md); - } -} diff --git a/app/src/components/domain/ThreeWDecommissionMessage/index.tsx b/app/src/components/domain/ThreeWDecommissionMessage/index.tsx index 0e93644b0f..615634b0e1 100644 --- a/app/src/components/domain/ThreeWDecommissionMessage/index.tsx +++ b/app/src/components/domain/ThreeWDecommissionMessage/index.tsx @@ -1,4 +1,8 @@ -import { Container } from '@ifrc-go/ui'; +import { + Container, + Description, + ListView, +} from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; import { _cs } from '@togglecorp/fujs'; @@ -27,14 +31,17 @@ function ThreeWDecommissionMessage(props: Props) { heading={strings.pageHeading} mainSectionClassName={styles.threeWDecommissionPage} > - {strings.description} - - {strings.rationale} - + + + {strings.description} + + + {strings.rationale} + + ); } @@ -43,17 +50,19 @@ function ThreeWDecommissionMessage(props: Props) { - {strings.description} - - {strings.rationale} - + + + {strings.description} + + + {strings.rationale} + + ); } diff --git a/app/src/components/printable/Link/index.tsx b/app/src/components/printable/Link/index.tsx index 22cc331a78..83f9afe20d 100644 --- a/app/src/components/printable/Link/index.tsx +++ b/app/src/components/printable/Link/index.tsx @@ -7,7 +7,7 @@ import GoLink, { import styles from './styles.module.css'; -type Props = CommonLinkProps<'withUnderline'> & Omit; +type Props = Omit & Omit; function Link(props: Props) { const { diff --git a/app/src/declarations/eslintrc.d.ts b/app/src/declarations/eslintrc.d.ts new file mode 100644 index 0000000000..54dc1cbd7b --- /dev/null +++ b/app/src/declarations/eslintrc.d.ts @@ -0,0 +1 @@ +declare module '@eslint/eslintrc'; diff --git a/app/src/hooks/domain/useLink.ts b/app/src/hooks/domain/useLink.ts new file mode 100644 index 0000000000..61cf5782c9 --- /dev/null +++ b/app/src/hooks/domain/useLink.ts @@ -0,0 +1,67 @@ +import { useContext } from 'react'; +import { isNotDefined } from '@togglecorp/fujs'; + +import RouteContext from '#contexts/route'; +import useAuth from '#hooks/domain/useAuth'; +import usePermissions from '#hooks/domain/usePermissions'; +import { type WrappedRoutes } from '#routes'; +import { + resolvePath, + type UrlParams, +} from '#utils/domain/link'; + +interface ExternalLinkProps { + external: true, + href: string | undefined | null, + to?: never, + urlParams?: never, +} + +interface InternalLinkProps { + external: false | undefined, + to: keyof WrappedRoutes | undefined | null, + urlParams?: UrlParams, + href?: never, +} + +function useLink(props: InternalLinkProps | ExternalLinkProps) { + const { isAuthenticated } = useAuth(); + const routes = useContext(RouteContext); + const perms = usePermissions(); + + const { + external, + href, + to, + urlParams, + } = props; + + if (external) { + if (isNotDefined(href)) { + return { disabled: true, to: undefined }; + } + return { disabled: false, to: href }; + } + + if (isNotDefined(to)) { + return { disabled: true, to: undefined }; + } + + const route = resolvePath(to, routes, urlParams); + const { resolvedPath } = route; + + if (isNotDefined(resolvedPath)) { + return { disabled: true, to: undefined }; + } + + const disabled = (route.visibility === 'is-authenticated' && !isAuthenticated) + || (route.visibility === 'is-not-authenticated' && isAuthenticated) + || (route.permissions && !route.permissions(perms, urlParams)); + + return { + disabled, + to: resolvedPath, + }; +} + +export default useLink; diff --git a/app/src/hooks/useRouting.ts b/app/src/hooks/useRouting.ts index 477408e17d..f8829192e0 100644 --- a/app/src/hooks/useRouting.ts +++ b/app/src/hooks/useRouting.ts @@ -8,13 +8,12 @@ import { useNavigate, } from 'react-router-dom'; +import RouteContext from '#contexts/route'; +import { type WrappedRoutes } from '#routes'; import { resolvePath, type UrlParams, -} from '#components/Link'; -import RouteContext from '#contexts/route'; - -import { type WrappedRoutes } from '../App/routes'; +} from '#utils/domain/link'; function useRouting() { const location = useLocation(); diff --git a/app/src/index.css b/app/src/index.css index 1161db1ad5..7bd798a590 100644 --- a/app/src/index.css +++ b/app/src/index.css @@ -1,6 +1,21 @@ * { box-sizing: border-box; } +::-webkit-scrollbar { + transform: translateX(100%); + background-color: var(--go-ui-color-scrollbar-background); + width: var(--go-ui-width-scrollbar); + height: var(--go-ui-width-scrollbar); +} + +::-webkit-scrollbar-track { + background-color: var(--go-ui-color-scrollbar-background); +} + +::-webkit-scrollbar-thumb { + border-radius: var(--go-ui-radius-scrollbar-border); + background-color: var(--go-ui-color-scrollbar-foreground); +} html { @media screen { @@ -28,6 +43,22 @@ ul, ol, p { margin: 0; } +ul, ol { + padding-inline-start: var(--go-ui-spacing-lg); +} + +li { + margin: var(--go-ui-spacing-2xs) 0; + + &:first-child { + margin-top: unset; + } + + &:last-child { + margin-bottom: unset; + } +} + @media print { @page { size: portrait A4; diff --git a/app/src/utils/common.ts b/app/src/utils/common.ts index f387c4d06f..1f7c33e1f6 100644 --- a/app/src/utils/common.ts +++ b/app/src/utils/common.ts @@ -1,5 +1,8 @@ import { DEFAULT_INVALID_TEXT } from '@ifrc-go/ui/utils'; -import { isTruthyString } from '@togglecorp/fujs'; +import { + isNotDefined, + isTruthyString, +} from '@togglecorp/fujs'; import type { GoApiResponse } from '#utils/restRequest'; @@ -59,3 +62,22 @@ export function joinStrings( ): string { return values.filter(Boolean).join(separator); } + +export function hasChanged(prevValue: unknown, newValue: unknown) { + // NOTE: we consider `null` and `undefined` as same for + // this scenario + if (isNotDefined(prevValue) && isNotDefined(newValue)) { + return false; + } + + if (typeof newValue === 'string' + || typeof newValue === 'number' + || typeof newValue === 'boolean' + || typeof newValue === 'bigint' + ) { + return newValue !== prevValue; + } + + // TODO: add better method to check the diff + return JSON.stringify(prevValue) !== JSON.stringify(newValue); +} diff --git a/app/src/utils/domain/link.ts b/app/src/utils/domain/link.ts new file mode 100644 index 0000000000..0ec63e46ad --- /dev/null +++ b/app/src/utils/domain/link.ts @@ -0,0 +1,28 @@ +import { generatePath } from 'react-router-dom'; + +import { type WrappedRoutes } from '../../App/routes'; + +export interface UrlParams { + [key: string]: string | number | null | undefined; +} + +export function resolvePath( + to: keyof WrappedRoutes, + routes: WrappedRoutes, + urlParams: UrlParams | undefined, +) { + const route = routes[to]; + + try { + const resolvedPath = generatePath(route.absoluteForwardPath, urlParams); + return { + ...route, + resolvedPath, + }; + } catch { + return { + ...route, + resolvedPath: undefined, + }; + } +} diff --git a/app/src/views/Account/index.tsx b/app/src/views/Account/index.tsx index bf0ab653a6..158dc2f92e 100644 --- a/app/src/views/Account/index.tsx +++ b/app/src/views/Account/index.tsx @@ -24,7 +24,7 @@ export function Component() { title={strings.accountPageTitle} actions={( )} heading={ diff --git a/app/src/views/AccountDetails/ChangePassword/index.tsx b/app/src/views/AccountDetails/ChangePassword/index.tsx index 7e84bfb448..3f5150c95b 100644 --- a/app/src/views/AccountDetails/ChangePassword/index.tsx +++ b/app/src/views/AccountDetails/ChangePassword/index.tsx @@ -4,6 +4,7 @@ import { } from 'react'; import { Button, + ListView, Modal, TextInput, } from '@ifrc-go/ui'; @@ -29,7 +30,6 @@ import { import { transformObjectError } from '#utils/restRequest/error'; import i18n from './i18n.json'; -import styles from './styles.module.css'; type PasswordChangeRequestBody = GoApiBody<'/change_password', 'POST'>; @@ -157,15 +157,12 @@ function ChangePasswordModal(props: Props) { return ( + - + )} - childrenContainerClassName={styles.content} + withHeaderBorder + withFooterBorder > - - - - + + + + + + ); } diff --git a/app/src/views/AccountDetails/ChangePassword/styles.module.css b/app/src/views/AccountDetails/ChangePassword/styles.module.css deleted file mode 100644 index 3772c3ca33..0000000000 --- a/app/src/views/AccountDetails/ChangePassword/styles.module.css +++ /dev/null @@ -1,9 +0,0 @@ -.change-password { - background-color: var(--go-ui-color-gray-20); - - .content { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-xl); - } -} \ No newline at end of file diff --git a/app/src/views/AccountDetails/EditAccountInfo/index.tsx b/app/src/views/AccountDetails/EditAccountInfo/index.tsx index 4ec02eb815..db7909a992 100644 --- a/app/src/views/AccountDetails/EditAccountInfo/index.tsx +++ b/app/src/views/AccountDetails/EditAccountInfo/index.tsx @@ -4,6 +4,7 @@ import { } from 'react'; import { Button, + ListView, Modal, SelectInput, TextInput, @@ -38,7 +39,6 @@ import { import { transformObjectError } from '#utils/restRequest/error'; import i18n from './i18n.json'; -import styles from './styles.module.css'; type UserMeResponse = GoApiResponse<'/api/v2/user/me/'>; type AccountRequestBody = GoApiBody<'/api/v2/user/{id}/', 'PATCH'>; @@ -205,16 +205,15 @@ function EditAccountInfo(props: Props) { return ( + - + )} - childrenContainerClassName={styles.content} + withFooterBorder + withHeaderBorder > - - - - - - - {isNationalSociety ? ( + + + + + + + {isNationalSociety ? ( + + ) : ( + + )} + - ) : ( - )} - - - + + ); } diff --git a/app/src/views/AccountDetails/EditAccountInfo/styles.module.css b/app/src/views/AccountDetails/EditAccountInfo/styles.module.css deleted file mode 100644 index 396b8cad45..0000000000 --- a/app/src/views/AccountDetails/EditAccountInfo/styles.module.css +++ /dev/null @@ -1,17 +0,0 @@ -.edit-account-info { - .content { - display: grid; - grid-gap: var(--go-ui-spacing-xl); - grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr)); - background-color: var(--go-ui-color-white); - - .email-input { - grid-column: 1 / -1; - - } - - .non-field-error { - grid-column: 1 / -1; - } - } -} diff --git a/app/src/views/AccountDetails/GenerateMontandonTokenModal/index.tsx b/app/src/views/AccountDetails/GenerateMontandonTokenModal/index.tsx index 310aaa6ff9..a8488b638f 100644 --- a/app/src/views/AccountDetails/GenerateMontandonTokenModal/index.tsx +++ b/app/src/views/AccountDetails/GenerateMontandonTokenModal/index.tsx @@ -1,6 +1,7 @@ import { useCallback } from 'react'; import { Button, + ListView, Modal, TextInput, } from '@ifrc-go/ui'; @@ -78,6 +79,7 @@ function GenerateMontandonTokenModal(props: Props) { to="termsAndConditions" withLinkIcon withUnderline + spacing="xs" > {strings.termsAndConditionLabel} @@ -85,16 +87,13 @@ function GenerateMontandonTokenModal(props: Props) { }, )} size="sm" - contentViewType="vertical" - spacing="comfortable" footerActions={( - <> + {!accepted && ( <> @@ -103,6 +102,7 @@ function GenerateMontandonTokenModal(props: Props) { onClick={handleAcceptAndGenerateClick} disabled={isNotDefined(tokenTitle) || tokenTitle.trim().length < MIN_TITLE_LENGTH} + styleVariant="filled" > {strings.acceptButtonLabel} @@ -116,37 +116,41 @@ function GenerateMontandonTokenModal(props: Props) { {strings.doneButtonLabel} )} - + )} pending={tokenPending} errored={isDefined(tokenError)} errorMessage={tokenError?.value.messageForNotification} + withHeaderBorder + withFooterBorder > - {!accepted && ( - - )} - {accepted && ( - <> - + {!accepted && ( + -
- {strings.tokenNote} -
- - )} + )} + {accepted && ( + <> + +
+ {strings.tokenNote} +
+ + )} + ); } diff --git a/app/src/views/AccountDetails/TokenDetails/index.tsx b/app/src/views/AccountDetails/TokenDetails/index.tsx index 7e4510cf28..ac1bd32a4f 100644 --- a/app/src/views/AccountDetails/TokenDetails/index.tsx +++ b/app/src/views/AccountDetails/TokenDetails/index.tsx @@ -3,30 +3,23 @@ import { CopyLineIcon } from '@ifrc-go/icons'; import { Button, Container, + ListView, TextOutput, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; -import { - _cs, - isDefined, -} from '@togglecorp/fujs'; +import { isDefined } from '@togglecorp/fujs'; import useAlert from '#hooks/useAlert'; import { type GoApiResponse } from '#utils/restRequest'; import i18n from './i18n.json'; -import styles from './styles.module.css'; interface Props { - className?: string; data: GoApiResponse<'/api/v2/external-token/{id}/'> | undefined; } function TokenDetails(props: Props) { - const { - data, - className, - } = props; + const { data } = props; const alert = useAlert(); const strings = useTranslation(i18n); @@ -43,13 +36,12 @@ function TokenDetails(props: Props) { return ( @@ -57,27 +49,30 @@ function TokenDetails(props: Props) { )} headerDescription={( - <> + - + )} + withBackground + withPadding + withShadow > - {isDefined(data?.token) && ( -
- {data?.token} -
- )} + {isDefined(data?.token) && data?.token}
); } diff --git a/app/src/views/AccountDetails/TokenDetails/styles.module.css b/app/src/views/AccountDetails/TokenDetails/styles.module.css deleted file mode 100644 index b065950cf6..0000000000 --- a/app/src/views/AccountDetails/TokenDetails/styles.module.css +++ /dev/null @@ -1,15 +0,0 @@ -.token-details { - .token { - flex-grow: 1; - background-color: var(--go-ui-color-background); - padding: var(--go-ui-spacing-md); - overflow-wrap: break-word; - font-family: monospace; - } - - .created-at, - .expires-on { - color: var(--go-ui-color-text-light); - font-size: var(--go-ui-font-size-sm); - } -} diff --git a/app/src/views/AccountDetails/index.tsx b/app/src/views/AccountDetails/index.tsx index c11ea196e6..9fece6fc71 100644 --- a/app/src/views/AccountDetails/index.tsx +++ b/app/src/views/AccountDetails/index.tsx @@ -6,6 +6,7 @@ import { PencilFillIcon } from '@ifrc-go/icons'; import { Button, Container, + ListView, Pager, TextOutput, } from '@ifrc-go/ui'; @@ -21,6 +22,7 @@ import { } from '@togglecorp/fujs'; import Link from '#components/Link'; +import TabPage from '#components/TabPage'; import useGlobalEnums from '#hooks/domain/useGlobalEnums'; import useUserMe from '#hooks/domain/useUserMe'; import useFilterState from '#hooks/useFilterState'; @@ -32,7 +34,6 @@ import GenerateMontandonTokenModal from './GenerateMontandonTokenModal'; import TokenDetails from './TokenDetails'; import i18n from './i18n.json'; -import styles from './styles.module.css'; const TOKEN_PAGE_SIZE = 12; @@ -90,93 +91,94 @@ export function Component() { }); return ( -
+ )} - contentViewType="grid" - numPreferredGridContentColumns={3} > - - - - - - - - - + + + + + + + + + + + )} headingLevel={4} - actions={( + headerActions={( )} pending={montandonTokenPending} - contentViewType="grid" - numPreferredGridContentColumns={3} footerActions={isDefined(montandonTokenResponse) && isDefined(montandonTokenResponse.count) && ( @@ -217,19 +218,26 @@ export function Component() { /> )} overlayPending + withPadding + withDarkBackground > - {/* FIXME: use list */} - {montandonTokenResponse?.results?.map( - (tokenResponse, i) => ( - - ), - )} + + {/* FIXME: use list */} + {montandonTokenResponse?.results?.map( + (tokenResponse, i) => ( + + ), + )} + {showEditProfileModal && ( @@ -249,7 +257,7 @@ export function Component() { onCreate={refetchMontandonTokenList} /> )} -
+ ); } diff --git a/app/src/views/AccountDetails/styles.module.css b/app/src/views/AccountDetails/styles.module.css deleted file mode 100644 index cf5aaf5af0..0000000000 --- a/app/src/views/AccountDetails/styles.module.css +++ /dev/null @@ -1,11 +0,0 @@ -.account-information { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-2xl); - padding: var(--go-ui-spacing-2xl) 0; - - .token-details { - border: var(--go-ui-width-separator-thin) solid var(--go-ui-color-separator); - padding: var(--go-ui-spacing-sm); - } -} diff --git a/app/src/views/AccountMyFormsDref/ActiveDrefTable/index.tsx b/app/src/views/AccountMyFormsDref/ActiveDrefTable/index.tsx index 5e00c6747e..c5c0c7b6cf 100644 --- a/app/src/views/AccountMyFormsDref/ActiveDrefTable/index.tsx +++ b/app/src/views/AccountMyFormsDref/ActiveDrefTable/index.tsx @@ -359,7 +359,7 @@ function ActiveDrefTable(props: Props) { {strings.downloadButtonLabel} )} - contentViewType="vertical" - spacing="comfortable" onClose={onComplete} > - -
- {strings.description} -
+ + + + {strings.description} + + ); } diff --git a/app/src/views/AccountMyFormsDref/DrefTableActions/index.tsx b/app/src/views/AccountMyFormsDref/DrefTableActions/index.tsx index 8b16ad1f7f..02466ee697 100644 --- a/app/src/views/AccountMyFormsDref/DrefTableActions/index.tsx +++ b/app/src/views/AccountMyFormsDref/DrefTableActions/index.tsx @@ -406,7 +406,7 @@ function DrefTableActions(props: Props) { } + before={} confirmMessage={strings.drefAccountConfirmMessage} onConfirm={handlePublishClick} disabled={disabled} @@ -420,7 +420,7 @@ function DrefTableActions(props: Props) { name={undefined} type="button" onClick={handleDrefAllocationExport} - icons={} + before={} disabled={disabled} persist > @@ -431,7 +431,7 @@ function DrefTableActions(props: Props) { } + before={} confirmHeading={ strings.dropdownActionImminentNewOpsUpdateConfirmationHeading } @@ -449,7 +449,7 @@ function DrefTableActions(props: Props) { } + before={} onClick={handleAddOpsUpdate} disabled={disabled} persist @@ -462,7 +462,7 @@ function DrefTableActions(props: Props) { name={undefined} type="button" onClick={handleAddFinalReport} - icons={} + before={} disabled={disabled} persist > @@ -472,7 +472,7 @@ function DrefTableActions(props: Props) { } + before={} onClick={handleShareClick} disabled={disabled} persist @@ -483,7 +483,7 @@ function DrefTableActions(props: Props) { } + before={} onClick={handleExportClick} disabled={disabled} persist @@ -498,8 +498,10 @@ function DrefTableActions(props: Props) { } + colorVariant="primary" + styleVariant="outline" + before={} + spacing="sm" > {strings.dropdownActionEditLabel} @@ -508,8 +510,10 @@ function DrefTableActions(props: Props) { } + colorVariant="primary" + styleVariant="outline" + before={} + spacing="sm" > {strings.dropdownActionEditLabel} @@ -518,8 +522,10 @@ function DrefTableActions(props: Props) { } + colorVariant="primary" + styleVariant="outline" + before={} + spacing="sm" > {strings.dropdownActionEditLabel} diff --git a/app/src/views/AccountMyFormsDref/index.tsx b/app/src/views/AccountMyFormsDref/index.tsx index 4f4a188dd5..add3a5073a 100644 --- a/app/src/views/AccountMyFormsDref/index.tsx +++ b/app/src/views/AccountMyFormsDref/index.tsx @@ -26,7 +26,7 @@ export function Component() {
} + styleVariant="action" + after={} > {strings.showCompletedButtonLabel} @@ -57,8 +57,8 @@ export function Component() { diff --git a/app/src/views/AccountMyFormsFieldReport/index.tsx b/app/src/views/AccountMyFormsFieldReport/index.tsx index ace15b929a..cd391ed4e6 100644 --- a/app/src/views/AccountMyFormsFieldReport/index.tsx +++ b/app/src/views/AccountMyFormsFieldReport/index.tsx @@ -142,9 +142,8 @@ export function Component() { - + + @@ -37,7 +37,7 @@ export function Component() { -
+ ); } diff --git a/app/src/views/AccountMyFormsLayout/styles.module.css b/app/src/views/AccountMyFormsLayout/styles.module.css deleted file mode 100644 index 03ef579995..0000000000 --- a/app/src/views/AccountMyFormsLayout/styles.module.css +++ /dev/null @@ -1,6 +0,0 @@ -.account-my-forms-layout { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-2xl); - padding: var(--go-ui-spacing-2xl) 0; -} diff --git a/app/src/views/AccountMyFormsPer/PerTableActions/index.tsx b/app/src/views/AccountMyFormsPer/PerTableActions/index.tsx index 086ba4e02c..64af247391 100644 --- a/app/src/views/AccountMyFormsPer/PerTableActions/index.tsx +++ b/app/src/views/AccountMyFormsPer/PerTableActions/index.tsx @@ -117,7 +117,7 @@ function PerTableActions(props: Props) { type="link" to="perOverviewForm" urlParams={{ perId }} - icons={} + before={} > {resolveToString(strings.tableActionEditLabel, { phaseDisplay: phaseMap?.[PER_PHASE_OVERVIEW] ?? '--' })}
@@ -126,7 +126,7 @@ function PerTableActions(props: Props) { type="link" to="perOverviewForm" urlParams={{ perId }} - icons={} + before={} > {resolveToString(strings.tableActionViewLabel, { phaseDisplay: phaseMap?.[PER_PHASE_OVERVIEW] ?? '--' })}
diff --git a/app/src/views/AccountMyFormsPer/index.tsx b/app/src/views/AccountMyFormsPer/index.tsx index 2b2314852d..bff66981ad 100644 --- a/app/src/views/AccountMyFormsPer/index.tsx +++ b/app/src/views/AccountMyFormsPer/index.tsx @@ -222,16 +222,17 @@ export function Component() { className={styles.accountPerForms} heading={strings.processStatusTitle} withHeaderBorder - actions={( + headerActions={( <> {strings.newProcessButtonLabel} )} diff --git a/app/src/views/AccountMyFormsThreeW/ThreeWTableActions/index.tsx b/app/src/views/AccountMyFormsThreeW/ThreeWTableActions/index.tsx index d6f318dd3d..c160aeaa3b 100644 --- a/app/src/views/AccountMyFormsThreeW/ThreeWTableActions/index.tsx +++ b/app/src/views/AccountMyFormsThreeW/ThreeWTableActions/index.tsx @@ -38,7 +38,7 @@ function ThreeWTableActions(props: Props) { type="link" to="threeWActivityDetail" urlParams={{ activityId }} - icons={} + before={} > {strings.threeWViewDetails}
@@ -46,7 +46,7 @@ function ThreeWTableActions(props: Props) { type="link" to="threeWActivityEdit" urlParams={{ activityId }} - icons={} + before={} > {strings.threeWEdit}
@@ -54,7 +54,7 @@ function ThreeWTableActions(props: Props) { type="link" to="newThreeWActivity" state={{ activityId }} - icons={} + before={} > {strings.threeWDuplicate}
@@ -72,7 +72,7 @@ function ThreeWTableActions(props: Props) { type="link" to="threeWProjectDetail" urlParams={{ projectId }} - icons={} + before={} > {strings.threeWViewDetails} @@ -80,7 +80,7 @@ function ThreeWTableActions(props: Props) { type="link" to="threeWProjectEdit" urlParams={{ projectId }} - icons={} + before={} > {strings.threeWEdit} diff --git a/app/src/views/AccountMyFormsThreeW/index.tsx b/app/src/views/AccountMyFormsThreeW/index.tsx index 9db0d30665..0228a4aeec 100644 --- a/app/src/views/AccountMyFormsThreeW/index.tsx +++ b/app/src/views/AccountMyFormsThreeW/index.tsx @@ -248,7 +248,7 @@ export function Component(props: Props) { ['schemas']['ApiRegionNameEnum']; @@ -214,128 +214,135 @@ function SubscriptionPreferences() { return ( {strings.subscriptionUpdateButtonLabel} )} > - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + ); } diff --git a/app/src/views/AccountNotifications/SubscriptionPreferences/styles.module.css b/app/src/views/AccountNotifications/SubscriptionPreferences/styles.module.css deleted file mode 100644 index 7a387374d2..0000000000 --- a/app/src/views/AccountNotifications/SubscriptionPreferences/styles.module.css +++ /dev/null @@ -1,22 +0,0 @@ -.subscription-preferences { - .content { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-2xl); - - .notification-type-input-list-content { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-md); - } - - .other-notifications-list-content, - .surge-notifications-list-content, - .region-option-list-content, - .disaster-type-option-list-content { - display: grid; - grid-gap: var(--go-ui-spacing-md); - grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr)); - } - } -} diff --git a/app/src/views/AccountNotifications/index.tsx b/app/src/views/AccountNotifications/index.tsx index ec852fd0e4..bd7703cd3a 100644 --- a/app/src/views/AccountNotifications/index.tsx +++ b/app/src/views/AccountNotifications/index.tsx @@ -1,14 +1,19 @@ import { useCallback } from 'react'; import { Container, - List, + ListView, Pager, + RawList, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; import { numericIdSelector } from '@ifrc-go/ui/utils'; -import { isDefined } from '@togglecorp/fujs'; +import { + isDefined, + isNotDefined, +} from '@togglecorp/fujs'; import OperationListItem, { type Props as OperationListItemProps } from '#components/domain/OperationListItem'; +import TabPage from '#components/TabPage'; import useFilterState from '#hooks/useFilterState'; import { type GoApiResponse, @@ -56,12 +61,9 @@ export function Component() { ( _: number, operation: NonNullable[number], - i: number, - data: unknown[], ): OperationListItemProps => ({ eventItem: operation, updateSubscribedEvents: updateSubscribedEventsResponse, - isLastItem: i === (data.length - 1), }), [updateSubscribedEventsResponse], ); @@ -69,7 +71,7 @@ export function Component() { const eventList = subscribedEventsResponse?.results; return ( -
+ )} + pending={subscribedEventsResponsePending} + errored={isDefined(subscribedEventsResponseError)} + empty={isNotDefined(eventList) || eventList?.length === 0} > - + + + -
+ ); } diff --git a/app/src/views/ActiveSurgeDeployments/ActiveRapidResponseTable/index.tsx b/app/src/views/ActiveSurgeDeployments/ActiveRapidResponseTable/index.tsx index 245e3646f8..9b5946b920 100644 --- a/app/src/views/ActiveSurgeDeployments/ActiveRapidResponseTable/index.tsx +++ b/app/src/views/ActiveSurgeDeployments/ActiveRapidResponseTable/index.tsx @@ -189,7 +189,7 @@ function ActiveRapidResponseAlertsTable() { onActivePageChange={setPage} /> )} - actions={( + headerActions={( {emergencyName} )} - headerDescription={resolveToComponent( - strings.operationTimeline, - { - startDate: ( - - ), - duration, - }, + headerDescription={( + )} - icons={severityLevel ? ( + headerIcons={isDefined(severityLevel) && ( - ) : undefined} - childrenContainerClassName={styles.content} + )} + withPadding + withBackground + withShadow > - {deployedERUCount > 0 && ( - <> - -
- - + {deployedERUCount > 0 && ( + + + - )} - label={strings.surgeDeployingOrganizations} - strongValue - /> - - )} - {deployedERUCount > 0 && deployedPersonnelCount > 0 && ( -
- )} - {deployedPersonnelCount > 0 && ( - <> - -
- - + + )} + label={strings.surgeDeployingOrganizations} + strongValue + /> + + )} + {deployedPersonnelCount > 0 && deployedERUCount > 0 && ( +
+ )} + {deployedPersonnelCount > 0 && ( + + + - )} - label={strings.surgeDeployingOrganizations} - strongValue - /> - - )} + + + )} + label={strings.surgeDeployingOrganizations} + strongValue + /> + + )} + ); } diff --git a/app/src/views/ActiveSurgeDeployments/ActiveSurgeSupport/SurgeCard/styles.module.css b/app/src/views/ActiveSurgeDeployments/ActiveSurgeSupport/SurgeCard/styles.module.css index 7ff5069f5b..bf9f57dadd 100644 --- a/app/src/views/ActiveSurgeDeployments/ActiveSurgeSupport/SurgeCard/styles.module.css +++ b/app/src/views/ActiveSurgeDeployments/ActiveSurgeSupport/SurgeCard/styles.module.css @@ -1,7 +1,15 @@ +.separator { + border: unset; + border-top: var(--go-ui-width-separator-thin) solid var(--go-ui-color-separator); + width: 100%; +} + .surge-card { border-radius: var(--go-ui-border-radius-lg); box-shadow: var(--go-ui-box-shadow-md); + + .severity-indicator { font-size: var(--go-ui-font-size-xl); } @@ -11,15 +19,6 @@ grid-template-columns: 4fr var(--go-ui-width-separator-thin) 5fr; gap: var(--go-ui-spacing-md); - .figure { - padding: 0; - } - - .separator { - grid-column: span 3; - border-top: var(--go-ui-width-separator-thin) solid var(--go-ui-color-separator); - } - .vertical-separator { border-left: var(--go-ui-width-separator-thin) solid var(--go-ui-color-separator); } diff --git a/app/src/views/ActiveSurgeDeployments/ActiveSurgeSupport/index.tsx b/app/src/views/ActiveSurgeDeployments/ActiveSurgeSupport/index.tsx index 24367e64eb..7c4c9bfbb6 100644 --- a/app/src/views/ActiveSurgeDeployments/ActiveSurgeSupport/index.tsx +++ b/app/src/views/ActiveSurgeDeployments/ActiveSurgeSupport/index.tsx @@ -1,6 +1,7 @@ import { useCallback } from 'react'; import { Container, + ListView, Pager, RawList, } from '@ifrc-go/ui'; @@ -63,9 +64,6 @@ function ActiveSurgeSupport() { withHeaderBorder pending={aggregatedSurgePending} errored={isDefined(aggregatedSurgeResponseError)} - contentViewType="grid" - numPreferredGridContentColumns={3} - spacing="comfortable" footerActions={( )} > - + + + ); } diff --git a/app/src/views/ActiveSurgeDeployments/OngoingEruDeployments/index.tsx b/app/src/views/ActiveSurgeDeployments/OngoingEruDeployments/index.tsx index 86659c7047..6af32e0865 100644 --- a/app/src/views/ActiveSurgeDeployments/OngoingEruDeployments/index.tsx +++ b/app/src/views/ActiveSurgeDeployments/OngoingEruDeployments/index.tsx @@ -6,6 +6,7 @@ import { import { Container, LegendItem, + ListView, Pager, SelectInput, Table, @@ -137,6 +138,7 @@ function OngoingEruDeployments() { emergencyId: String(item.id), }, }), + { columnClassName: styles.name }, ), createStringColumn( 'organisation', @@ -181,6 +183,7 @@ function OngoingEruDeployments() { onClick: handleExpandClick, expanded: row.id === expandedRow?.id, }), + { columnClassName: styles.actions }, ), ]), [ @@ -278,7 +281,7 @@ function OngoingEruDeployments() { onActivePageChange={setPage} /> )} - actions={( + headerActions={( )} - footerContent={( - <> + footer={( + - + )} > diff --git a/app/src/views/ActiveSurgeDeployments/OngoingEruDeployments/styles.module.css b/app/src/views/ActiveSurgeDeployments/OngoingEruDeployments/styles.module.css index 7aabe0bc2d..05a8dce702 100644 --- a/app/src/views/ActiveSurgeDeployments/OngoingEruDeployments/styles.module.css +++ b/app/src/views/ActiveSurgeDeployments/OngoingEruDeployments/styles.module.css @@ -1,16 +1,26 @@ .ongoing-eru-deployments { .table { min-height: 5rem; + + .name { + width: 0%; + min-width: 12rem; + } + .organisation { - min-width: 10rem; + width: 11rem; } .country { - min-width: 10rem; + width: 10rem; } .timeline { - min-width: 24rem; + width: 22rem; + } + + .actions { + width: 3rem; } .sub-cell { diff --git a/app/src/views/ActiveSurgeDeployments/OngoingRapidResponseDeployments/index.tsx b/app/src/views/ActiveSurgeDeployments/OngoingRapidResponseDeployments/index.tsx index efcb01a5d3..aca479cf8f 100644 --- a/app/src/views/ActiveSurgeDeployments/OngoingRapidResponseDeployments/index.tsx +++ b/app/src/views/ActiveSurgeDeployments/OngoingRapidResponseDeployments/index.tsx @@ -6,6 +6,7 @@ import { import { Container, LegendItem, + ListView, Pager, Table, TableBodyContent, @@ -175,6 +176,7 @@ function OngoingRapidResponseDeployments() { onClick: handleExpandClick, expanded: row.id === expandedRow?.id, }), + { columnClassName: styles.actions }, ), ]), [ @@ -290,7 +292,7 @@ function OngoingRapidResponseDeployments() { onActivePageChange={setPage} /> )} - actions={( + headerActions={( )} - footerContent={( - <> + footer={( + - + )} > diff --git a/app/src/views/ActiveSurgeDeployments/OngoingRapidResponseDeployments/styles.module.css b/app/src/views/ActiveSurgeDeployments/OngoingRapidResponseDeployments/styles.module.css index 9f3a9a396f..3a8bd9cc3a 100644 --- a/app/src/views/ActiveSurgeDeployments/OngoingRapidResponseDeployments/styles.module.css +++ b/app/src/views/ActiveSurgeDeployments/OngoingRapidResponseDeployments/styles.module.css @@ -1,28 +1,33 @@ .rapid-response-deployments { .table { min-height: 5rem; + .name { - min-width: 8rem; + width: 0%; + min-width: 12rem; } .role { - min-width: 12rem; + width: 20rem; } .organisation { - min-width: 12rem; + width: 11rem; } .country { - min-width: 8rem; + width: 10rem; } .timeline { - width: 24rem; + width: 22rem; + } + + .actions { + width: 3rem; } .sub-cell { - border-bottom: unset; background-color: var(--go-ui-color-gray-20); } } diff --git a/app/src/views/ActiveSurgeDeployments/SurgeMap/index.tsx b/app/src/views/ActiveSurgeDeployments/SurgeMap/index.tsx index 32083d5814..7ea2a0fea3 100644 --- a/app/src/views/ActiveSurgeDeployments/SurgeMap/index.tsx +++ b/app/src/views/ActiveSurgeDeployments/SurgeMap/index.tsx @@ -7,6 +7,7 @@ import { Button, Container, LegendItem, + ListView, RadioInput, ReducedListDisplay, SelectInput, @@ -35,8 +36,8 @@ import { import DisplayName from '#components/DisplayName'; import DisasterTypeSelectInput from '#components/domain/DisasterTypeSelectInput'; import GlobalMap, { type AdminZeroFeatureProperties } from '#components/domain/GlobalMap'; +import GoMapContainer from '#components/GoMapContainer'; import Link from '#components/Link'; -import MapContainerWithDisclaimer from '#components/MapContainerWithDisclaimer'; import MapPopup from '#components/MapPopup'; import useCountryRaw from '#hooks/domain/useCountryRaw'; import useInputState from '#hooks/useInputState'; @@ -80,9 +81,7 @@ interface Props { } function SurgeMap(props: Props) { - const { - className, - } = props; + const { className } = props; const [ disasterFilter, @@ -351,7 +350,6 @@ function SurgeMap(props: Props) {
+ + )} /> )} - childrenContainerClassName={styles.popupContent} > {popupDetails?.eruDeployedEvents?.map( (event) => ( ( + - + ); } diff --git a/app/src/views/ActiveSurgeDeployments/styles.module.css b/app/src/views/ActiveSurgeDeployments/styles.module.css deleted file mode 100644 index 1083a2d851..0000000000 --- a/app/src/views/ActiveSurgeDeployments/styles.module.css +++ /dev/null @@ -1,11 +0,0 @@ -.active-surge-deployments { - display: flex; - flex-direction: column; - padding: var(--go-ui-spacing-2xl) 0; - - .content { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-2xl); - } -} diff --git a/app/src/views/AllAppeals/index.tsx b/app/src/views/AllAppeals/index.tsx index 652b24fd2f..12b33bc0f1 100644 --- a/app/src/views/AllAppeals/index.tsx +++ b/app/src/views/AllAppeals/index.tsx @@ -342,7 +342,6 @@ export function Component() { heading={heading} > )} - actions={( + headerActions={( )} - actions={( + headerActions={( )} - actions={( + headerActions={( )} - actions={( + headerActions={( } + before={} > {strings.flashUpdateViewDetails} @@ -36,7 +36,7 @@ function FlashUpdatesTableActions(props: Props) { type="link" to="flashUpdateFormEdit" urlParams={{ flashUpdateId }} - icons={} + before={} > {strings.flashUpdateEdit} diff --git a/app/src/views/AllFlashUpdates/index.tsx b/app/src/views/AllFlashUpdates/index.tsx index df874a1a20..40ddcdc8bd 100644 --- a/app/src/views/AllFlashUpdates/index.tsx +++ b/app/src/views/AllFlashUpdates/index.tsx @@ -144,7 +144,6 @@ export function Component() { > )} - actions={( + headerActions={( } + before={} > {strings.threeWActivityViewDetails} @@ -37,7 +37,7 @@ function AllThreeWActivityTableActions(props: Props) { type="link" to="threeWActivityEdit" urlParams={{ activityId }} - icons={} + before={} > {strings.threeWActivityEdit} @@ -45,7 +45,7 @@ function AllThreeWActivityTableActions(props: Props) { type="link" to="newThreeWActivity" state={{ activityId }} - icons={} + before={} > {strings.threeWActivityDuplicate} diff --git a/app/src/views/AllThreeWActivity/index.tsx b/app/src/views/AllThreeWActivity/index.tsx index 4acc5b02f8..85b637e320 100644 --- a/app/src/views/AllThreeWActivity/index.tsx +++ b/app/src/views/AllThreeWActivity/index.tsx @@ -300,7 +300,7 @@ export function Component() { heading={heading} > ('disclaimer'); - const disclaimerRef = useRef(null); - const useOfOurInformationRef = useRef(null); - const ourPrivacyPolicyRef = useRef(null); + const { hash: locationHash } = useLocation(); - const handleTabChange = (newTab: TitlesOptionKey) => { - setActiveTitleOption(newTab); + useEffect(() => { + if (isFalsyString(locationHash)) { + return; + } - const tabRefs = { - disclaimer: disclaimerRef, - 'use-of-our-information': useOfOurInformationRef, - 'our-privacy-policy': ourPrivacyPolicyRef, - }; - tabRefs[newTab]?.current?.scrollIntoView({ behavior: 'smooth' }); - }; + const element = document.getElementById(locationHash.substring(1)); + if (element) { + element.scrollIntoView({ + block: 'start', + behavior: 'smooth', + }); + } + }, [locationHash]); return ( - -
- + + + + {strings.disclaimerTitle} + + + {strings.useOfOurInformationTitle} + + + {strings.ourPrivacyPolicyHeading} + + + - - - {strings.disclaimerTitle} - - - {strings.useOfOurInformationTitle} - - - {strings.ourPrivacyPolicyHeading} - - - -
+ > + {strings.disclaimerDescription} + -
{strings.useOfOurInformationDescription1}
-
- { resolveToComponent( - strings.useOfOurInformationDescription2, - { - termsLink: ( - - {strings.useOfOurInformationAudiovisualLink} - - ), - }, - )} -
-
{strings.useOfOurInformationDescription3}
-
- - {strings.useOfOurInformationDescriptionLink} - -
- - )} withHeaderBorder - withInternalPadding - /> + > + +
{strings.useOfOurInformationDescription1}
+
+ { resolveToComponent( + strings.useOfOurInformationDescription2, + { + termsLink: ( + + {strings.useOfOurInformationAudiovisualLink} + + ), + }, + )} +
+
{strings.useOfOurInformationDescription3}
+
+ + {strings.useOfOurInformationDescriptionLink} + +
+
+
-
- {resolveToString(strings.ourPrivacyPolicyContent, { - publishedDay: 'November', - publishedDate: 29, - publishedYear: 2021, - })} -
- +
+ {resolveToString(strings.ourPrivacyPolicyContent, { + publishedDay: 'November', + publishedDate: 29, + publishedYear: 2021, + })} +
-
{strings.informationProvideDescription1}
-
{strings.informationProvideDescription2}
- - )} - /> - -
{strings.automaticallyCollectedDescription}
-
    -
  • {strings.automaticallyCollectedList1}
  • -
  • {strings.automaticallyCollectedList2}
  • -
  • {strings.automaticallyCollectedList3}
  • -
  • {strings.automaticallyCollectedList4}
  • -
  • {strings.automaticallyCollectedList5}
  • -
- - )} - /> + heading={strings.dataCollectedByAccessingHeading} + headingLevel={4} + > + + + +
{strings.informationProvideDescription1}
+
{strings.informationProvideDescription2}
+
+
+ + +
{strings.automaticallyCollectedDescription}
+
    +
  • {strings.automaticallyCollectedList1}
  • +
  • {strings.automaticallyCollectedList2}
  • +
  • {strings.automaticallyCollectedList3}
  • +
  • {strings.automaticallyCollectedList4}
  • +
  • {strings.automaticallyCollectedList5}
  • +
+
+
+ + +
+ {strings.ifrcLimitedCookiesAnalyticDescription} +
+
    +
  • {strings.ifrcLimitedCookiesAnalyticList1}
  • +
  • {strings.ifrcLimitedCookiesAnalyticList2}
  • +
  • {strings.ifrcLimitedCookiesAnalyticList3}
  • +
  • {strings.ifrcLimitedCookiesAnalyticList4}
  • +
+
+ {strings.ifrcLimitedCookiesAnalyticDescription2} +
+
+ {strings.ifrcLimitedCookiesAnalyticDescription3} +
+
+
+
+
-
{strings.ifrcLimitedCookiesAnalyticDescription}
-
    -
  • {strings.ifrcLimitedCookiesAnalyticList1}
  • -
  • {strings.ifrcLimitedCookiesAnalyticList2}
  • -
  • {strings.ifrcLimitedCookiesAnalyticList3}
  • -
  • {strings.ifrcLimitedCookiesAnalyticList4}
  • -
-
{strings.ifrcLimitedCookiesAnalyticDescription2}
-
{strings.ifrcLimitedCookiesAnalyticDescription3}
- - )} - /> -
- + heading={strings.howInformationUsedHeading} + headingLevel={4} + > +
{strings.howInformationUsedDescription}
  • {strings.howInformationUsedDescriptionList1}
  • @@ -193,33 +206,27 @@ export function Component() {
  • {strings.howInformationUsedDescriptionList5}
  • {strings.howInformationUsedDescriptionList6}
- - )} - /> - +
+
+ +
{strings.dataAccessSharingDescription1}
{strings.dataAccessSharingDescription2}
{strings.dataAccessSharingDescription3}
- - )} - /> - +
+
+ +
{strings.storageSecurityQuestionsDataDescription1}
{strings.storageSecurityQuestionsDataDescription2}
- { resolveToComponent( + {resolveToComponent( strings.storageSecurityQuestionsAboutDataDescription3, { termsLink: ( @@ -251,124 +258,125 @@ export function Component() { )}
{strings.storageSecurityQuestionsDataDescription5}
-
- - { resolveToComponent( - strings.storageSecurityQuestionsDataGoEnquires, - { - termsLink: ( - - im@ifrc.org - - ), - }, - )} - -
-
- - { resolveToComponent( - strings.storageSecurityQuestionsDataDonations, - { - termsLink: ( - - prd@ifrc.org - - ), - }, - )} - -
-
- - {resolveToComponent( - strings.storageSecurityQuestionsDataRecruitment, - { - termsLink: ( - - ask.hr@ifrc.org - - ), - }, - )} - -
-
- - { resolveToComponent( - strings.securityQuestionsWebpageCollection, - { - termsLink: ( - - webteam@ifrc.org - - ), - }, - )} - -
-
- - { resolveToComponent( - strings.storageSecurityQuestionsDataEnquires, - { - termsLink: ( - - dataprotection@ifrc.org - - ), - }, - )} - -
- - )} - /> - +
+ + { resolveToComponent( + strings.storageSecurityQuestionsDataGoEnquires, + { + termsLink: ( + + im@ifrc.org + + ), + }, + )} + +
+
+ + { resolveToComponent( + strings.storageSecurityQuestionsDataDonations, + { + termsLink: ( + + prd@ifrc.org + + ), + }, + )} + +
+
+ + {resolveToComponent( + strings.storageSecurityQuestionsDataRecruitment, + { + termsLink: ( + + ask.hr@ifrc.org + + ), + }, + )} + +
+
+ + { resolveToComponent( + strings.securityQuestionsWebpageCollection, + { + termsLink: ( + + webteam@ifrc.org + + ), + }, + )} + +
+
+ + { resolveToComponent( + strings.storageSecurityQuestionsDataEnquires, + { + termsLink: ( + + dataprotection@ifrc.org + + ), + }, + )} + +
+
+ +
+
{strings.privilegesAndImmunitiesDescription}
- )} - /> - + + +
{strings.noteOnLinksToExternalWebsitesDescription1}
{strings.noteOnLinksToExternalWebsitesDescription2}
- - )} - /> +
+
+
-
-
+ +
); } diff --git a/app/src/views/CookiePolicy/styles.module.css b/app/src/views/CookiePolicy/styles.module.css deleted file mode 100644 index f90892fa2f..0000000000 --- a/app/src/views/CookiePolicy/styles.module.css +++ /dev/null @@ -1,36 +0,0 @@ -.cookie-page { - display: flex; - gap: var(--go-ui-spacing-xl); - - .side-titles { - display: flex; - flex-direction: column; - flex-shrink: 0; - padding: var(--go-ui-spacing-sm); - gap: var(--go-ui-spacing-md); - } - - .header-description { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-md); - } - - .main-content { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-md); - - .first-level-content { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-md); - - .second-level-content { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-sm); - } - } - } -} diff --git a/app/src/views/Country/index.tsx b/app/src/views/Country/index.tsx index 863cba70ed..33b4ffcb68 100644 --- a/app/src/views/Country/index.tsx +++ b/app/src/views/Country/index.tsx @@ -41,7 +41,6 @@ import { resolveUrl } from '#utils/resolveUrl'; import { useRequest } from '#utils/restRequest'; import i18n from './i18n.json'; -import styles from './styles.module.css'; /** @knipignore */ // eslint-disable-next-line import/prefer-default-export @@ -115,7 +114,6 @@ export function Component() { return ( + @@ -140,7 +135,6 @@ export function Component() { return ( } + before={} + spacing="sm" + colorVariant="primary" + styleVariant="outline" > {strings.editCountryLink} diff --git a/app/src/views/Country/styles.module.css b/app/src/views/Country/styles.module.css deleted file mode 100644 index 4fa1c7428a..0000000000 --- a/app/src/views/Country/styles.module.css +++ /dev/null @@ -1,19 +0,0 @@ -.country { - .key-figure-list { - display: grid; - grid-gap: var(--go-ui-spacing-md); - grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr)); - - .key-figure { - border-radius: var(--go-ui-border-radius-lg); - background-color: var(--go-ui-color-white); - height: 100%; - } - } - - .links { - display: flex; - flex-wrap: wrap; - gap: var(--go-ui-spacing-md) var(--go-ui-spacing-lg); - } -} diff --git a/app/src/views/CountryAdditionalInfo/index.tsx b/app/src/views/CountryAdditionalInfo/index.tsx index b0b1c58a22..dc9dc51202 100644 --- a/app/src/views/CountryAdditionalInfo/index.tsx +++ b/app/src/views/CountryAdditionalInfo/index.tsx @@ -118,9 +118,9 @@ export function Component() { return ( )} > diff --git a/app/src/views/CountryNsOverview/index.tsx b/app/src/views/CountryNsOverview/index.tsx index 1e27d79f01..9e863a50bf 100644 --- a/app/src/views/CountryNsOverview/index.tsx +++ b/app/src/views/CountryNsOverview/index.tsx @@ -6,10 +6,10 @@ import { NavigationTabList } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; import NavigationTab from '#components/NavigationTab'; +import TabPage from '#components/TabPage'; import { type CountryOutletContext } from '#utils/outletContext'; import i18n from './i18n.json'; -import styles from './styles.module.css'; /** @knipignore */ // eslint-disable-next-line import/prefer-default-export @@ -19,8 +19,10 @@ export function Component() { const strings = useTranslation(i18n); return ( -
- + + -
+ ); } diff --git a/app/src/views/CountryNsOverview/styles.module.css b/app/src/views/CountryNsOverview/styles.module.css deleted file mode 100644 index fb3fbd759e..0000000000 --- a/app/src/views/CountryNsOverview/styles.module.css +++ /dev/null @@ -1,6 +0,0 @@ -.country-ns-overview { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-2xl); - padding: var(--go-ui-spacing-2xl) 0; -} diff --git a/app/src/views/CountryNsOverviewActivities/NationalSocietyDevelopmentInitiatives/InitiativeCard/index.tsx b/app/src/views/CountryNsOverviewActivities/NationalSocietyDevelopmentInitiatives/InitiativeCard/index.tsx index 08f73b0b4b..0570b1cd0e 100644 --- a/app/src/views/CountryNsOverviewActivities/NationalSocietyDevelopmentInitiatives/InitiativeCard/index.tsx +++ b/app/src/views/CountryNsOverviewActivities/NationalSocietyDevelopmentInitiatives/InitiativeCard/index.tsx @@ -1,16 +1,15 @@ import { Container, + ListView, NumberOutput, TextOutput, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; import { resolveToString } from '@ifrc-go/ui/utils'; -import { _cs } from '@togglecorp/fujs'; import { type GoApiResponse } from '#utils/restRequest'; import i18n from './i18n.json'; -import styles from './styles.module.css'; type CountryResponse = NonNullable> interface Props { @@ -28,10 +27,14 @@ function InitiativeCard(props: Props) { return ( )} + withBackground + withShadow + withPadding > - -
- - )} - description={strings.initiativeAllocationTitle} - strongValue - withoutLabelColon - /> + + + + )} + description={strings.initiativeAllocationTitle} + strongValue + withoutLabelColon + /> + ); } diff --git a/app/src/views/CountryNsOverviewActivities/NationalSocietyDevelopmentInitiatives/InitiativeCard/styles.module.css b/app/src/views/CountryNsOverviewActivities/NationalSocietyDevelopmentInitiatives/InitiativeCard/styles.module.css deleted file mode 100644 index db3eb0ebb6..0000000000 --- a/app/src/views/CountryNsOverviewActivities/NationalSocietyDevelopmentInitiatives/InitiativeCard/styles.module.css +++ /dev/null @@ -1,25 +0,0 @@ -.initiative-card { - border-radius: var(--go-ui-border-radius-lg); - box-shadow: var(--go-ui-box-shadow-md); - padding: var(--go-ui-spacing-md); - - .footer { - border-top: var(--go-ui-width-separator-sm) solid var(--go-ui-color-separator); - padding-top: var(--go-ui-spacing-sm); - } - - .content { - display: flex; - justify-content: space-between; - - .text-output { - display: block; - } - - .vertical-separator { - flex-shrink: 0; - border-left: var(--go-ui-width-separator-sm) solid var(--go-ui-color-separator); - } - - } -} diff --git a/app/src/views/CountryNsOverviewActivities/NationalSocietyDevelopmentInitiatives/index.tsx b/app/src/views/CountryNsOverviewActivities/NationalSocietyDevelopmentInitiatives/index.tsx index b8f00a985b..3c42dd51e1 100644 --- a/app/src/views/CountryNsOverviewActivities/NationalSocietyDevelopmentInitiatives/index.tsx +++ b/app/src/views/CountryNsOverviewActivities/NationalSocietyDevelopmentInitiatives/index.tsx @@ -2,6 +2,7 @@ import { useCallback } from 'react'; import { useOutletContext } from 'react-router-dom'; import { Container, + ListView, RawList, TextOutput, } from '@ifrc-go/ui'; @@ -25,7 +26,10 @@ const keySelector = (initiative: CountryInitiative) => initiative.id; function NationalSocietyDirectoryInitiatives() { const strings = useTranslation(i18n); - const { countryResponse } = useOutletContext(); + const { + countryResponse, + countryResponsePending, + } = useOutletContext(); const rendererParams = useCallback( (_: number, data: CountryInitiative) => ({ @@ -40,6 +44,9 @@ function NationalSocietyDirectoryInitiatives() { // TODO: Add Contacts link in description headerDescription={strings.nSDirectoryInitiativesDescription} withHeaderBorder + pending={countryResponsePending} + errored={false} + filtered={false} footerActions={isDefined(countryResponse) && isDefined(countryResponse.initiatives) && countryResponse.initiatives.length > 0 && ( @@ -47,28 +54,34 @@ function NationalSocietyDirectoryInitiatives() { label={strings.source} value={( {strings.ifrcNSDFunds} )} /> )} - contentViewType="grid" - numPreferredGridContentColumns={3} empty={isNotDefined(countryResponse) || isNotDefined(countryResponse.initiatives) || countryResponse.initiatives.length === 0} + spacing="lg" > - + + + ); } diff --git a/app/src/views/CountryNsOverviewActivities/index.tsx b/app/src/views/CountryNsOverviewActivities/index.tsx index 34f2dd0a37..da190640fd 100644 --- a/app/src/views/CountryNsOverviewActivities/index.tsx +++ b/app/src/views/CountryNsOverviewActivities/index.tsx @@ -1,6 +1,4 @@ -import { Container } from '@ifrc-go/ui'; - -import WikiLink from '#components/WikiLink'; +import TabPage from '#components/TabPage'; import NationalSocietyDevelopmentInitiatives from './NationalSocietyDevelopmentInitiatives'; @@ -8,18 +6,11 @@ import NationalSocietyDevelopmentInitiatives from './NationalSocietyDevelopmentI // eslint-disable-next-line import/prefer-default-export export function Component() { return ( - - )} - withCenteredHeaderDescription - contentViewType="vertical" - spacing="loose" + - + ); } diff --git a/app/src/views/CountryNsOverviewCapacity/CountryNsCapacityStrengthening/OCACListItem/index.tsx b/app/src/views/CountryNsOverviewCapacity/CountryNsCapacityStrengthening/OCACListItem/index.tsx index 9b9d8fdbde..c9047a32f7 100644 --- a/app/src/views/CountryNsOverviewCapacity/CountryNsCapacityStrengthening/OCACListItem/index.tsx +++ b/app/src/views/CountryNsOverviewCapacity/CountryNsCapacityStrengthening/OCACListItem/index.tsx @@ -1,13 +1,12 @@ import { Container, - DateOutput, + KeyFigure, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; import { type CountryOutletContext } from '#utils/outletContext'; import i18n from './i18n.json'; -import styles from './styles.module.css'; type CapacityItem = NonNullable['capacity']>[number]; @@ -24,24 +23,27 @@ function OCACListItem(props: Props) { return ( -
- -
- {strings.capacityListItemDateOfAssessment} -
-
+
); } diff --git a/app/src/views/CountryNsOverviewCapacity/CountryNsCapacityStrengthening/OCACListItem/styles.module.css b/app/src/views/CountryNsOverviewCapacity/CountryNsCapacityStrengthening/OCACListItem/styles.module.css deleted file mode 100644 index 11322fa5a0..0000000000 --- a/app/src/views/CountryNsOverviewCapacity/CountryNsCapacityStrengthening/OCACListItem/styles.module.css +++ /dev/null @@ -1,14 +0,0 @@ -.ocac-list-item { - border-radius: var(--go-ui-border-radius-md); - box-shadow: var(--go-ui-box-shadow-md); - - .ocac-detail { - display: flex; - flex-direction: column; - - .date { - font-size: var(--go-ui-font-size-3xl); - font-weight: var(--go-ui-font-weight-medium); - } - } -} diff --git a/app/src/views/CountryNsOverviewCapacity/CountryNsCapacityStrengthening/index.tsx b/app/src/views/CountryNsOverviewCapacity/CountryNsCapacityStrengthening/index.tsx index a902f7e814..268d27ecd4 100644 --- a/app/src/views/CountryNsOverviewCapacity/CountryNsCapacityStrengthening/index.tsx +++ b/app/src/views/CountryNsOverviewCapacity/CountryNsCapacityStrengthening/index.tsx @@ -3,6 +3,7 @@ import { useOutletContext } from 'react-router-dom'; import { Container, KeyFigure, + ListView, RawList, TextOutput, } from '@ifrc-go/ui'; @@ -19,7 +20,6 @@ import { type CountryOutletContext } from '#utils/outletContext'; import OCACListItem from './OCACListItem'; import i18n from './i18n.json'; -import styles from './styles.module.css'; type CapacityItem = NonNullable['capacity']>[number]; type AssessmentTypeEnum = components<'read'>['schemas']['AssessmentTypeEnum']; @@ -64,21 +64,19 @@ function CountryNsCapacityStrengthening() { return ( {strings.globalOCAC} @@ -87,28 +85,40 @@ function CountryNsCapacityStrengthening() { )} pending={countryResponsePending} empty={isEmpty} + errored={false} + filtered={false} > - - {hasBocaAssessments && ( - - - - )} + + + {hasBocaAssessments && ( + + + + )} + ); } diff --git a/app/src/views/CountryNsOverviewCapacity/CountryNsCapacityStrengthening/styles.module.css b/app/src/views/CountryNsOverviewCapacity/CountryNsCapacityStrengthening/styles.module.css deleted file mode 100644 index 44739c19ca..0000000000 --- a/app/src/views/CountryNsOverviewCapacity/CountryNsCapacityStrengthening/styles.module.css +++ /dev/null @@ -1,18 +0,0 @@ -.country-ns-capacity-strengthening { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-md); - - .empty-message { - grid-column: -1 / 1; - } - - .capacity-list-container { - display: flex; - } - - .capacity-item { - border-radius: var(--go-ui-border-radius-md); - box-shadow: var(--go-ui-box-shadow-md); - } -} diff --git a/app/src/views/CountryNsOverviewCapacity/index.tsx b/app/src/views/CountryNsOverviewCapacity/index.tsx index c2eda15695..a7e6135d5a 100644 --- a/app/src/views/CountryNsOverviewCapacity/index.tsx +++ b/app/src/views/CountryNsOverviewCapacity/index.tsx @@ -1,6 +1,7 @@ import { useOutletContext } from 'react-router-dom'; import { Container, + ListView, TextOutput, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; @@ -15,14 +16,13 @@ import { } from '@togglecorp/fujs'; import Link from '#components/Link'; -import WikiLink from '#components/WikiLink'; +import TabPage from '#components/TabPage'; import { type CountryOutletContext } from '#utils/outletContext'; import { useRequest } from '#utils/restRequest'; import CountryNsCapacityStrengthening from './CountryNsCapacityStrengthening'; import i18n from './i18n.json'; -import styles from './styles.module.css'; /** @knipignore */ // eslint-disable-next-line import/prefer-default-export @@ -48,28 +48,27 @@ export function Component() { && countryPerProcessStatusResponse.results.length > 0; return ( - + + {strings.nsOverviewCapacityLink} - - - )} - headerDescription={strings.nSOverviewCapacityDescription} - withCenteredHeaderDescription - contentViewType="vertical" - spacing="loose" - > + )} + headerDescription={strings.nSOverviewCapacityDescription} + withCenteredHeaderDescription + spacing="xl" + > + {null} + {/* Data is currently under review, it will be include in the next version */} {/* Hide this section */} {/* {countryResponse?.region === REGION_ASIA && ( @@ -80,13 +79,12 @@ export function Component() { heading={strings.nsPreparednessHeading} headerDescription={strings.nsPreparednessDescription} withHeaderBorder - contentViewType="grid" - numPreferredGridContentColumns={3} pending={countryPerProcessStatusPending} - actions={( + headerActions={( {strings.perStartPerProcess} @@ -96,9 +94,10 @@ export function Component() { label={strings.moreDetails} value={( {strings.perGlobalSummary} @@ -107,81 +106,85 @@ export function Component() { )} empty={!hasPer} > - {countryPerProcessStatusResponse?.results?.map( - (perProcess) => ( - + {countryPerProcessStatusResponse?.results?.map( + (perProcess) => ( + + {strings.perViewLink} + + )} + footer={( + + + + + )} + withFooterBorder + withPadding + withBackground + withShadow + > + - {strings.perViewLink} - - )} - footerContent={( - <> - - )} - withFooterBorder - > -
-
- {perProcess.phase_display} -
-
- {strings.perPhaseLabel} -
-
-
-
-
- {perProcess.date_of_assessment} -
-
- {strings.perAssessmentDateLabel} -
-
- - ), - )} + + + ), + )} + - + ); } diff --git a/app/src/views/CountryNsOverviewCapacity/styles.module.css b/app/src/views/CountryNsOverviewCapacity/styles.module.css deleted file mode 100644 index c8753dd22c..0000000000 --- a/app/src/views/CountryNsOverviewCapacity/styles.module.css +++ /dev/null @@ -1,36 +0,0 @@ -.ns-overview-capacity { - .per-cycle-item { - border-radius: var(--go-ui-border-radius-lg); - box-shadow: var(--go-ui-box-shadow-md); - - .figures { - display: flex; - gap: var(--go-ui-spacing-md); - - .phase-assessment-date-section { - flex-basis: 0; - flex-grow: 1; - - .phase-assessment-value { - font-weight: var(--go-ui-font-weight-bold); - } - - .phase-assessment-label { - color: var(--go-ui-color-text-light); - } - } - - .vertical-separator { - flex-shrink: 0; - border: var(--go-ui-width-separator-sm) solid var(--go-ui-color-separator); - width: 0; - } - - } - - .footer-figures { - display: flex; - flex-direction: column; - } - } -} diff --git a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyContacts/index.tsx b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyContacts/index.tsx index c2f9741258..c2a4cfc72c 100644 --- a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyContacts/index.tsx +++ b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyContacts/index.tsx @@ -60,7 +60,6 @@ function NationalSocietyContacts(props: Props) { return ( diff --git a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyDirectory/index.tsx b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyDirectory/index.tsx index 1c7ebf2208..05a3a96eb0 100644 --- a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyDirectory/index.tsx +++ b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyDirectory/index.tsx @@ -1,12 +1,12 @@ import { useOutletContext } from 'react-router-dom'; import { Container, - List, + ListView, + RawList, TextOutput, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; import { - _cs, isDefined, isTruthyString, } from '@togglecorp/fujs'; @@ -28,7 +28,7 @@ function NsDirectory(props: NsDirectoryProps) { const { directory } = props; return ( -
+
{[directory?.first_name, directory?.last_name].filter(isTruthyString).join(' ')}
@@ -48,12 +48,11 @@ function NationalSocietyDirectory(props: Props) { const strings = useTranslation(i18n); const { countryResponse } = useOutletContext(); - const directoryList = countryResponse?.directory; + const directoryList = countryResponse?.directory ?? []; return ( {countryResponse.society_name} )} /> )} + pending={false} + errored={false} + filtered={false} + empty={directoryList.length === 0} + withContentOverflow > - id} - renderer={NsDirectory} - rendererParams={(_, datum) => ({ directory: datum })} - /> + + id} + renderer={NsDirectory} + rendererParams={(_, datum) => ({ directory: datum })} + /> + ); } diff --git a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyDirectory/styles.module.css b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyDirectory/styles.module.css index 7019c44b37..5fe41e476d 100644 --- a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyDirectory/styles.module.css +++ b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyDirectory/styles.module.css @@ -1,23 +1,9 @@ -.national-society-directory { - overflow-y: auto; - - .content { - overflow-y: auto; - - .directory-list { - display: flex; - flex-direction: column; - gap: var(--go-ui-spacing-sm); - - .directory { - .full-name { - font-weight: var(--go-ui-font-weight-bold); - } +.ns-directory { + .full-name { + font-weight: var(--go-ui-font-weight-medium); + } - .position { - color: var(--go-ui-color-text-light); - } - } - } + .position { + color: var(--go-ui-color-text-light); } } diff --git a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyIncomeOverTime/index.tsx b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyIncomeOverTime/index.tsx index 9727c12126..62e5c62e2c 100644 --- a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyIncomeOverTime/index.tsx +++ b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyIncomeOverTime/index.tsx @@ -1,4 +1,7 @@ -import { useCallback } from 'react'; +import { + useCallback, + useMemo, +} from 'react'; import { useOutletContext } from 'react-router-dom'; import { ChartAxes, @@ -45,31 +48,33 @@ function NationalSocietyIncomeOverTime(props: Props) { const strings = useTranslation(i18n); const { countryResponse } = useOutletContext(); - const annualIncome = databankResponse?.fdrs_annual_income?.map( - (income) => { - const { - date, - value, - ...other - } = income; - - if (isNotDefined(date) || isNotDefined(value)) { - return undefined; - } - - const dateObj = new Date(date); - - if (Number.isNaN(dateObj.getTime())) { - return undefined; - } - - return { - ...other, - date: dateObj, - value, - }; - }, - ).filter(isDefined); + const annualIncome = useMemo(() => ( + databankResponse?.fdrs_annual_income?.map( + (income) => { + const { + date, + value, + ...other + } = income; + + if (isNotDefined(date) || isNotDefined(value)) { + return undefined; + } + + const dateObj = new Date(date); + + if (Number.isNaN(dateObj.getTime())) { + return undefined; + } + + return { + ...other, + date: dateObj, + value, + }; + }, + ).filter(isDefined) + ), [databankResponse?.fdrs_annual_income]); const incomeByYear = listToMap( annualIncome, @@ -125,6 +130,10 @@ function NationalSocietyIncomeOverTime(props: Props) { return ( {resolveToString( strings.sourceFDRSLabel, diff --git a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyIncomeSourceBreakdown/index.tsx b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyIncomeSourceBreakdown/index.tsx index 0e59f4dc52..79b4523a95 100644 --- a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyIncomeSourceBreakdown/index.tsx +++ b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyIncomeSourceBreakdown/index.tsx @@ -3,6 +3,7 @@ import { useOutletContext } from 'react-router-dom'; import { BarChart, Container, + ListView, TextOutput, } from '@ifrc-go/ui'; import { useTranslation } from '@ifrc-go/ui/hooks'; @@ -48,6 +49,7 @@ function NationalSocietyIncomeSourceBreakdown(props: Props) { const { response: countryIncomeResponse, pending: countryIncomeResponsePending, + error: countryIncomeResponseError, } = useRequest({ skip: isNotDefined(countryId), url: '/api/v2/country-income/', @@ -82,15 +84,16 @@ function NationalSocietyIncomeSourceBreakdown(props: Props) { withHeaderBorder footerActions={isDefined(countryResponse?.fdrs) && isDefined(countryResponse.society_name) && ( - <> + {resolveToString( strings.incomeSourceBreakdownSource, @@ -105,9 +108,11 @@ function NationalSocietyIncomeSourceBreakdown(props: Props) { value={selectedYear} strongValue /> - + )} pending={countryIncomeResponsePending} + filtered={false} + errored={isDefined(countryIncomeResponseError)} empty={isNotDefined(incomeListForSelectedYear) || incomeListForSelectedYear.length === 0} emptyMessage={strings.incomeSourceBreakdownNotAvailableMessage} diff --git a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyIndicators/index.tsx b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyIndicators/index.tsx index ae6fa10b4c..fa06a7e811 100644 --- a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyIndicators/index.tsx +++ b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyIndicators/index.tsx @@ -5,6 +5,7 @@ import { Container, Heading, InfoPopup, + ListView, Message, Modal, NumberOutput, @@ -248,29 +249,31 @@ function NationalSocietyIndicators(props: Props) { return ( {strings.goToFDRS} )} headingLevel={4} withHeaderBorder - contentViewType="grid" - numPreferredGridContentColumns={3} footerActions={isDefined(countryResponse?.fdrs) && isDefined(countryResponse.society_name) && ( )} > - - )} - strongValue - /> - } - strongValue - /> - - - {isDefined(totalVolunteerDisaggregation) && ( - - )} - - )} - /> - } - strongValue - /> - )} - valueType="number" - strongValue - /> - )} - valueType="number" - strongValue - /> - - - {isDefined(totalStaffDisaggregation) && ( - - )} - - )} - /> + + + )} + strongValue + /> + } + strongValue + /> + + + {isDefined(totalVolunteerDisaggregation) && ( + + )} + + )} + /> + } + strongValue + /> + )} + valueType="number" + strongValue + /> + )} + valueType="number" + strongValue + /> + + + {isDefined(totalStaffDisaggregation) && ( + + )} + + )} + /> + {showVolunteerDisaggregation && ( )} {isDefined(totalVolunteerDisaggregation) && ( -
+
), )} -
+ )} )} {showStaffDisaggregation && ( )} {isDefined(totalStaffDisaggregation) && ( -
+
), )} -
+ )} )} diff --git a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyIndicators/styles.module.css b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyIndicators/styles.module.css index b741a4804c..cc6fd34229 100644 --- a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyIndicators/styles.module.css +++ b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyIndicators/styles.module.css @@ -1,43 +1,25 @@ -.national-society-indicators { - .info-container { - display: flex; - gap: var(--go-ui-spacing-2xs); - - .disaggregation-icon { - font-size: var(--go-ui-height-icon-multiplier); - } - } -} - -.staff-list, -.volunteer-list { - display: flex; - flex-direction: column; +.staff, +.volunteer { + display: grid; + align-items: center; + grid-template-columns: 2rem 3fr 3rem 3fr 2rem; gap: var(--go-ui-spacing-md); - .staff, - .volunteer { - display: grid; - align-items: center; - grid-template-columns: 2rem 3fr 3rem 3fr 2rem; - gap: var(--go-ui-spacing-md); - - .male-label { - display: flex; - justify-content: flex-end; - } + .male-label { + display: flex; + justify-content: flex-end; + } - .male-disaggregation { - transform: scaleX(-1); - color: var(--go-ui-color-primary-blue); - } + .male-disaggregation { + transform: scaleX(-1); + color: var(--go-ui-color-primary-blue); + } - .label { - text-align: center; - } + .label { + text-align: center; + } - .female-disaggregation { - color: var(--go-ui-color-primary-red); - } + .female-disaggregation { + color: var(--go-ui-color-primary-red); } } diff --git a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyKeyDocuments/DocumentListCard/index.tsx b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyKeyDocuments/DocumentListCard/index.tsx index ebb5640495..0d7a3d3e7e 100644 --- a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyKeyDocuments/DocumentListCard/index.tsx +++ b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyKeyDocuments/DocumentListCard/index.tsx @@ -1,15 +1,11 @@ -import { useMemo } from 'react'; import { DownloadFillIcon } from '@ifrc-go/icons'; import { Container, - Table, + Description, + ListView, } from '@ifrc-go/ui'; -import { - createDateColumn, - createStringColumn, -} from '@ifrc-go/ui/utils'; -import { createLinkColumn } from '#utils/domain/tableHelpers'; +import Link from '#components/Link'; import { type GoApiResponse } from '#utils/restRequest'; import styles from './styles.module.css'; @@ -22,62 +18,61 @@ interface Props { documents: KeyDocumentItem[]; } -function documentKeySelector(document: KeyDocumentItem) { - return document.id; -} - function DocumentListCard(props: Props) { const { label, documents, } = props; - const columns = useMemo( - () => ([ - createStringColumn( - 'name', - '', - (item) => item.name, - ), - createDateColumn( - 'date', - '', - (item) => item.year, - { - columnClassName: styles.date, - }, - ), - createLinkColumn( - 'url', - '', - () => , - (item) => ({ - external: true, - href: item.url, - }), - ), - ]), - [ - ], - ); - return ( -
+ + {documents.map((document) => ( + + + + )} + headingLevel={5} + withEllipsizedHeading + spacing="xs" + withoutWrapInHeader + > + + {document.name} + + + ))} + ); } diff --git a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyKeyDocuments/DocumentListCard/styles.module.css b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyKeyDocuments/DocumentListCard/styles.module.css index 558798f56d..0230b976ef 100644 --- a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyKeyDocuments/DocumentListCard/styles.module.css +++ b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyKeyDocuments/DocumentListCard/styles.module.css @@ -1,17 +1,3 @@ .document-list-card { - border-radius: var(--go-ui-border-radius-sm); - box-shadow: var(--go-ui-box-shadow-md); - - .document { - .date { - width: 0%; - min-width: 9rem; - } - } - - .content { - max-height: 20rem; - overflow: auto; - } + max-height: 26rem; } - diff --git a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyKeyDocuments/index.tsx b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyKeyDocuments/index.tsx index c15b1b1b16..2c2249c888 100644 --- a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyKeyDocuments/index.tsx +++ b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyKeyDocuments/index.tsx @@ -4,6 +4,7 @@ import { SearchLineIcon } from '@ifrc-go/icons'; import { Container, DateInput, + ListView, RawList, TextInput, TextOutput, @@ -58,7 +59,7 @@ function NationalSocietyKeyDocuments() { filter: {}, }); const { - response: documentResponse, + response: documentsResponse, pending: documentResponsePending, error: documentResponseError, } = useRequest({ @@ -76,7 +77,7 @@ function NationalSocietyKeyDocuments() { const groupedDocumentsByType = ( listToGroupList( - documentResponse?.results, + documentsResponse?.results, (item) => item.document_type, (item) => item, ) @@ -127,10 +128,11 @@ function NationalSocietyKeyDocuments() { label={strings.source} value={( {resolveToString( strings.sourceFDRS, @@ -143,15 +145,19 @@ function NationalSocietyKeyDocuments() { pending={documentResponsePending} errored={isDefined(documentResponseError)} filtered={filtered} - contentViewType="grid" - numPreferredGridContentColumns={3} + empty={isNotDefined(documentsResponse) || documentsResponse.results.length === 0} > - + + + ); } diff --git a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/ConfigureLocalUnitsModal/ConfirmationModal/index.tsx b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/ConfigureLocalUnitsModal/ConfirmationModal/index.tsx index 3dcf88497a..ff26e57b89 100644 --- a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/ConfigureLocalUnitsModal/ConfirmationModal/index.tsx +++ b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/ConfigureLocalUnitsModal/ConfirmationModal/index.tsx @@ -131,7 +131,6 @@ function ConfirmationModal(props: Props) { diff --git a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/ConfigureLocalUnitsModal/index.tsx b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/ConfigureLocalUnitsModal/index.tsx index 5ecfe0fe8f..ef0c566dc7 100644 --- a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/ConfigureLocalUnitsModal/index.tsx +++ b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/ConfigureLocalUnitsModal/index.tsx @@ -140,12 +140,10 @@ function ConfigureLocalUnitsModal(props: Props) { )} onClose={onClose} withHeaderBorder - contentViewType="vertical" footerActions={( diff --git a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/Filters/index.tsx b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/Filters/index.tsx index d671df4d75..8b66047295 100644 --- a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/Filters/index.tsx +++ b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/Filters/index.tsx @@ -17,7 +17,6 @@ import { type GoApiResponse } from '#utils/restRequest'; import { type ValidationOption } from '../common'; import i18n from './i18n.json'; -import styles from './styles.module.css'; export interface FilterValue { search?: string | undefined; @@ -86,16 +85,13 @@ function Filters(props: Props) { onChange={onChange} icons={} /> -
- -
+ ); } diff --git a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/Filters/styles.module.css b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/Filters/styles.module.css deleted file mode 100644 index 8a6aeff431..0000000000 --- a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/Filters/styles.module.css +++ /dev/null @@ -1,4 +0,0 @@ -.actions { - display: flex; - align-items: flex-end; -} diff --git a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/LocalUnitDeleteModal/index.tsx b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/LocalUnitDeleteModal/index.tsx index afb70fab38..e3b363bf29 100644 --- a/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/LocalUnitDeleteModal/index.tsx +++ b/app/src/views/CountryNsOverviewContextAndStructure/NationalSocietyLocalUnits/LocalUnitDeleteModal/index.tsx @@ -4,6 +4,7 @@ import { } from 'react'; import { Button, + ListView, Modal, RadioInput, TextArea, @@ -28,7 +29,6 @@ import { } from '#utils/restRequest'; import i18n from './i18n.json'; -import styles from './styles.module.css'; type DeprecateReason = NonNullable[number]; @@ -149,7 +149,6 @@ function LocalUnitDeleteModal(props: Props) { { localUnitName }, )} withHeaderBorder - childrenContainerClassName={styles.localUnitDeleteFormContent} onClose={onClose} footerActions={(