Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

LF-4374 Badge component #3486

Open
wants to merge 6 commits into
base: integration
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions packages/webapp/public/locales/de/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1909,5 +1909,11 @@
},
"YEAR_SELECTOR": {
"TITLE": "Jahr auswählen"
},
"BADGE": {
"BETA": {
"TITLE": "MISSING",
"CONTENT": "MISSING"
}
}
}
6 changes: 6 additions & 0 deletions packages/webapp/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -2059,5 +2059,11 @@
},
"YEAR_SELECTOR": {
"TITLE": "Select Year"
},
"BADGE": {
"BETA": {
"TITLE": "Beta",
"CONTENT": "Beta version: A pre-release version for testing and feedback. We're excited to bring you a sneak peek of our new animals management feature, now in beta! As we embark on this beta journey together, your insights are more valuable than ever. While we've worked hard to bring you this feature, the road to perfection is paved with feedback - and sometimes, a few bumps! If you encounter any quirks or bugs, please let us know. Your reports are crucial in helping us refine and improve. Thank you for your patience and for being an integral part of our community's growth.You can learn more about beta <a href=\"#\">here</a>"
}
gursimran-singh marked this conversation as resolved.
Show resolved Hide resolved
}
}
6 changes: 6 additions & 0 deletions packages/webapp/public/locales/es/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -2066,5 +2066,11 @@
},
"YEAR_SELECTOR": {
"TITLE": "Seleccionar año"
},
"BADGE": {
"BETA": {
"TITLE": "MISSING",
"CONTENT": "MISSING"
}
}
}
6 changes: 6 additions & 0 deletions packages/webapp/public/locales/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -2065,5 +2065,11 @@
},
"YEAR_SELECTOR": {
"TITLE": "Selectionnez une année"
},
"BADGE": {
"BETA": {
"TITLE": "MISSING",
"CONTENT": "MISSING"
}
}
}
6 changes: 6 additions & 0 deletions packages/webapp/public/locales/hi/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1909,5 +1909,11 @@
},
"YEAR_SELECTOR": {
"TITLE": "वर्ष चुनें"
},
"BADGE": {
"BETA": {
"TITLE": "MISSING",
"CONTENT": "MISSING"
}
}
}
6 changes: 6 additions & 0 deletions packages/webapp/public/locales/ml/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1909,5 +1909,11 @@
},
"YEAR_SELECTOR": {
"TITLE": ""
},
"BADGE": {
"BETA": {
"TITLE": "MISSING",
"CONTENT": "MISSING"
}
}
}
6 changes: 6 additions & 0 deletions packages/webapp/public/locales/pa/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1909,5 +1909,11 @@
},
"YEAR_SELECTOR": {
"TITLE": "ਸਾਲ ਚੁਣੋ"
},
"BADGE": {
"BETA": {
"TITLE": "MISSING",
"CONTENT": "MISSING"
}
}
}
6 changes: 6 additions & 0 deletions packages/webapp/public/locales/pt/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -2065,5 +2065,11 @@
},
"YEAR_SELECTOR": {
"TITLE": "Selecione o ano"
},
"BADGE": {
"BETA": {
"TITLE": "MISSING",
"CONTENT": "MISSING"
}
}
}
113 changes: 113 additions & 0 deletions packages/webapp/src/components/Badge/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/*
* Copyright 2024 LiteFarm.org
* This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LiteFarm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details, see <https://www.gnu.org/licenses/>.
*/

import React, { useState } from 'react';
import { Tooltip, ClickAwayListener, IconButton, tooltipClasses } from '@mui/material';
import InfoOutlinedIcon from '@mui/icons-material/InfoOutlined';
import styles from './styles.module.scss';

// Define the Props
interface BadgeProps {
content?: string;
title: string;
showIcon?: boolean;
style?: React.CSSProperties;
}

const Badge: React.FC<BadgeProps> = ({ content = '', title, showIcon = true, style }) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We're aiming to avoid inline CSS, so could you please change the style prop to className instead? 🙏

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its good we are avoiding the inline css, i have seen a lot here. And sure, i will update accordingly.

const [open, setOpen] = useState<boolean>(false);
const [tooltipHover, setTooltipHover] = useState<boolean>(false);

const handleTooltipOpen = () => {
if (!tooltipHover) {
setOpen(true);
}
};
const handleTooltipClose = () => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could handleTooltipOpen + handleTooltipClose be combined by letting the state setter to use previous/pending value. React reference if useful

