Skip to content

Commit

Permalink
Merge pull request #3544 from LiteFarmOrg/LF-4375-spotlight-animals-a…
Browse files Browse the repository at this point in the history
…dd-animals-beta-spotlight

Lf 4375 spotlight animals add animals beta spotlight
  • Loading branch information
kathyavini authored Nov 26, 2024
2 parents 8dade36 + bdd242a commit 34490d0
Show file tree
Hide file tree
Showing 28 changed files with 301 additions and 84 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright (c) 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/>.
*/

export const up = async function (knex) {
await knex.schema.alterTable('showedSpotlight', (t) => {
t.boolean('animals_beta').defaultTo(false);
t.timestamp('animals_beta_end').nullable().defaultTo(null);
});
};

export const down = async function (knex) {
await knex.schema.alterTable('showedSpotlight', (t) => {
t.dropColumn('animals_beta');
t.dropColumn('animals_beta_end');
});
};
1 change: 1 addition & 0 deletions packages/api/src/controllers/showedSpotlightController.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const showedSpotlightController = {
'repeat_management_plan_creation',
'manage_custom_expense_type',
'manage_custom_revenue_type',
'animals_beta',
)
.findById(user_id);
res.status(200).send(data);
Expand Down
2 changes: 2 additions & 0 deletions packages/api/src/models/showedSpotlightModel.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ class ShowedSpotlight extends Model {
manage_custom_expense_type_end: { type: ['string', 'null'] },
manage_custom_revenue_type: { type: 'boolean' },
manage_custom_revenue_type_end: { type: ['string', 'null'] },
animals_beta: { type: 'boolean' },
animals_beta_end: { type: ['string', 'null'] },
},
};
}
Expand Down
2 changes: 1 addition & 1 deletion packages/webapp/public/locales/de/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1927,7 +1927,7 @@
"BADGE": {
"BETA": {
"TITLE": "MISSING",
"CONTENT": "MISSING"
"ANIMALS_CONTENT": "MISSING"
}
}
}
4 changes: 3 additions & 1 deletion packages/webapp/public/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -307,6 +307,7 @@
"WEANING_DATE": "Weaning date"
},
"BATCH": "Batch",
"BETA_SPOTLIGHT_HEADING": "Introducing the new Animals feature",
"EDIT_ANIMAL_FLOW": "editing",
"FILTER": {
"BATCHES": "Batches",
Expand Down Expand Up @@ -1052,6 +1053,7 @@
"ATTACHMENT_LABEL": "Upload screenshot or file",
"EMAIL": "Email",
"FEEDBACK_INVITATION": "Get help or give us feedback",
"SEND_US_FEEDBACK": "Send us feedback",
"MESSAGE_LABEL": "Message",
"OPTIONS": {
"OTHER": "Other",
Expand Down Expand Up @@ -2075,7 +2077,7 @@
"BADGE": {
"BETA": {
"TITLE": "Beta",
"CONTENT": "Get a sneak peek at our new animal management feature—now in beta! Your feedback is crucial as we refine this feature. Please share any bugs or suggestions you encounter. We appreciate your help in improving liteFarm! You can learn more about beta <a>here</a>"
"ANIMALS_CONTENT": "Get a sneak peek at our new animal management feature—now in beta! Your feedback is crucial as we refine this feature. Please share any bugs or suggestions you encounter. We appreciate your help in improving liteFarm! You can learn more about beta <a>here</a>"
}
}
}
2 changes: 1 addition & 1 deletion packages/webapp/public/locales/es/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -2081,7 +2081,7 @@
"BADGE": {
"BETA": {
"TITLE": "MISSING",
"CONTENT": "MISSING"
"ANIMALS_CONTENT": "MISSING"
}
}
}
2 changes: 1 addition & 1 deletion packages/webapp/public/locales/fr/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -2080,7 +2080,7 @@
"BADGE": {
"BETA": {
"TITLE": "MISSING",
"CONTENT": "MISSING"
"ANIMALS_CONTENT": "MISSING"
}
}
}
2 changes: 1 addition & 1 deletion packages/webapp/public/locales/hi/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1924,7 +1924,7 @@
"BADGE": {
"BETA": {
"TITLE": "MISSING",
"CONTENT": "MISSING"
"ANIMALS_CONTENT": "MISSING"
}
}
}
2 changes: 1 addition & 1 deletion packages/webapp/public/locales/ml/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1923,7 +1923,7 @@
"BADGE": {
"BETA": {
"TITLE": "MISSING",
"CONTENT": "MISSING"
"ANIMALS_CONTENT": "MISSING"
}
}
}
2 changes: 1 addition & 1 deletion packages/webapp/public/locales/pa/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -1924,7 +1924,7 @@
"BADGE": {
"BETA": {
"TITLE": "MISSING",
"CONTENT": "MISSING"
"ANIMALS_CONTENT": "MISSING"
}
}
}
2 changes: 1 addition & 1 deletion packages/webapp/public/locales/pt/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -2080,7 +2080,7 @@
"BADGE": {
"BETA": {
"TITLE": "MISSING",
"CONTENT": "MISSING"
"ANIMALS_CONTENT": "MISSING"
}
}
}
9 changes: 8 additions & 1 deletion packages/webapp/src/App.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { ANIMALS_INVENTORY_URL } from './util/siteMapConstants';

