-
-
Notifications
You must be signed in to change notification settings - Fork 28
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
Website: Enhance partners page #943
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
📝 WalkthroughWalkthroughThis pull request introduces significant updates to the handling of NGO data across multiple files. It enhances the structure and content of the JSON data for NGOs, adding new fields and detailed descriptions for several organizations. Additionally, new React components for displaying badges and partner information are introduced, while existing components are modified for improved layout and functionality. The changes also include the addition of a new page component for rendering individual NGO partner pages based on slugs. Changes
Possibly related PRs
Suggested labels
Suggested reviewers
Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
Visit the preview URL for this PR (updated for commit 1da2c29): https://si-admin-staging--pr943-pranav-enhance-partn-o2vj9sf7.web.app (expires Tue, 17 Dec 2024 17:59:35 GMT) 🔥 via Firebase Hosting GitHub Action 🌎 Sign: b7b0969384059dce6ea8fad1ee1d1737e54e6676 |
website/src/app/[lang]/[region]/(website)/partners/(components)/PartnerHome.tsx
Fixed
Show resolved
Hide resolved
@coderabbitai review |
✅ Actions performedReview triggered.
|
@coderabbitai review |
✅ Actions performedReview triggered.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Outside diff range and nitpick comments (6)
website/src/app/[lang]/[region]/(website)/partners/[slug]/page.tsx (1)
17-50
: Consider adding error boundary handling.While the implementation is solid, consider wrapping the component with an error boundary to gracefully handle runtime errors.
website/src/app/[lang]/[region]/(website)/partners/(sections)/ngolist.tsx (1)
33-38
: Use map instead of forEach for array transformation.Transform the array using map for a more functional approach.
-const ngoArray: NgoEntryJSON[] = []; -ngos.forEach((slug: string) => { - const ngo: NgoEntryJSON = translator.t(slug); - ngoArray.push(ngo); -}); +const ngoArray: NgoEntryJSON[] = ngos.map((slug: string) => translator.t(slug));website/src/app/[lang]/[region]/(website)/partners/(sections)/ngocard.tsx (2)
148-167
: Extract fundraiser section into a separate component.Consider extracting this section into a reusable component for better maintainability.
+type FundraiserSectionProps = { + orgFundRaiserText: Array<{href?: string, text: string}>; + fundRaiserTranslation: string; +}; + +const FundraiserSection = ({ orgFundRaiserText, fundRaiserTranslation }: FundraiserSectionProps) => ( + <div className="border-primary mb-8 flex items-center justify-start space-x-5 rounded-md border-2 border-opacity-80 py-4 pl-4"> + <FundraiserBadge fundRaiserTranslation={fundRaiserTranslation} /> + <span> + {orgFundRaiserText?.map((fragment, index) => ( + fragment.href ? ( + <Link href={fragment.href} key={index}> + <Typography as="span" size="md" color="primary" className="underline"> + {fragment.text} + </Typography> + </Link> + ) : ( + <Typography as="span" size="md" key={index}> + {fragment.text} + </Typography> + ) + ))} + </span> + </div> +);
Line range hint
218-287
: Extract repeated grid structure into a reusable component.The grid layout pattern is repeated multiple times. Consider extracting it into a reusable component.
+type InfoGridProps = { + label: string; + children: React.ReactNode; +}; + +const InfoGrid = ({ label, children }: InfoGridProps) => ( + <div className="grid grid-cols-3 gap-12 sm:gap-4"> + <div className="col-span-1"> + <Typography size="lg">{label}</Typography> + </div> + <div className="col-span-2"> + {children} + </div> + </div> +);website/src/app/[lang]/[region]/(website)/partners/(components)/PartnerHome.tsx (2)
11-17
: Improve type safety and error handling in flag mappingThe flag mapping implementation could be enhanced for better type safety and error handling.
-const country_abbreviations_to_flag_map: Record<string, ReactElement> = { +type CountryCode = 'SL' | 'CH'; +const country_abbreviations_to_flag_map: Record<CountryCode, ReactElement> = { SL: <SL className="h-5 w-5 rounded-full" />, CH: <CH className="h-5 w-5 rounded-full" />, }; -function getFlag(abbreviation: string): ReactElement { - return country_abbreviations_to_flag_map[abbreviation] || <SL className="h-5 w-5 rounded-full" />; +function getFlag(abbreviation: string): ReactElement { + if (abbreviation in country_abbreviations_to_flag_map) { + return country_abbreviations_to_flag_map[abbreviation as CountryCode]; + } + console.warn(`Unknown country code: ${abbreviation}`); + return <SL className="h-5 w-5 rounded-full" />; }
55-61
: Simplify boolean expression using Array.some()The boolean check for social media presence can be simplified.
-const showVisitOnline: boolean = !!( - ngoHoverCard.orgInstagram || - ngoHoverCard.orgFacebook || - ngoHoverCard.orgWebsite || - ngoHoverCard.orgLinkedIn || - ngoHoverCard.orgYoutube -); +const showVisitOnline = ['orgInstagram', 'orgFacebook', 'orgWebsite', 'orgLinkedIn', 'orgYoutube'] + .some(key => !!ngoHoverCard[key as keyof typeof ngoHoverCard]);
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (9)
shared/locales/de/website-partners.json
(1 hunks)shared/locales/en/website-partners.json
(1 hunks)shared/locales/fr/website-partners.json
(1 hunks)shared/locales/it/website-partners.json
(1 hunks)website/src/app/[lang]/[region]/(website)/partners/(components)/PartnerHome.tsx
(1 hunks)website/src/app/[lang]/[region]/(website)/partners/(sections)/ngocard.tsx
(9 hunks)website/src/app/[lang]/[region]/(website)/partners/(sections)/ngolist.tsx
(3 hunks)website/src/app/[lang]/[region]/(website)/partners/(types)/PartnerCards.ts
(1 hunks)website/src/app/[lang]/[region]/(website)/partners/[slug]/page.tsx
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- website/src/app/[lang]/[region]/(website)/partners/(types)/PartnerCards.ts
🔇 Additional comments (13)
website/src/app/[lang]/[region]/(website)/partners/[slug]/page.tsx (1)
1-15
: LGTM!
The imports and type definitions are well-structured.
website/src/app/[lang]/[region]/(website)/partners/(sections)/ngolist.tsx (1)
76-85
: LGTM!
The new properties are well-implemented with proper null handling.
website/src/app/[lang]/[region]/(website)/partners/(sections)/ngocard.tsx (2)
281-285
: URL construction with orgSlug needs input validation.
The code directly interpolates orgSlug into URLs without validation.
198-207
: 🛠️ Refactor suggestion
Enable image optimization for quote photos.
Remove the unoptimized
prop to enable Next.js image optimization features.
<Image
src={ngoHoverCard.quotePhoto}
alt={ngoHoverCard.quoteAuthor}
width="48"
height="48"
className="my-3 h-auto w-12"
- unoptimized
/>
Likely invalid or redundant comment.
website/src/app/[lang]/[region]/(website)/partners/(components)/PartnerHome.tsx (3)
68-75
: Fix width
and height
props in Image
component
The width
and height
props should be numbers without quotes.
140-140
: Correct the key
prop in the mapped elements
When mapping over paragraph
, the key
prop should use index2
instead of index
to ensure uniqueness within the nested loop.
242-246
:
Validate and sanitize the permalink URL
The URL construction should include proper validation and sanitization of the slug.
+const sanitizeSlug = (slug: string) => {
+ return encodeURIComponent(slug.replace(/[^a-zA-Z0-9-]/g, ''));
+};
+
<Link href={`https://socialincome.org/en/int/partners/${ngoHoverCard.orgSlug}`}>
<Typography size="lg" className="break-words underline">
- {`socialincome.org/partners/${ngoHoverCard.orgSlug}`}
+ {`socialincome.org/partners/${sanitizeSlug(ngoHoverCard.orgSlug)}`}
</Typography>
</Link>
Likely invalid or redundant comment.
shared/locales/en/website-partners.json (1)
Line range hint 1-329
: LGTM! Well-structured and comprehensive NGO data
The JSON structure is consistent and well-organized.
shared/locales/it/website-partners.json (1)
Line range hint 1-329
: LGTM! Well-structured and properly translated NGO data
The JSON structure and translations are consistent and accurate.
shared/locales/fr/website-partners.json (3)
31-33
: LGTM: Generic field translations are accurate.
The translations, including the new "fundraiser" field, are correctly implemented as per the provided translations.
36-42
: LGTM: NGO list is well-structured.
The list of NGO slugs is complete and matches the detailed entries below.
313-320
: Verify the fundraiser campaign link.
The fundraiser link for SLAES points to a campaign URL. Let's verify its accessibility.
✅ Verification successful
The fundraiser campaign link is valid but redirects to a localized URL
The link is accessible and redirects to /en/int/campaign/MZmXEVHlDjOOFOMk82jW
, which is the expected behavior for internationalized URLs.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify the fundraiser campaign URL accessibility
curl -I "https://socialincome.org/campaign/MZmXEVHlDjOOFOMk82jW"
Length of output: 672
shared/locales/de/website-partners.json (1)
31-33
: LGTM: Generic field translations are accurate.
The translations, including the new "fundraiser" field ("Spendenaktion"), are correctly implemented as per the provided translations.
function getNGOTranslation(translator: Translator, slug: string): NgoEntryJSON { | ||
return translator.t(slug); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add input validation for the slug parameter.
The function should validate the slug before passing it to the translator to prevent potential issues with invalid slugs.
function getNGOTranslation(translator: Translator, slug: string): NgoEntryJSON {
+ if (!slug || typeof slug !== 'string' || !/^[a-z0-9-]+$/.test(slug)) {
+ throw new Error('Invalid slug format');
+ }
return translator.t(slug);
}
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
function getNGOTranslation(translator: Translator, slug: string): NgoEntryJSON { | |
return translator.t(slug); | |
} | |
function getNGOTranslation(translator: Translator, slug: string): NgoEntryJSON { | |
if (!slug || typeof slug !== 'string' || !/^[a-z0-9-]+$/.test(slug)) { | |
throw new Error('Invalid slug format'); | |
} | |
return translator.t(slug); | |
} |
const recipientsBadge: RecipientsBadgeType = { | ||
hoverCardOrgName: currentNgo!['org-long-name'], | ||
hoverCardTotalRecipients: currentNgo!['recipients-total'], | ||
hoverCardTotalActiveRecipients: currentNgo!['recipients-active'], | ||
hoverCardTotalFormerRecipients: currentNgo!['recipients-former'], | ||
hoverCardTotalSuspendedRecipients: currentNgo!['recipients-suspend'], | ||
translatorBadgeRecipients: '', | ||
translatorBadgeRecipientsBy: '', | ||
translatorBadgeActive: '', | ||
translatorBadgeFormer: '', | ||
translatorBadgeSuspended: '', | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Replace non-null assertions with proper type checking
The extensive use of non-null assertions (!
) is risky and should be replaced with proper type checking.
const recipientsBadge: RecipientsBadgeType = {
- hoverCardOrgName: currentNgo!['org-long-name'],
- hoverCardTotalRecipients: currentNgo!['recipients-total'],
- hoverCardTotalActiveRecipients: currentNgo!['recipients-active'],
- hoverCardTotalFormerRecipients: currentNgo!['recipients-former'],
- hoverCardTotalSuspendedRecipients: currentNgo!['recipients-suspend'],
+ hoverCardOrgName: currentNgo?.['org-long-name'] ?? '',
+ hoverCardTotalRecipients: currentNgo?.['recipients-total'] ?? '0',
+ hoverCardTotalActiveRecipients: currentNgo?.['recipients-active'] ?? '0',
+ hoverCardTotalFormerRecipients: currentNgo?.['recipients-former'] ?? '0',
+ hoverCardTotalSuspendedRecipients: currentNgo?.['recipients-suspend'] ?? '0',
translatorBadgeRecipients: '',
translatorBadgeRecipientsBy: '',
translatorBadgeActive: '',
translatorBadgeFormer: '',
translatorBadgeSuspended: '',
};
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const recipientsBadge: RecipientsBadgeType = { | |
hoverCardOrgName: currentNgo!['org-long-name'], | |
hoverCardTotalRecipients: currentNgo!['recipients-total'], | |
hoverCardTotalActiveRecipients: currentNgo!['recipients-active'], | |
hoverCardTotalFormerRecipients: currentNgo!['recipients-former'], | |
hoverCardTotalSuspendedRecipients: currentNgo!['recipients-suspend'], | |
translatorBadgeRecipients: '', | |
translatorBadgeRecipientsBy: '', | |
translatorBadgeActive: '', | |
translatorBadgeFormer: '', | |
translatorBadgeSuspended: '', | |
}; | |
const recipientsBadge: RecipientsBadgeType = { | |
hoverCardOrgName: currentNgo?.['org-long-name'] ?? '', | |
hoverCardTotalRecipients: currentNgo?.['recipients-total'] ?? '0', | |
hoverCardTotalActiveRecipients: currentNgo?.['recipients-active'] ?? '0', | |
hoverCardTotalFormerRecipients: currentNgo?.['recipients-former'] ?? '0', | |
hoverCardTotalSuspendedRecipients: currentNgo?.['recipients-suspend'] ?? '0', | |
translatorBadgeRecipients: '', | |
translatorBadgeRecipientsBy: '', | |
translatorBadgeActive: '', | |
translatorBadgeFormer: '', | |
translatorBadgeSuspended: '', | |
}; |
website/src/app/[lang]/[region]/(website)/partners/(components)/PartnerHome.tsx
Outdated
Show resolved
Hide resolved
…to pranav/enhance-partners-page # Conflicts: # shared/locales/de/website-partners.json # shared/locales/en/website-partners.json # shared/locales/fr/website-partners.json # shared/locales/it/website-partners.json
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 4
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (7)
shared/locales/de/website-partners.json
(1 hunks)shared/locales/en/website-partners.json
(1 hunks)shared/locales/fr/website-partners.json
(1 hunks)shared/locales/it/website-partners.json
(1 hunks)website/src/app/[lang]/[region]/(website)/partners/(components)/PartnerHome.tsx
(1 hunks)website/src/app/[lang]/[region]/(website)/partners/(types)/PartnerCards.ts
(1 hunks)website/src/app/[lang]/[region]/(website)/partners/[slug]/page.tsx
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- website/src/app/[lang]/[region]/(website)/partners/(types)/PartnerCards.ts
🔇 Additional comments (8)
website/src/app/[lang]/[region]/(website)/partners/[slug]/page.tsx (1)
7-9
: Add input validation for the slug parameter.
The function should validate the slug before using it to prevent potential issues with invalid slugs.
website/src/app/[lang]/[region]/(website)/partners/(components)/PartnerHome.tsx (2)
20-54
: Replace non-null assertions with proper type checking.
Extensive use of non-null assertions (!
) should be replaced with optional chaining and nullish coalescing.
68-75
: Fix Image component props.
The width
and height
props should be numbers, not strings.
shared/locales/en/website-partners.json (1)
314-316
: Verify campaign URL integrity.
The campaign URL contains a hardcoded ID. Consider implementing a more secure way to handle campaign identifiers.
shared/locales/it/website-partners.json (3)
31-33
: LGTM! Translations are consistent.
The translations for the new fields match the previously approved translations.
36-42
: LGTM! NGO list structure is correct.
The NGO slugs are properly maintained and consistent across language files.
62-69
:
Fix duplicated text in Aurora Foundation description.
The link text "des projets culturels et de développement" appears to be duplicated in the description.
Apply this fix:
- "text": "La Fondation Aurora soutient des projets culturels et de développement "
- },
- {
- "text": "des projets culturels et de développement",
+ "text": "La Fondation Aurora soutient ",
+ },
+ {
+ "text": "des projets culturels et de développement",
Likely invalid or redundant comment.
shared/locales/fr/website-partners.json (1)
31-328
: LGTM! French translations are complete and accurate.
The structure is consistent with other language files, and translations are properly maintained.
permalink: translator.t('ngo-generic.permalink'), | ||
}; | ||
|
||
const currentNgo: NgoEntryJSON | undefined = getNGOTranslation(translator, slug.replaceAll('%26', '&')); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Verify URL encoding handling.
The replaceAll('%26', '&')
handles only one URL encoding case. Consider using decodeURIComponent
for comprehensive URL decoding.
-const currentNgo: NgoEntryJSON | undefined = getNGOTranslation(translator, slug.replaceAll('%26', '&'));
+const currentNgo: NgoEntryJSON | undefined = getNGOTranslation(translator, decodeURIComponent(slug));
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const currentNgo: NgoEntryJSON | undefined = getNGOTranslation(translator, slug.replaceAll('%26', '&')); | |
const currentNgo: NgoEntryJSON | undefined = getNGOTranslation(translator, decodeURIComponent(slug)); |
redirect('/not-found'); | ||
return; | ||
} | ||
const currentNgoCountry = translator.t(currentNgo!['org-country'] || 'SL'); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add null check before accessing currentNgo properties.
The non-null assertion (!
) after currentNgo
is unnecessary since we already check for its existence.
-const currentNgoCountry = translator.t(currentNgo!['org-country'] || 'SL');
+const currentNgoCountry = translator.t(currentNgo['org-country'] || 'SL');
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const currentNgoCountry = translator.t(currentNgo!['org-country'] || 'SL'); | |
const currentNgoCountry = translator.t(currentNgo['org-country'] || 'SL'); |
<Link href={`https://socialincome.org/en/int/partners/${ngoHoverCard.orgSlug}`}> | ||
<Typography size="lg" className="break-words underline"> | ||
{`socialincome.org/partners/${ngoHoverCard.orgSlug}`} | ||
</Typography> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Validate URL construction.
The hardcoded URL should be derived from environment variables to support different environments.
-<Link href={`https://socialincome.org/en/int/partners/${ngoHoverCard.orgSlug}`}>
+<Link href={`${process.env.NEXT_PUBLIC_BASE_URL}/en/int/partners/${ngoHoverCard.orgSlug}`}>
Committable suggestion skipped: line range outside the PR's diff.
[ | ||
{ | ||
"text": "im Kampf gegen Armut für die Schutzbedürftigen. ", | ||
"color": "accent" | ||
}, | ||
"text": "Die Mission ist es, die Benachteiligten und Schutzbedürftigen zu unterstützen und ihnen Wege zu einem besseren Leben zu bieten. Die Vision ist es, Einzelpersonen und Gemeinschaften zu stärken, den Kreislauf der Armut zu durchbrechen und benachteiligten Gruppen gleiche Chancen zu bieten." | ||
} | ||
] | ||
], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent paragraph count in Reachout Salone description.
The German translation contains an additional paragraph that's not present in other language versions. Please ensure consistency across all translations.
Consider either:
- Adding this paragraph to other language versions if it contains important information
- Removing it from the German translation to maintain consistency
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (2)
website/src/app/[lang]/[region]/(website)/transparency/evidence/section-card.tsx (1)
Line range hint
50-64
: LGTM! Typography implementation enhances text consistency.The implementation correctly handles both regular and linked text fragments while maintaining consistent typography styling throughout the component.
Consider extracting the fragment rendering logic into a separate component for better maintainability:
+const TextFragment = ({ fragment }: { fragment: { text: string; href?: string } }) => { + if (fragment.href) { + return ( + <Link href={fragment.href}> + <Typography as="span" color="primary">{fragment.text}</Typography> + </Link> + ); + } + return <Typography as="span">{fragment.text}</Typography>; +}; <Typography key={key} className="mt-2"> - {paragraph.map((fragment, key) => ( - <span key={key}> - {fragment.href ? ( - <Link href={fragment.href}> - <Typography as="span" color="primary"> - {fragment.text} - </Typography> - </Link> - ) : ( - <Typography as="span">{fragment.text}</Typography> - )} - </span> - ))} + {paragraph.map((fragment, key) => ( + <span key={key}> + <TextFragment fragment={fragment} /> + </span> + ))} </Typography>website/src/app/[lang]/[region]/(website)/partners/(sections)/ngocard.tsx (1)
199-208
: Add alt text optimization for quote photoWhile alt text is provided, it could be more descriptive.
<Image src={ngoHoverCard.quotePhoto} - alt={ngoHoverCard.quoteAuthor} + alt={`${ngoHoverCard.quoteAuthor} from ${orgShortName}`} width="48" height="48" className="my-3 h-auto w-12" />
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
📒 Files selected for processing (7)
ui/src/components/dialog.tsx
(1 hunks)website/src/app/[lang]/[region]/(website)/partners/(components)/PartnerHome.tsx
(1 hunks)website/src/app/[lang]/[region]/(website)/partners/(sections)/ngocard.tsx
(10 hunks)website/src/app/[lang]/[region]/(website)/partners/(sections)/ngolist.tsx
(5 hunks)website/src/app/[lang]/[region]/(website)/partners/(types)/PartnerCards.ts
(1 hunks)website/src/app/[lang]/[region]/(website)/partners/[slug]/page.tsx
(1 hunks)website/src/app/[lang]/[region]/(website)/transparency/evidence/section-card.tsx
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- ui/src/components/dialog.tsx
- website/src/app/[lang]/[region]/(website)/partners/(types)/PartnerCards.ts
👮 Files not reviewed due to content moderation or server errors (3)
- website/src/app/[lang]/[region]/(website)/partners/[slug]/page.tsx
- website/src/app/[lang]/[region]/(website)/partners/(sections)/ngolist.tsx
- website/src/app/[lang]/[region]/(website)/partners/(components)/PartnerHome.tsx
🔇 Additional comments (5)
website/src/app/[lang]/[region]/(website)/partners/(sections)/ngocard.tsx (5)
1-5
: LGTM: Clean import organization
The imports are well-organized and properly scoped from the new PartnerBadges
component.
53-54
: LGTM: Clear boolean flag
Good use of double negation operator for type coercion and null checking.
102-102
: LGTM: Conditional badge rendering
Clean conditional rendering of the fundraiser badge using the previously defined flag.
149-168
:
Validate fundraiser link URLs
The fundraiser section directly uses URLs from the data without validation.
Add URL validation before rendering:
{showFundRaiser && (
<div className="border-primary mb-8 flex items-center justify-start space-x-5 rounded-md border-2 border-opacity-80 py-4 pl-4">
<FundraiserBadge fundRaiserTranslation={translator.t('ngo-generic.fundraiser')} />
<span>
{ngoHoverCard.orgFundRaiserText?.map((fragment, index) => {
+ const isValidUrl = (url?: string) => {
+ if (!url) return false;
+ try {
+ new URL(url);
+ return true;
+ } catch {
+ return false;
+ }
+ };
return fragment.href ? (
+ isValidUrl(fragment.href) ? (
<Link href={fragment.href} key={index}>
<Typography as="span" size="md" color="primary" className="underline">
{fragment.text}
</Typography>
- </Link>
+ </Link>) : null
) : (
282-285
:
Validate and sanitize permalink URL construction
The permalink URL is constructed using user-provided data without validation.
Add validation before URL construction:
+ const isValidSlug = (slug: string) => /^[a-zA-Z0-9-]+$/.test(slug);
+ const safeSlug = isValidSlug(ngoHoverCard.orgSlug) ? ngoHoverCard.orgSlug : '';
- <Link href={`/${lang}/${region}/partners/${ngoHoverCard.orgSlug}`}>
+ <Link href={`/${lang}/${region}/partners/${safeSlug}`}>
<Typography size="lg" className="break-words underline">
- {`socialincome.org/partners/${ngoHoverCard.orgSlug}`}
+ {`socialincome.org/partners/${safeSlug}`}
</Typography>
</Link>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Looks good to me 🙌
I committed a few cleanups here: c53b670
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Documentation
Chores