setOpen(prevState => !prevState)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That can be done if we want the button to behave like toggle(one click open tooltip and another closes it). Honestly speaking, i am little unclear about the behaviour of this component and that is why i came to the meeting to show you guys what i build. Got some feedback and changed accordingly. Even Antonella is not sure about the hover/click functionality for both mobile and desktop and told me that she would let me know after discussing with the team.

So, do let me know what should be the behaviour of this component for onHover and click, for both mobile and desktop and i will make changes accordingly

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Honestly its mostly fine the way you have it as an only onHover on desktop and onClick on mobile.

But specifically the style of the button on desktop should not change onClick on desktop though as shown in the first video... unless the full click behaviour opens the tooltip. So either we need to disable click styles on desktop, or add the full onClick open behaviour. I would personally approve either of those two options.

I will tag Loic on the Jira ticket to hopefully get you clarification on this though so you feel confident. Sorry about that lack of clarity -- please always feel free to tag Loic with your UI/UX questions on the Jira ticket too!

if (!tooltipHover) {
setOpen(false);
}
};
const handleTooltipContentHover = (hovering: boolean) => {
setTooltipHover(hovering);
setOpen(hovering);
};

const tooltipContent = (
<div
onClick={(e) => {
e.stopPropagation();
handleTooltipContentHover(true);
}}
onMouseEnter={() => handleTooltipContentHover(true)}
onMouseLeave={() => handleTooltipContentHover(false)}
Duncan-Brain marked this conversation as resolved.
Show resolved Hide resolved
className={styles.tooltip}
dangerouslySetInnerHTML={{ __html: content }}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain the reason behind this change? Instead of setting the link as HTML within the content string, I think we should keep this as is and set the content up as a React Node including the tag

Copy link
Collaborator Author

@gursimran-singh gursimran-singh Oct 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My intentions when developing the component was to make it reusable with different title and content in any other section. So, do not want to hard code anything in the component itself. I will change it to use <Trans> component from 'react-i18next' package(which i found later), is safer way to handle these situations and set the link when passing the content to the component.

Also, it would be nice if you can tell the link address, then i will update that as well.

/>
);
const slotProps = {
tooltip: {
sx: {
backgroundColor: '#fff',
p: 0,
m: 0,
},
},
popper: {
sx: {
[`&.${tooltipClasses.popper}[data-popper-placement*="bottom"] .${tooltipClasses.tooltip}`]:
{
marginTop: '2px',
},
},
},
};

return (
<ClickAwayListener onClickAway={handleTooltipClose}>
<Tooltip
title={tooltipContent}
open={open}
onClose={handleTooltipClose}
disableHoverListener={false} // Keep hover for desktop
disableFocusListener
disableTouchListener
enterTouchDelay={0}
placement="bottom-start"
slotProps={slotProps}
>
<IconButton
className={styles.badge}
style={{ ...style }}
onClick={(e) => {
if (showIcon) {
e.stopPropagation();
handleTooltipOpen();
}
}} // Toggle on click for both desktop and mobile
onMouseEnter={() => {
if (showIcon) {
handleTooltipOpen();
}
}} // Show on hover (desktop)
>
<span>{title}</span> {showIcon && <InfoOutlinedIcon />}
</IconButton>
</Tooltip>
</ClickAwayListener>
);
};

export default Badge;
73 changes: 73 additions & 0 deletions packages/webapp/src/components/Badge/styles.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright 2024 LiteFarm.org
* This file is part of LiteFarm.
*
* LiteFarm is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LiteFarm is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details, see <https://www.gnu.org/licenses/>.
*/

@import '../../assets/mixin.scss';

.tooltip {
color: #000;
border-radius: 4px;
font-size: 16px;
padding: 8px;
border: 1px solid var(--Colors-Neutral-Neutral-50);
box-shadow: 0px 4px 12px 0px #00000040;
z-index: 10;
}

.badge {
color: var(--Colors-Accent-Accent-yellow-600);
background: #fffbf2;
border-radius: 16px;
height: 24px;
font-size: 14px;
padding: 5px 4px 5px 6px;
> svg {
margin-left: 3px;
}
&:hover {
background: #ffeab2;
color: var(--Colors-Accent-Accent-yellow-700);
}
&:focus {
background: var(--Colors-Accent-Accent-yellow-500);
color: var(--Colors-Accent-Accent-yellow-50);
border-radius: 8px 8px 4px 4px !important;
}
}

