From 012b85680468828d8cd9404d9469d93753fc125e Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Thu, 16 Jul 2026 09:35:33 -0700 Subject: [PATCH 1/5] LF-5380 Update CertificationsEmptyState to accept className prop --- .../components/Certifications/CertificationsEmptyState.tsx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/webapp/src/components/Certifications/CertificationsEmptyState.tsx b/packages/webapp/src/components/Certifications/CertificationsEmptyState.tsx index 3b3bfce786..1b757924ea 100644 --- a/packages/webapp/src/components/Certifications/CertificationsEmptyState.tsx +++ b/packages/webapp/src/components/Certifications/CertificationsEmptyState.tsx @@ -14,6 +14,7 @@ */ import { useTranslation } from 'react-i18next'; +import clsx from 'clsx'; import { ReactComponent as AwardIcon } from '../../assets/images/nav/certifications.svg'; import { ReactComponent as PlusCircleIcon } from '../../assets/images/plus-circle.svg'; import Button from '../Form/Button'; @@ -21,15 +22,17 @@ import styles from './index.module.scss'; interface CertificationsEmptyStateProps { onAddCertification: () => void; + className?: string; } export default function CertificationsEmptyState({ onAddCertification, + className, }: CertificationsEmptyStateProps) { const { t } = useTranslation(['translation', 'common']); return ( -
+

{t('CERTIFICATION.EMPTY_STATE.HEADING')}

{t('CERTIFICATION.EMPTY_STATE.BODY')}

From abb0c1ef4e119b8e97058b33e4919fea39f54db4 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Thu, 16 Jul 2026 10:13:50 -0700 Subject: [PATCH 2/5] LF-5380 Add MarketDirectoryCertifications component --- .../MarketDirectory/Certifications/index.tsx | 69 +++++++++++++++++++ .../Certifications/styles.module.scss | 24 +++++++ 2 files changed, 93 insertions(+) create mode 100644 packages/webapp/src/containers/Profile/FarmSettings/MarketDirectory/Certifications/index.tsx create mode 100644 packages/webapp/src/containers/Profile/FarmSettings/MarketDirectory/Certifications/styles.module.scss diff --git a/packages/webapp/src/containers/Profile/FarmSettings/MarketDirectory/Certifications/index.tsx b/packages/webapp/src/containers/Profile/FarmSettings/MarketDirectory/Certifications/index.tsx new file mode 100644 index 0000000000..0d6467712c --- /dev/null +++ b/packages/webapp/src/containers/Profile/FarmSettings/MarketDirectory/Certifications/index.tsx @@ -0,0 +1,69 @@ +/* + * Copyright 2026 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 . + */ + +import clsx from 'clsx'; +import { useHistory } from 'react-router-dom'; +import { useTranslation } from 'react-i18next'; +import { toCertificationItems } from '../../../../Certifications/utils'; +import CertificationsEmptyState from '../../../../../components/Certifications/CertificationsEmptyState'; +import CertificationCard, { + getCertificationStatus, +} from '../../../../../components/Certifications/CertificationCard'; +import { + Certification, + SupportedCertificationSystemType, + SupportedCertifier, +} from '../../../../../store/api/types'; +import certificationStyles from '../../../../../components/Certifications/index.module.scss'; +import styles from './styles.module.scss'; + +interface MarketDirectoryCertificationsProps { + certifications: Certification[]; + systemTypes: SupportedCertificationSystemType[]; + certifiers: SupportedCertifier[]; +} +export default function MarketDirectoryCertifications({ + certifications, + systemTypes, + certifiers, +}: MarketDirectoryCertificationsProps) { + const { t } = useTranslation('common'); + const history = useHistory(); + + const certificationItems = toCertificationItems(certifications, systemTypes, certifiers, t); + + // Only certifications that are actually publishable (active and not expired) belong on this read-only summary + const publishableCertifications = certificationItems.filter( + (cert) => + !['expired', 'pursuing'].includes(getCertificationStatus(cert.isActive, cert.expiryDate)), + ); + + return publishableCertifications.length === 0 ? ( + history.push('/certifications/add_certification')} + /> + ) : ( +
+ {publishableCertifications.map((cert) => ( + history.push(`/certifications/${cert.id}/edit_certification`)} + /> + ))} +
+ ); +} diff --git a/packages/webapp/src/containers/Profile/FarmSettings/MarketDirectory/Certifications/styles.module.scss b/packages/webapp/src/containers/Profile/FarmSettings/MarketDirectory/Certifications/styles.module.scss new file mode 100644 index 0000000000..8e1775f5f7 --- /dev/null +++ b/packages/webapp/src/containers/Profile/FarmSettings/MarketDirectory/Certifications/styles.module.scss @@ -0,0 +1,24 @@ +/* + * Copyright 2026 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 . + */ + +@use '@assets/mixin' as *; + +.emptyState { + box-shadow: none; +} + +.list { + padding: 32px 8px 16px 8px; +} From fe4b108fdb30e6d50ec2ab37f713ad3c9706ecc3 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Thu, 16 Jul 2026 10:14:56 -0700 Subject: [PATCH 3/5] LF-5380 Add MarketDirectoryCertifications to MarketDirectory --- .../FarmSettings/MarketDirectory/index.tsx | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/packages/webapp/src/containers/Profile/FarmSettings/MarketDirectory/index.tsx b/packages/webapp/src/containers/Profile/FarmSettings/MarketDirectory/index.tsx index 8b410b1179..87fc51c437 100644 --- a/packages/webapp/src/containers/Profile/FarmSettings/MarketDirectory/index.tsx +++ b/packages/webapp/src/containers/Profile/FarmSettings/MarketDirectory/index.tsx @@ -15,6 +15,7 @@ import { useEffect, useState } from 'react'; import { useHistory } from 'react-router-dom'; +import { useSelector } from 'react-redux'; import { useTranslation } from 'react-i18next'; import { TFunction } from 'i18next'; import clsx from 'clsx'; @@ -29,24 +30,35 @@ import { ReactComponent as CheckComplete } from '../../../../assets/images/check import { ReactComponent as CheckIncomplete } from '../../../../assets/images/check-incomplete.svg'; import MarketDirectoryInfoForm from './InfoForm'; import MarketDirectoryConsent from './Consent'; +import MarketDirectoryCertifications from './Certifications'; +import { loginSelector } from '../../../userFarmSlice'; import { useGetMarketDirectoryInfoQuery } from '../../../../store/api/marketDirectoryInfoApi'; import { useGetMarketProductCategoriesQuery } from '../../../../store/api/marketProductCategoryApi'; +import { useGetCertificationsQuery } from '../../../../store/api/certificationsApi'; +import { + useGetSupportedCertifiersQuery, + useGetSupportedCertificationSystemTypesQuery, +} from '../../../../store/api/certifiersApi'; // When adding/removing forms, update farmCardsLength below to match the number of enum values enum FormCards { INFO, + CERTIFICATIONS, } -const farmCardsLength = 1; +const farmCardsLength = 2; const MarketDirectory = () => { const history = useHistory(); const routerTabs = useFarmSettingsRouterTabs(); const { t } = useTranslation(); + const { farm_id } = useSelector(loginSelector); const { expandedIds, toggleExpanded, unExpand } = useExpandable({ isSingleExpandable: true }); - const [completionStatus, setCompletionStatus] = useState>>({}); + const [completionStatus, setCompletionStatus] = useState>>({ + [FormCards.CERTIFICATIONS]: true, + }); const updateCompletionStatus = (formKey: FormCards, isComplete: boolean) => { setCompletionStatus((prev) => ({ @@ -68,12 +80,23 @@ const MarketDirectory = () => { const { data: marketProductCategories = [], isLoading: isMarketProductCategoriesLoading } = useGetMarketProductCategoriesQuery(); + const { data: certifications = [], isLoading: isCertificationsLoading } = + useGetCertificationsQuery(); + const { data: certifiers = [], isLoading: isCertifiersLoading } = useGetSupportedCertifiersQuery( + farm_id!, + ); + const { data: systemTypes = [], isLoading: isSystemTypesLoading } = + useGetSupportedCertificationSystemTypesQuery(farm_id!); + const isMarketDirectoryDataLoading = [ isMarketDirectoryInfoLoading, isMarketProductCategoriesLoading, !marketProductCategories.length, ].some(Boolean); + const isCertificationDataLoading = + isCertificationsLoading || isCertifiersLoading || isSystemTypesLoading; + useEffect(() => { if (!isMarketDirectoryInfoLoading) { updateCompletionStatus(FormCards.INFO, !!marketDirectoryInfo); @@ -92,6 +115,17 @@ const MarketDirectory = () => { /> ), }, + { + key: FormCards.CERTIFICATIONS, + title: t('MENU.CERTIFICATIONS'), + content: !isCertificationDataLoading && ( + + ), + }, ]; return ( From 869cb337ef7918f4cafd110bbf01f0216393a871 Mon Sep 17 00:00:00 2001 From: Sayaka Ono Date: Thu, 16 Jul 2026 10:34:00 -0700 Subject: [PATCH 4/5] LF-5380 Adjust MarketDirectory styles --- .../FarmSettings/MarketDirectory/index.tsx | 48 ++++++++++--------- .../MarketDirectory/styles.module.scss | 7 +++ 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/packages/webapp/src/containers/Profile/FarmSettings/MarketDirectory/index.tsx b/packages/webapp/src/containers/Profile/FarmSettings/MarketDirectory/index.tsx index 87fc51c437..e912ca191a 100644 --- a/packages/webapp/src/containers/Profile/FarmSettings/MarketDirectory/index.tsx +++ b/packages/webapp/src/containers/Profile/FarmSettings/MarketDirectory/index.tsx @@ -135,29 +135,31 @@ const MarketDirectory = () => {
- {formCards.map(({ key, title, content }) => { - const isExpanded = expandedIds.includes(key); - - return ( -
- toggleExpanded(key)} - mainContent={ - - } - expandedContent={content} - leftCollapseIcon - iconClickOnly={false} - /> -
- ); - })} +
+ {formCards.map(({ key, title, content }) => { + const isExpanded = expandedIds.includes(key); + + return ( +
+ toggleExpanded(key)} + mainContent={ + + } + expandedContent={content} + leftCollapseIcon + iconClickOnly={false} + /> +
+ ); + })} +
{areAllFormsComplete !== undefined && ( Date: Thu, 16 Jul 2026 10:45:49 -0700 Subject: [PATCH 5/5] LF-5380 Remove unnecessary import --- .../MarketDirectory/Certifications/styles.module.scss | 2 -- 1 file changed, 2 deletions(-) diff --git a/packages/webapp/src/containers/Profile/FarmSettings/MarketDirectory/Certifications/styles.module.scss b/packages/webapp/src/containers/Profile/FarmSettings/MarketDirectory/Certifications/styles.module.scss index 8e1775f5f7..bd09559d46 100644 --- a/packages/webapp/src/containers/Profile/FarmSettings/MarketDirectory/Certifications/styles.module.scss +++ b/packages/webapp/src/containers/Profile/FarmSettings/MarketDirectory/Certifications/styles.module.scss @@ -13,8 +13,6 @@ * GNU General Public License for more details, see . */ -@use '@assets/mixin' as *; - .emptyState { box-shadow: none; }