function App() {
const [isCompactSideMenu, setIsCompactSideMenu] = useState(false);
const [isFeedbackSurveyOpen, setFeedbackSurveyOpen] = useState(false);
const FULL_WIDTH_ROUTES = ['/map', ANIMALS_INVENTORY_URL];
const isFullWidth = FULL_WIDTH_ROUTES.some((path) => matchPath(history.location.pathname, path));

Expand All @@ -38,6 +39,8 @@ function App() {
history={history}
isCompactSideMenu={isCompactSideMenu}
setIsCompactSideMenu={setIsCompactSideMenu}
isFeedbackSurveyOpen={isFeedbackSurveyOpen}
setFeedbackSurveyOpen={setFeedbackSurveyOpen}
>
<div className={clsx(styles.app, isFullWidth && styles.fullWidthApp)}>
<OfflineDetector />
Expand All @@ -53,7 +56,11 @@ function App() {
// https://notistack.com/features/customization#custom-component
Components={{ common: NotistackSnackbar }}
>
<Routes isCompactSideMenu={isCompactSideMenu} />
<Routes
isCompactSideMenu={isCompactSideMenu}
isFeedbackSurveyOpen={isFeedbackSurveyOpen}
setFeedbackSurveyOpen={setFeedbackSurveyOpen}
/>
</SnackbarProvider>
</div>
</Navigation>
Expand Down
12 changes: 10 additions & 2 deletions packages/webapp/src/components/Badge/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,20 @@ export interface BadgeProps {
showIcon?: boolean;
isMenuItem?: boolean;
position?: 'left' | 'right';
id?: string;
classes?: {
iconButton: string;
};
}

const Badge: React.FC<BadgeProps> = ({
title,
content = '',
showIcon = true,
isMenuItem = false,
position = 'right',
position,
id,
classes,
}) => {
const [open, setOpen] = useState<boolean>(false);
const [focus, setFocus] = useState<boolean>(false);
Expand Down Expand Up @@ -90,11 +96,13 @@ const Badge: React.FC<BadgeProps> = ({
slotProps={slotProps}
>
<IconButton
id={id}
className={clsx(
styles.badge,
focus && styles.focus,
!isMenuItem && styles[position + 'Position'],
!isMenuItem && position && styles[position + 'Position'],
isMenuItem && styles.menuItem,
classes?.iconButton,
)}
onClick={(e) => {
if (showIcon) {
Expand Down
2 changes: 1 addition & 1 deletion packages/webapp/src/components/Form/Button/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import React, { ReactNode } from 'react';
import styles from './button.module.scss';
import clsx from 'clsx';

type ButtonProps = {
export type ButtonProps = {
color?: 'primary' | 'secondary' | 'secondary-2' | 'secondary-cta' | 'warning' | 'error' | 'none';
children?: ReactNode;
sm?: boolean;
Expand Down
15 changes: 13 additions & 2 deletions packages/webapp/src/components/Navigation/TopMenu/TopMenu.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,15 @@ import clsx from 'clsx';
import styles from './styles.module.scss';
import FeedbackSurvey from '../../../containers/FeedbackSurvey';

const TopMenu = ({ history, isMobile, showNavActions, onClickBurger, showNav }) => {
const TopMenu = ({
history,
isMobile,
showNavActions,
onClickBurger,
showNav,
isFeedbackSurveyOpen,
setFeedbackSurveyOpen,
}) => {
const { t } = useTranslation(['translation']);
const profileIconRef = useRef(null);
const selectedLanguage = getLanguageFromLocalStorage();
Expand Down Expand Up @@ -244,7 +252,10 @@ const TopMenu = ({ history, isMobile, showNavActions, onClickBurger, showNav })
>
<ProfilePicture />
</IconButton>
<FeedbackSurvey />
<FeedbackSurvey
isFeedbackSurveyOpen={isFeedbackSurveyOpen}
setFeedbackSurveyOpen={setFeedbackSurveyOpen}
/>
{isMobile ? drawerMenu : floaterMenu}
</>
);
Expand Down
4 changes: 4 additions & 0 deletions packages/webapp/src/components/Navigation/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export default function PureNavigation({
children,
isCompactSideMenu,
setIsCompactSideMenu,
isFeedbackSurveyOpen,
setFeedbackSurveyOpen,
}) {
// This namespacing is needed for translations to work throughout the app
const { t } = useTranslation([
Expand Down Expand Up @@ -80,6 +82,8 @@ export default function PureNavigation({
showNavActions={showNavActions}
onClickBurger={openSideMenu}
showNav={showNav}
isFeedbackSurveyOpen={isFeedbackSurveyOpen}
setFeedbackSurveyOpen={setFeedbackSurveyOpen}
/>
{children}
</div>
Expand Down
20 changes: 20 additions & 0 deletions packages/webapp/src/components/Navigation/styles.module.scss
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
* GNU General Public License for more details, see <https://www.gnu.org/licenses/>.
*/

@import '@assets/mixin.scss';

.mainColumn {
display: flex;
flex-direction: column;
Expand All @@ -23,3 +25,21 @@
overflow: clip;
min-width: 0;
}

.animalInventoryTitle {
display: flex;
flex-direction: row;
gap: 8px;
}

.badge {
@include xs-breakpoint {
order: 1;
}
}

.text {
@include xs-breakpoint {
order: 2;
}
}
13 changes: 9 additions & 4 deletions packages/webapp/src/components/Navigation/useSectionHeaders.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { useTranslation, Trans } from 'react-i18next';
import type { Pathname } from 'history';
import Badge from '../Badge';
import React from 'react';
import styles from './styles.module.scss';

// Key value pair for path and its header
interface PathHeaderKVP {
Expand All @@ -45,13 +46,17 @@ export function useSectionHeader(path: Pathname): string | React.ReactElement |
const { t } = useTranslation(['translation']);

const animalInventoryTitle = (
<>
{t('SECTION_HEADER.ANIMALS_INVENTORY')}
<div className={styles.animalInventoryTitle}>
<div className={styles.text}>{t('SECTION_HEADER.ANIMALS_INVENTORY')}</div>
<Badge
title={t('BADGE.BETA.TITLE')}
content={<Trans i18nKey={'BADGE.BETA.CONTENT'} components={{ a: <a href="#" /> }} />}
content={
<Trans i18nKey={'BADGE.BETA.ANIMALS_CONTENT'} components={{ a: <a href="#" /> }} />
}
id="animalsBeta"
classes={{ iconButton: styles.badge }}
/>
</>
</div>
);

const HEADERS_BY_PATH: PathHeaderKVP = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import React, { ReactNode, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { Label, Semibold } from '../Typography';
import { colors } from '../../assets/theme';
import Button from '../Form/Button';
import Button, { ButtonProps } from '../Form/Button';
import styles from './styles.module.scss';

const opositeSide = {
Expand Down Expand Up @@ -98,6 +98,7 @@ type TourContentBodyStep = {
isOrdered?: boolean;
list?: ReactNode[];
buttonText?: ReactNode;
buttonProps?: ButtonProps;
icon?: ReactNode;
onNext?(): void;
};
Expand All @@ -108,13 +109,15 @@ type TourProviderWrapperProps = ReactourChildrenWrapperProps &
Omit<ProviderProps, 'children' | 'steps'> & {
steps: Step[];
onFinish?(): void;
showCloseButton?: boolean;
};

export function TourProviderWrapper({
steps,
children = <div />,
open,
onFinish,
showCloseButton = false,
...props
}: TourProviderWrapperProps) {
if (!open) return children;
Expand Down Expand Up @@ -151,10 +154,14 @@ export function TourProviderWrapper({
}}
showBadge={false}
showNavigation={false}
showCloseButton={false}
showCloseButton={showCloseButton}
defaultOpen={open}
steps={processedSteps}
className={styles.popover}
onClickClose={({ setIsOpen }) => {
setIsOpen(false);
onFinish?.();
}}
{...props}
>
<ReactourChildrenWrapper open={open}>{children}</ReactourChildrenWrapper>
Expand Down Expand Up @@ -183,7 +190,7 @@ type TourContentBodyProps = {
};

export function TourContentBody({
step: { title, children, contents, isOrdered, list, buttonText, icon, onNext },
step: { title, children, contents, isOrdered, list, buttonText, buttonProps, icon, onNext },
continuous,
primaryProps,
isLastStep,
Expand All @@ -202,6 +209,7 @@ export function TourContentBody({
}
onNext?.();
};

return (
<>
{!!title && (
Expand Down Expand Up @@ -247,6 +255,7 @@ export function TourContentBody({
sm
id={continuous ? 'next' : 'close'}
{...primaryProps}
{...buttonProps}
>
{buttonText || (isLastStep ? t('common:GOT_IT') : t('common:NEXT'))}
</Button>
Expand Down
Loading

0 comments on commit 34490d0

Please sign in to comment.