:global(.hasBadge) .badge {
height: 12px;
font-size: 11px;
padding: 6px;
position: absolute;
left: 50px;
top: 8px;
border-radius: 16px;
&:focus,
&:hover {
color: var(--Colors-Accent-Accent-yellow-600);
background: #fffbf2;
border-radius: 16px !important;
}

@include xs-breakpoint {
height: 16px;
position: relative;
font-size: 14px;
top: initial;
left: initial;
padding: 6px;
margin-right: 6px;
}
}
Comment on lines +49 to +73
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be a bad idea to pass a className with these styles to the Badge component instead?
I've never seen a raw CSS className used here before, so it would be nice if we could keep things consistent!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is one of the way by which we can access the parent class in the child component. But, i will see these styles can be attained by passing class to the component and also avoiding the inline css.

Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ const SideMenuContent = ({ history, closeDrawer, isCompact, hasBeenExpanded }) =
<Logo alt={'logo'} />
</div>
</ListItemButton>
{mainActions.map(({ icon, label, path, subMenu, key }) => {
{mainActions.map(({ icon, label, path, subMenu, key, badge }) => {
if (!subMenu) {
return (
<MenuItem
Expand All @@ -115,6 +115,7 @@ const SideMenuContent = ({ history, closeDrawer, isCompact, hasBeenExpanded }) =
isCompact && styles.hiddenContent,
)}
/>
{!isCompact && badge}
</MenuItem>
);
}
Expand All @@ -126,6 +127,7 @@ const SideMenuContent = ({ history, closeDrawer, isCompact, hasBeenExpanded }) =
onClick={() => toggleExpanded(key)}
path={path}
ref={(el) => (expandableItemsRef.current[key] = el)}
className={badge && 'hasBadge'}
>
<ListItemIcon className={styles.icon}>{icon}</ListItemIcon>
<ListItemText
Expand All @@ -136,6 +138,7 @@ const SideMenuContent = ({ history, closeDrawer, isCompact, hasBeenExpanded }) =
isCompact && styles.hiddenContent,
)}
/>
{!isCompact && badge}
<ExpandMore
className={clsx(
styles.expandCollapseIcon,
Expand Down
21 changes: 17 additions & 4 deletions packages/webapp/src/components/Navigation/useSectionHeaders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,43 @@ import {
} from '../../util/siteMapConstants';
import { useTranslation } from 'react-i18next';
import type { Pathname } from 'history';
import Badge from '../Badge';
import React from 'react';

// Key value pair for path and its header
interface PathHeaderKVP {
[key: string]: string;
[key: string]: string | React.ReactElement;
}

/**
* Retrieves the translated section header based on the provided path.
*
* @param {Pathname} path - The pathname to match against specific sections.
* @returns {string | null} Returns the translated section header if the path matches a known section, otherwise returns null.
* @returns {string | React.ReactElement | null} Returns the translated section header if the path matches a known section, otherwise returns null.
*
* @example
* const currentPath = '/animals';
* const sectionHeader = useSectionHeader(currentPath);
* console.log(sectionHeader); // Output: 'Translated Animals Section Header'
*/

export function useSectionHeader(path: Pathname): string | null {
export function useSectionHeader(path: Pathname): string | React.ReactElement | null {
const { t } = useTranslation(['translation']);

const animalInventoryTitle = (
<>
{t('SECTION_HEADER.ANIMALS_INVENTORY')}
<Badge
style={{ marginLeft: '10px' }}
title={t('BADGE.BETA.TITLE')}
content={t('BADGE.BETA.CONTENT')}
/>
</>
);

const HEADERS_BY_PATH: PathHeaderKVP = {
[ANIMALS_GROUPS_URL]: t('SECTION_HEADER.ANIMALS_GROUPS'),
[ANIMALS_INVENTORY_URL]: t('SECTION_HEADER.ANIMALS_INVENTORY'),
[ANIMALS_INVENTORY_URL]: animalInventoryTitle,
[ANIMALS_LOCATION_URL]: t('SECTION_HEADER.ANIMALS_LOCATION'),
[ADD_ANIMALS_URL]: t('SECTION_HEADER.ANIMALS_INVENTORY'),
};
Expand Down
4 changes: 2 additions & 2 deletions packages/webapp/src/components/TileDashboard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
* GNU General Public License for more details, see <https://www.gnu.org/licenses/>.
*/

import { ReactNode, useRef } from 'react';
import React, { useRef } from 'react';
import clsx from 'clsx';
import styles from './styles.module.scss';
import { Title } from '../Typography';
Expand All @@ -35,7 +35,7 @@ export interface TypeCountTile {

export interface PureTileDashboardProps {
typeCountTiles: TypeCountTile[];
dashboardTitle: string;
dashboardTitle: string | React.ReactElement;
categoryLabel: string;
selectedFilterIds?: FilterId[];
}
Expand Down
Loading
Loading