-
-
Notifications
You must be signed in to change notification settings - Fork 32
feat(views): add pdf template for upcoming events | refactor current views directory #4294
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
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎
|
WalkthroughThis change introduces a comprehensive PDF export feature for upcoming events, adding new utility functions, React components, and type definitions to support PDF rendering. It refactors existing event logic to use new utilities, implements a custom export workflow, and standardizes icon and page component usage across the codebase. Several new icon components and a centralized export module for components are also included. Changes
Sequence Diagram(s)sequenceDiagram
participant User
participant ExportUpcomingEventsButton
participant useExportUpcomingEvents
participant PDFGenerator (TemplateUpcomingEvents)
participant FileSaver
User->>ExportUpcomingEventsButton: Click "Export" button
ExportUpcomingEventsButton->>useExportUpcomingEvents: handleExport()
useExportUpcomingEvents->>useExportUpcomingEvents: Set isProcessing=true
useExportUpcomingEvents->>useExportUpcomingEvents: Gather and format event data
useExportUpcomingEvents->>PDFGenerator: Generate PDF blob with events
PDFGenerator-->>useExportUpcomingEvents: Return PDF blob
useExportUpcomingEvents->>FileSaver: Save PDF to device
useExportUpcomingEvents->>useExportUpcomingEvents: Set isProcessing=false
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. 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 (
|
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: 8
🧹 Nitpick comments (19)
src/views/congregation/field_service_groups/index.styles.ts (2)
78-78
: Consider using a design system constant for border color.The borderColor is hardcoded to
#AAAAAA
. Consider extracting this to a constant if it's used elsewhere for consistency.
91-91
: Consider using a design system constant for border color.The border color is hardcoded to
#DADADA
. Consider extracting this to a constant if it's used elsewhere for consistency.src/views/components/document/index.tsx (1)
6-11
: Consider making metadata configurable for better reusability.The hardcoded metadata values work for the current use case but could limit reusability.
Consider making metadata configurable:
const Document = ({ title, children, + author = "sws2apps", + creator = "Organized", + producer = "sws2apps (by react-pdf)" }: PDFDocumentType) => { return ( <ReactPDFDocument - author="sws2apps" + author={author} title={title} - creator="Organized" + creator={creator} - producer="sws2apps (by react-pdf)" + producer={producer} > {children} </ReactPDFDocument> ); };This would require updating the
PDFDocumentType
interface accordingly.src/views/congregation/upcoming_events/UpcomingEventsList.tsx (2)
7-28
: Solid grouping logic with minor clarity improvements possible.The event grouping and sorting logic is correct and handles edge cases well. The non-null assertion operators are technically safe given the surrounding logic, but could be made more explicit for better code clarity.
Consider storing the array references to avoid repeated map lookups:
const sortEventsByYear = (events: UpcomingEventType[]) => { const yearMap = new Map<number, UpcomingEventType[]>(); for (const event of events) { if (event._deleted) continue; const dateStr = event.event_data?.start; if (!dateStr) continue; const year = new Date(dateStr).getFullYear(); if (!yearMap.has(year)) { yearMap.set(year, []); } - yearMap.get(year)!.push(event); + const yearEvents = yearMap.get(year)!; + yearEvents.push(event); } const sortedYears = Array.from(yearMap.keys()).sort((a, b) => a - b); - return sortedYears.map((year) => yearMap.get(year)!); + return sortedYears.map((year) => { + const events = yearMap.get(year)!; + return events; + }); };
40-70
: Verify events array safety in render logic.The code assumes
events[0]
exists when accessingevents[0].event_data.start
for the key and year display. While this should be safe given the filtering logic, consider adding explicit checks for robustness.{sortedEvents.map((events) => ( + {events.length > 0 && ( <View - key={new Date(events[0].event_data.start).getFullYear()} + key={new Date(events[0].event_data.start).getFullYear()} style={{ display: 'flex', flexDirection: 'column', gap: '8px' }} > <View style={{ border: '1px solid #D5DFFD', padding: '5px 8px', borderRadius: '4px', backgroundColor: '#F2F5FF', display: 'flex', alignItems: 'center', justifyContent: 'center', }} > <Text style={{ fontWeight: 600, fontSize: '12px', color: '#5065D0', }} > {new Date(events[0].event_data.start).getFullYear()} </Text> </View> {events.map((eventData) => ( <UpcomingEvent key={eventData.event_data.start} event={eventData} /> ))} </View> + )} ))}src/features/congregation/upcoming_events/export_upcoming_events/useExportUpcomingEvents.tsx (1)
38-38
: Consider filename sanitization for cross-platform compatibility.The filename generation uses
replaceAll(' ', '_')
but might need additional sanitization for special characters that could be problematic on different operating systems.- const filename = `${t('tr_upcomingEvents').replaceAll(' ', '_')}.pdf`; + const filename = `${t('tr_upcomingEvents').replace(/[^a-zA-Z0-9]/g, '_')}.pdf`;src/views/components/page_bottom/index.tsx (1)
16-64
: Consider consistent styling approach.The component mixes hardcoded color values with CSS variable calls. For PDF components, consider using a consistent approach with either all hardcoded values or a centralized theme configuration.
src/views/congregation/upcoming_events/index.tsx (1)
11-15
: Address unused prop in component signature.The
shortDateFormat
prop is defined inTemplateUpcomingEventsProps
but is not used anywhere in this component. Consider removing it from the type definition if it's truly unused, or implement its intended functionality.Either remove the unused prop from the type definition:
export type TemplateUpcomingEventsProps = { events: UpcomingEventType[]; - shortDateFormat: string; lang: string; congregation: string; };
Or destructure and use it if there's intended functionality:
const TemplateUpcomingEvents = ({ events, congregation, lang, + shortDateFormat, }: TemplateUpcomingEventsProps) => {
src/views/congregation/upcoming_events/UpcomingEventDate.tsx (2)
99-99
: Improve description condition check.The current condition
description !== ''
doesn't handle undefined/null values properly. Since description is optional, this could cause unexpected behavior.- {description !== '' && ( + {description && description !== '' && (Or more concisely:
- {description !== '' && ( + {description && (
46-46
: Consider using CSS variables for color consistency.The component uses hardcoded hex colors instead of CSS variables. For better maintainability and theming consistency, consider using
getCSSPropertyValue()
for colors like other components in the codebase.For example:
- backgroundColor: '#F2F5FF', + backgroundColor: getCSSPropertyValue('--some-background-color'),Also applies to: 55-55, 64-64, 75-75, 94-94, 104-104
src/views/components/page_header/index.tsx (1)
39-39
: Consider centralizing color values for consistency.The component uses hardcoded colors (
#FEFEFE
,#000000
) mixed with CSS variables. For better maintainability, consider using a consistent approach throughout the component.Also applies to: 49-49, 78-78, 95-95
src/views/components/icons/IconAirplaneTicket.tsx (2)
4-4
: Annotate the component with an explicitReact.FC
typeTyping the component as
React.FC<IconProps>
(orFC
) tightens the contract, enables better IntelliSense, and prevents implicit-any
return types:-const IconAirplaneTicket = ({ size = 24, color = '#222222' }: IconProps) => { +const IconAirplaneTicket: React.FC<IconProps> = ({ size = 24, color = '#222222' }) => {If your project still uses the classic JSX runtime, remember to
import React from 'react';
; otherwise ensuretsconfig.json
is set to"jsx": "react-jsx"
.
6-14
: Consider memoising repeated icon componentsIcons are pure functions of their props; wrapping them with
React.memo
avoids needless re-rendering when used repeatedly in complex PDF pages:-const IconAirplaneTicket: React.FC<IconProps> = ({ size = 24, color = '#222222' }) => { +const IconAirplaneTicket: React.FC<IconProps> = React.memo(({ size = 24, color = '#222222' }) => { … -}; +});(This refactor applies to the whole icon set for a low-cost perf win.)
src/views/components/icons/IconLightbulb.tsx (2)
4-4
: Apply the same explicit typing pattern-const IconLightbulb = ({ size = 24, color = '#222222' }: IconProps) => { +const IconLightbulb: React.FC<IconProps> = ({ size = 24, color = '#222222' }) => {This stays consistent with the rest of the codebase and with the recommendation given for
IconAirplaneTicket
.
6-14
: Optional: wrap withReact.memo
As above, memoising the component can shave off redundant renders when the same icon is scattered across pages.
src/views/components/icons/IconVacuum.tsx (2)
4-4
: AddReact.FC
typing for stronger type-safety-const IconVacuum = ({ size = 24, color = '#222222' }: IconProps) => { +const IconVacuum: React.FC<IconProps> = ({ size = 24, color = '#222222' }) => {
6-14
: Memoisation – same comment as other icons
React.memo
is a zero-risk optimisation here.src/views/components/icons/IconVoiceSelection.tsx (2)
4-4
: Consistent component typing-const IconVoiceSelection = ({ size = 24, color = '#222222' }: IconProps) => { +const IconVoiceSelection: React.FC<IconProps> = ({ size = 24, color = '#222222' }) => {
6-14
: OptionalReact.memo
optimisationSame rationale as for the other icons.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (2)
src/locales/en/forms-templates.json
is excluded by!**/*.json
src/locales/en/general.json
is excluded by!**/*.json
📒 Files selected for processing (49)
src/features/congregation/upcoming_events/export_upcoming_events/index.tsx
(1 hunks)src/features/congregation/upcoming_events/export_upcoming_events/useExportUpcomingEvents.tsx
(1 hunks)src/features/congregation/upcoming_events/upcoming_event/useUpcomingEvent.tsx
(1 hunks)src/pages/congregation/upcoming_events/index.tsx
(2 hunks)src/utils/date.ts
(1 hunks)src/views/components/document/index.tsx
(1 hunks)src/views/components/document/index.types.ts
(1 hunks)src/views/components/icons/IconAirplaneTicket.tsx
(1 hunks)src/views/components/icons/IconCalendarClock.tsx
(1 hunks)src/views/components/icons/IconCampaign.tsx
(1 hunks)src/views/components/icons/IconCart.tsx
(1 hunks)src/views/components/icons/IconCorporateFare.tsx
(1 hunks)src/views/components/icons/IconDate.tsx
(1 hunks)src/views/components/icons/IconDiagnosis.tsx
(1 hunks)src/views/components/icons/IconDistance.tsx
(1 hunks)src/views/components/icons/IconJwHome.tsx
(1 hunks)src/views/components/icons/IconLightbulb.tsx
(1 hunks)src/views/components/icons/IconLocalLibrary.tsx
(1 hunks)src/views/components/icons/IconStadium.tsx
(1 hunks)src/views/components/icons/IconTranslate.tsx
(1 hunks)src/views/components/icons/IconVacuum.tsx
(1 hunks)src/views/components/icons/IconVoiceSelection.tsx
(1 hunks)src/views/components/icons/IconWavingHand.tsx
(1 hunks)src/views/components/icons/IconWine.tsx
(1 hunks)src/views/components/icons/index.ts
(1 hunks)src/views/components/icons/index.types.ts
(0 hunks)src/views/components/index.ts
(1 hunks)src/views/components/page/index.tsx
(1 hunks)src/views/components/page/index.types.ts
(1 hunks)src/views/components/page_bottom/index.tsx
(1 hunks)src/views/components/page_bottom/index.types.ts
(1 hunks)src/views/components/page_content/index.tsx
(1 hunks)src/views/components/page_content/index.types.ts
(1 hunks)src/views/components/page_header/index.tsx
(1 hunks)src/views/components/page_header/index.types.ts
(1 hunks)src/views/congregation/field_service_groups/FSGGroup.tsx
(1 hunks)src/views/congregation/field_service_groups/FSGGroupMember.tsx
(1 hunks)src/views/congregation/field_service_groups/PageHeader.tsx
(0 hunks)src/views/congregation/field_service_groups/index.styles.ts
(3 hunks)src/views/congregation/field_service_groups/index.tsx
(1 hunks)src/views/congregation/field_service_groups/index.types.ts
(1 hunks)src/views/congregation/upcoming_events/UpcomingEvent.tsx
(1 hunks)src/views/congregation/upcoming_events/UpcomingEventDate.tsx
(1 hunks)src/views/congregation/upcoming_events/UpcomingEventsList.tsx
(1 hunks)src/views/congregation/upcoming_events/decoration_for_event.tsx
(1 hunks)src/views/congregation/upcoming_events/index.tsx
(1 hunks)src/views/congregation/upcoming_events/index.types.ts
(1 hunks)src/views/index.ts
(1 hunks)src/views/meetings/midweek/S140/app_normal/S140WeekHeader.tsx
(1 hunks)
💤 Files with no reviewable changes (2)
- src/views/components/icons/index.types.ts
- src/views/congregation/field_service_groups/PageHeader.tsx
🧰 Additional context used
🧬 Code Graph Analysis (32)
src/views/components/icons/IconJwHome.tsx (1)
src/views/components/icons/index.types.ts (1)
IconProps
(1-4)
src/views/congregation/field_service_groups/FSGGroupMember.tsx (1)
src/views/congregation/field_service_groups/index.types.ts (1)
FSGGroupMemberProps
(13-15)
src/views/components/page/index.tsx (1)
src/views/components/page/index.types.ts (1)
PageType
(3-6)
src/views/components/icons/IconCampaign.tsx (1)
src/views/components/icons/index.types.ts (1)
IconProps
(1-4)
src/views/components/icons/IconDistance.tsx (1)
src/views/components/icons/index.types.ts (1)
IconProps
(1-4)
src/views/components/icons/IconWine.tsx (1)
src/views/components/icons/index.types.ts (1)
IconProps
(1-4)
src/views/components/icons/IconCalendarClock.tsx (1)
src/views/components/icons/index.types.ts (1)
IconProps
(1-4)
src/views/components/icons/IconLightbulb.tsx (1)
src/views/components/icons/index.types.ts (1)
IconProps
(1-4)
src/features/congregation/upcoming_events/export_upcoming_events/useExportUpcomingEvents.tsx (3)
src/states/settings.ts (3)
JWLangLocaleState
(208-216)congNameState
(27-31)shortDateFormatState
(92-101)src/states/upcoming_events.ts (1)
upcomingEventsState
(8-8)src/services/i18n/translation.ts (1)
getMessageByCode
(43-45)
src/views/congregation/upcoming_events/UpcomingEventsList.tsx (2)
src/views/congregation/upcoming_events/index.types.ts (1)
UpcomingEventsListProps
(10-12)src/definition/upcoming_events.ts (1)
UpcomingEventType
(25-38)
src/views/congregation/field_service_groups/FSGGroup.tsx (1)
src/views/congregation/field_service_groups/index.types.ts (1)
FSGGroupProps
(9-11)
src/views/components/document/index.tsx (1)
src/views/components/document/index.types.ts (1)
PDFDocumentType
(4-7)
src/views/components/icons/IconVoiceSelection.tsx (1)
src/views/components/icons/index.types.ts (1)
IconProps
(1-4)
src/views/components/icons/IconDiagnosis.tsx (1)
src/views/components/icons/index.types.ts (1)
IconProps
(1-4)
src/views/components/icons/IconVacuum.tsx (1)
src/views/components/icons/index.types.ts (1)
IconProps
(1-4)
src/views/components/icons/IconAirplaneTicket.tsx (1)
src/views/components/icons/index.types.ts (1)
IconProps
(1-4)
src/views/components/icons/IconTranslate.tsx (1)
src/views/components/icons/index.types.ts (1)
IconProps
(1-4)
src/views/components/icons/IconDate.tsx (1)
src/views/components/icons/index.types.ts (1)
IconProps
(1-4)
src/views/components/icons/IconLocalLibrary.tsx (1)
src/views/components/icons/index.types.ts (1)
IconProps
(1-4)
src/views/components/icons/IconStadium.tsx (1)
src/views/components/icons/index.types.ts (1)
IconProps
(1-4)
src/views/congregation/upcoming_events/UpcomingEventDate.tsx (4)
src/views/congregation/upcoming_events/index.types.ts (1)
UpcomingEventDateProps
(18-23)src/services/i18n/translation.ts (1)
generateWeekday
(21-33)src/utils/date.ts (1)
formatDate
(15-17)src/utils/common.ts (1)
getCSSPropertyValue
(261-265)
src/views/components/icons/IconCorporateFare.tsx (1)
src/views/components/icons/index.types.ts (1)
IconProps
(1-4)
src/views/congregation/upcoming_events/index.tsx (2)
src/views/congregation/upcoming_events/index.types.ts (1)
TemplateUpcomingEventsProps
(3-8)src/constants/index.ts (1)
LANGUAGE_LIST
(31-361)
src/views/components/page_bottom/index.tsx (3)
src/views/components/page_bottom/index.types.ts (1)
PageBottomProps
(3-8)src/utils/common.ts (1)
getCSSPropertyValue
(261-265)src/utils/date.ts (1)
formatDate
(15-17)
src/views/components/icons/IconCart.tsx (1)
src/views/components/icons/index.types.ts (1)
IconProps
(1-4)
src/views/congregation/field_service_groups/index.types.ts (1)
src/definition/field_service_groups.ts (1)
FieldServiceGroupExportType
(22-28)
src/views/components/page_header/index.tsx (2)
src/views/components/page_header/index.types.ts (1)
PageHeaderProps
(3-10)src/utils/common.ts (1)
getCSSPropertyValue
(261-265)
src/views/congregation/upcoming_events/UpcomingEvent.tsx (4)
src/views/congregation/upcoming_events/index.types.ts (1)
UpcomingEventProps
(14-16)src/states/settings.ts (1)
hour24FormatState
(103-112)src/utils/date.ts (2)
formatDate
(15-17)getDatesBetweenDates
(472-484)src/views/congregation/upcoming_events/decoration_for_event.tsx (1)
decorationsForEvent
(20-85)
src/views/congregation/upcoming_events/index.types.ts (1)
src/definition/upcoming_events.ts (1)
UpcomingEventType
(25-38)
src/views/congregation/field_service_groups/index.tsx (2)
src/views/congregation/field_service_groups/index.types.ts (1)
TemplateFieldServiceGroupsProps
(3-7)src/constants/index.ts (1)
LANGUAGE_LIST
(31-361)
src/views/components/icons/IconWavingHand.tsx (1)
src/views/components/icons/index.types.ts (1)
IconProps
(1-4)
src/views/components/page_content/index.tsx (1)
src/views/components/page_content/index.types.ts (1)
PageContentProps
(3-6)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: Code QL
- GitHub Check: Summary
🔇 Additional comments (49)
src/views/components/document/index.types.ts (1)
1-7
: LGTM! Clean type definition with helpful naming context.The type definition is well-structured and the comment explaining the naming choice to avoid conflict with React's default
DocumentType
is valuable for maintainability.src/views/components/page_content/index.types.ts (1)
1-6
: LGTM! Simple and well-structured prop types.The type definition is clean with appropriate optional/required properties that align with typical React component patterns.
src/views/components/page_header/index.types.ts (1)
1-10
: LGTM! Comprehensive and well-typed page header props.The type definition effectively uses union types for variants and provides good flexibility with optional properties. The JSX.Element type for the icon is appropriate.
src/views/components/icons/IconDistance.tsx (1)
1-17
: LGTM! Well-structured icon component following established patterns.The component correctly implements the
IconProps
interface, uses appropriate default values, and follows the pattern established by other icon components in the codebase for @react-pdf/renderer usage.src/views/index.ts (1)
7-7
: LGTM! Clean export addition following established patterns.The new
TemplateUpcomingEvents
export follows the consistent naming convention and is properly grouped with other congregation templates.src/features/congregation/upcoming_events/upcoming_event/useUpcomingEvent.tsx (1)
8-8
: Good refactoring! Centralizing utility functions improves maintainability.Moving
getDatesBetweenDates
to a shared utility module promotes code reuse and reduces duplication across the codebase.src/views/congregation/field_service_groups/FSGGroup.tsx (2)
3-3
: Improved naming convention with "Props" suffix.The change from
FSGGroupType
toFSGGroupProps
better reflects that this type defines component props, following React TypeScript conventions.
7-7
: Type annotation updated consistently.The component prop type annotation correctly uses the renamed
FSGGroupProps
type.src/views/meetings/midweek/S140/app_normal/S140WeekHeader.tsx (1)
17-17
: Good addition of explicit icon props for better control.Adding
size={10}
andbackgroundColor="none"
provides explicit control over the icon's appearance and supports the broader icon standardization effort across the codebase.src/views/components/page/index.types.ts (1)
1-6
: Well-structured type definition for PDF page components.The
PageType
definition cleanly encapsulates the required props for PDF page components with appropriate typing forfont
styling andReactNode
children.src/views/congregation/field_service_groups/FSGGroupMember.tsx (1)
2-2
: LGTM: Type renaming follows consistent naming convention.The change from
FSGGroupMemberType
toFSGGroupMemberProps
aligns with the broader refactor to use "Props" suffix for component prop types, improving consistency across the codebase.Also applies to: 5-5
src/pages/congregation/upcoming_events/index.tsx (1)
9-9
: LGTM: Clean integration of export functionality.The
ExportUpcomingEvents
component is properly imported and integrated into the admin-only button group, following the existing conditional rendering pattern and logical button ordering.Also applies to: 36-36
src/views/components/page_bottom/index.types.ts (1)
1-8
: LGTM: Well-structured type definition.The
PageBottomProps
type is comprehensive with appropriate types for each property. The optionalfixed
prop andReactNode
type forqrCode
are correctly defined for PDF footer functionality.src/views/components/page_content/index.tsx (1)
4-18
: LGTM: Well-implemented reusable layout component.The
PageContent
component follows good practices with proper default value handling (gap ?? 16
), correct flex styling for PDF rendering, and clean prop destructuring. The component provides good reusability for PDF layouts.src/views/components/icons/IconWine.tsx (1)
4-15
: LGTM: Well-implemented SVG icon component.The
IconWine
component follows the established pattern for PDF renderer icons with proper prop defaults, correct SVG structure, and appropriate use of thecolor
prop for fill styling. The implementation is consistent with other icon components in the codebase.src/views/congregation/field_service_groups/index.styles.ts (2)
2-2
: Import remains necessary
ThegetCSSPropertyValue
function is still used for theborderRadius
property in this file:
- src/views/congregation/field_service_groups/index.styles.ts –
borderRadius: getCSSPropertyValue('--radius-xs')
40-40
: Verify CSS variable for repeated hardcoded color
I spotted many occurrences of#3B4CA3
across the codebase—ensure this hex value is an approved design-system token and replace all instances with the corresponding CSS variable or theme constant if one exists.Key locations:
- src/views/congregation/field_service_groups/index.styles.ts
- src/views/congregation/upcoming_events/UpcomingEventDate.tsx
- src/views/meetings/weekend/index.styles.ts
- src/views/meetings/midweek/S140/app_normal/index.tsx
- src/components/illustrations/IllustrationSecretary.tsx
- src/components/icons/IconMale.tsx
If
#3B4CA3
is the “brand” or “primary” blue, define it once (e.g.--color-primary-blue
) and import/use that variable everywhere instead of hardcoding.src/views/components/index.ts (1)
1-6
: Well-structured barrel export pattern.This centralized export approach improves import organization and provides a clean API for consuming these PDF components.
src/views/components/icons/IconJwHome.tsx (1)
4-23
: Well-implemented icon component following established patterns.The component correctly implements the IconProps interface and follows the established pattern for PDF-compatible SVG icons. The use of Group to contain multiple paths is appropriate.
src/views/components/icons/IconCampaign.tsx (1)
4-15
: Consistent icon implementation following established patterns.The component correctly implements the IconProps interface and maintains consistency with other icon components in the codebase.
src/views/components/icons/IconTranslate.tsx (1)
4-15
: Consistent icon implementation following established patterns.The component correctly implements the IconProps interface and maintains consistency with other icon components in the codebase. The complex path appropriately represents the translation/language concept.
src/views/components/icons/IconAirplaneTicket.tsx (1)
1-18
: Well-implemented icon component following established patterns.The component correctly implements the PDF icon pattern with proper TypeScript typing, appropriate defaults, and clean SVG structure. The implementation is consistent with the broader icon system being introduced.
src/views/components/icons/IconLightbulb.tsx (1)
1-18
: Consistent implementation with established icon patterns.The component maintains excellent consistency with other icon components in the system, using identical prop handling, defaults, and SVG structure. The implementation is clean and follows TypeScript best practices.
src/views/components/icons/IconVacuum.tsx (1)
1-18
: Excellent consistency with the icon component system.The implementation perfectly follows the established icon pattern with proper TypeScript typing, consistent defaults, and clean SVG structure. The component integrates well with the broader icon library.
src/views/components/page/index.tsx (1)
1-25
: Well-designed page wrapper promoting consistency.This component provides an excellent abstraction over @react-pdf/renderer's Page component, standardizing A4 page layout with consistent styling while allowing dynamic font application. The implementation promotes code reuse and maintains consistency across PDF documents.
src/views/components/icons/IconVoiceSelection.tsx (1)
1-18
: Perfect consistency completing the icon component system.The component maintains the same high-quality implementation pattern as all other icon components in this PR. The consistent approach across all icons demonstrates excellent architectural planning and will ensure easy maintenance and extensibility of the icon system.
src/views/components/icons/IconDiagnosis.tsx (1)
1-17
: LGTM! Clean icon component implementation.The component follows proper TypeScript patterns, correctly uses
@react-pdf/renderer
primitives, and implements theIconProps
interface consistently.src/views/components/icons/IconCalendarClock.tsx (1)
1-17
: LGTM! Consistent icon component implementation.The component follows the established patterns and correctly implements the
IconProps
interface. The viewBox dimensions (24 x 25) appear intentional for the calendar-clock design.src/views/components/icons/IconCorporateFare.tsx (1)
1-17
: LGTM! Follows established icon component patterns.The component is consistent with other icon components in the codebase and properly implements the
IconProps
interface.src/views/congregation/upcoming_events/decoration_for_event.tsx (1)
1-85
: Clean icon mapping implementation with consistent structure.The centralized mapping of event types to icons is well-organized and provides a maintainable way to manage event decorations. The consistent structure makes it easy to add or modify event-icon associations.
src/views/components/icons/IconStadium.tsx (1)
1-18
: Well-implemented SVG icon component following established patterns.The component correctly implements the IconProps interface, uses appropriate defaults, and follows the consistent structure established for other icon components. The SVG implementation is properly configured with viewBox and path data.
src/features/congregation/upcoming_events/export_upcoming_events/index.tsx (1)
1-28
: LGTM! Clean and well-structured export component.The component follows React best practices with proper separation of concerns using custom hooks, conditional rendering for loading states, and internationalization support. The code is readable and maintainable.
src/views/components/icons/IconCart.tsx (1)
1-73
: LGTM! Well-implemented PDF icon component.The component correctly follows the established pattern for PDF icons using @react-pdf/renderer primitives, properly handles the IconProps interface, and maintains consistency with other icon components in the codebase.
src/views/congregation/field_service_groups/index.types.ts (1)
3-15
: LGTM! Improved type naming for better semantic accuracy.The refactoring from "Type" to "Props" suffix better reflects that these types define component props rather than general data structures, following React/TypeScript naming conventions.
src/views/components/icons/IconWavingHand.tsx (1)
1-17
: LGTM! Good refactoring for consistency and flexibility.The refactoring successfully standardizes the icon component to match the established pattern with configurable size and color props, improving consistency across the icon library.
src/views/congregation/upcoming_events/index.tsx (2)
18-21
: LGTM: Font selection logic is well-implemented.The font selection logic correctly falls back to 'Inter' when no specific font is found for the language, ensuring proper text rendering across different locales.
6-6
: No icon inconsistency detectedThe
IconDate
import insrc/views/congregation/upcoming_events/index.tsx
is correctly used for the header, andIconCalendarClock
is intentionally reserved for individual event decorations indecoration_for_event.tsx
. No change needed here.Likely an incorrect or invalid review comment.
src/views/congregation/upcoming_events/UpcomingEventDate.tsx (1)
21-26
: LGTM: Weekday calculation correctly handles Sunday edge case.The logic properly adjusts Sunday (getDay() returns 0) to index 6 and shifts other days down by 1 to match the Monday-first weekday array from
generateWeekday()
.src/views/congregation/upcoming_events/UpcomingEvent.tsx (3)
63-66
: LGTM: Icon cloning with dynamic props is well-implemented.The use of
cloneElement
to pass size and backgroundColor props to the icon components is a clean approach for consistent styling across different event types.
89-111
: LGTM: Complex conditional rendering logic is well-structured.The nested conditional logic properly handles different combinations of event duration and category, providing appropriate date display for single-day events, multi-day events, and special campaign weeks.
19-30
: Fix variable dependency order issue.The
eventDaysCountIndicator
function (lines 19-24) referenceseventDates
which is declared later (lines 27-30). This will cause a ReferenceError at runtime.Move the
eventDates
declaration beforeeventDaysCountIndicator
:const UpcomingEvent = ({ event }: UpcomingEventProps) => { const { t } = useAppTranslation(); const hour24 = useAtomValue(hour24FormatState); + const eventDates = getDatesBetweenDates( + new Date(event.event_data.start), + new Date(event.event_data.end) + ); + const eventDaysCountIndicator = () => { const shortMonth = formatDate(eventDates[0], 'LLL'); const startDay = formatDate(eventDates[0], 'd'); const endDay = formatDate(eventDates[eventDates.length - 1], 'd'); return `${shortMonth}. ${startDay}-${endDay}`; }; const eventTime = `${formatDate(new Date(event.event_data.start), hour24 ? 'HH:mm' : 'hh:mm a')} - ${formatDate(new Date(event.event_data.end), hour24 ? 'HH:mm' : 'hh:mm a')}`; - const eventDates = getDatesBetweenDates( - new Date(event.event_data.start), - new Date(event.event_data.end) - );Likely an incorrect or invalid review comment.
src/views/congregation/upcoming_events/index.types.ts (2)
3-8
: LGTM: Type definitions are well-structured.The type definitions properly model the component props and provide good type safety. The
shortDateFormat
unused prop issue is already addressed in the main component review.
18-23
: LGTM: UpcomingEventDateProps type is comprehensive.The type definition properly handles all the optional properties and provides flexibility for different date display scenarios.
src/views/components/page_header/index.tsx (1)
13-103
: LGTM: Switch-based variant handling is clean and maintainable.The component properly separates the two layout variants with clear, distinct styling. The structure allows for easy extension with additional variants if needed.
src/views/congregation/field_service_groups/index.tsx (4)
8-9
: LGTM! Clean import organization for new components.The imports for the new icon and custom PDF components are well-organized and follow the established patterns in the codebase.
27-34
: LGTM! Enhanced PageHeader with proper prop structure.The new
PageHeader
component usage is well-structured with clear props forcongregationName
,variant
,icon
,title
, andfixed
. The addition of theIconGroups
icon enhances the visual presentation.
27-40
: PageContent gap prop handling verifiedThe
PageContent
component correctly reads thegap
prop (falling back to16
) and applies it via thegap
style on its container.gap={10}
will render exactly as expected. No further changes needed.
25-26
: Custom PDF wrappers correctly forward props and maintain functionalityI verified that:
src/views/components/document/index.tsx
wrapsReactPDFDocument
, forwarding thetitle
prop (and applying fixed metadata) and renderingchildren
.src/views/components/page/index.tsx
wrapsReactPDFPage
, applies the passedfont
viastyle={{ fontFamily: font }}
, and renderschildren
.No further changes needed.
src/views/components/icons/index.ts (1)
2-18
: LGTM! Consistent icon export expansion.The 17 new icon exports follow the established naming convention (
IconCamelCase
) and export pattern. The alphabetical organization makes the module easy to navigate and maintain.
src/features/congregation/upcoming_events/export_upcoming_events/useExportUpcomingEvents.tsx
Outdated
Show resolved
Hide resolved
src/features/congregation/upcoming_events/export_upcoming_events/useExportUpcomingEvents.tsx
Outdated
Show resolved
Hide resolved
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
🧹 Nitpick comments (1)
src/views/congregation/upcoming_events/UpcomingEventsList.tsx (1)
19-39
: Consider extracting inline styles for better maintainability.The year header styling is comprehensive and visually appropriate. Consider extracting the inline styles to a separate styles object for better maintainability.
+const styles = { + yearHeader: { + border: '1px solid #D5DFFD', + padding: '5px 8px', + borderRadius: '4px', + backgroundColor: '#F2F5FF', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + }, + yearText: { + fontWeight: 600, + fontSize: '12px', + color: '#5065D0', + }, +}; + const UpcomingEventsList = ({ events }: UpcomingEventsListProps) => { return ( <View style={{ display: 'flex', flexDirection: 'column', gap: '16px', }} > - {events.map((events) => ( + {events.map((yearEvents) => ( <View - key={events[0].year} + key={yearEvents[0].year} style={{ display: 'flex', flexDirection: 'column', gap: '8px' }} > <View - style={{ - border: '1px solid #D5DFFD', - padding: '5px 8px', - borderRadius: '4px', - backgroundColor: '#F2F5FF', - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - }} + style={styles.yearHeader} > <Text - style={{ - fontWeight: 600, - fontSize: '12px', - color: '#5065D0', - }} + style={styles.yearText} > - {events[0].year} + {yearEvents[0].year} </Text> </View>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
src/features/congregation/upcoming_events/export_upcoming_events/useExportUpcomingEvents.tsx
(1 hunks)src/utils/date.ts
(1 hunks)src/views/congregation/upcoming_events/UpcomingEvent.tsx
(1 hunks)src/views/congregation/upcoming_events/UpcomingEventDate.tsx
(1 hunks)src/views/congregation/upcoming_events/UpcomingEventsList.tsx
(1 hunks)src/views/congregation/upcoming_events/index.types.ts
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
- src/views/congregation/upcoming_events/UpcomingEventDate.tsx
- src/features/congregation/upcoming_events/export_upcoming_events/useExportUpcomingEvents.tsx
- src/views/congregation/upcoming_events/UpcomingEvent.tsx
- src/utils/date.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Socket Security: Pull Request Alerts
- GitHub Check: Summary
🔇 Additional comments (6)
src/views/congregation/upcoming_events/UpcomingEventsList.tsx (1)
5-13
: LGTM!The component structure is clean with proper TypeScript typing and appropriate flex layout for PDF rendering.
src/views/congregation/upcoming_events/index.types.ts (5)
6-16
: LGTM!The
TemplateUpcomingEventType
is comprehensive and well-structured with appropriate property types and clear naming conventions.
18-23
: LGTM!The props structure appropriately supports PDF template rendering with event grouping and localization requirements.
25-27
: LGTM!Clean and focused props interface for the events list component.
29-31
: LGTM!Appropriately simple and clean interface for the individual event component.
33-38
: LGTM!Well-designed interface with appropriate required and optional properties for flexible date rendering.
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: 6
🧹 Nitpick comments (4)
src/views/activities/upcoming_events/UpcomingEventDate.tsx (1)
22-106
: Consider extracting hardcoded colors to constants.The component is well-structured and functionally correct, but contains several hardcoded color values that could benefit from centralization for maintainability and consistency.
Consider creating a color constants object or using CSS variables:
const PDF_COLORS = { dateBackground: '#F2F5FF', datePrimary: '#3B4CA3', textPrimary: '#222222', textSecondary: '#505050', } as const;Then use these constants throughout the component styling instead of hardcoded values.
src/features/activities/upcoming_events/export_upcoming_events/useExportUpcomingEvents.tsx (2)
91-91
: Remove debug console.log statement.This console.log should be removed before production deployment.
- console.log(eventsForPDF);
68-73
: Potential issue with date range logic for single-day events.The
eventDaysCountIndicator
function assumes the event spans multiple days, but it could be called for single-day events wherestartDay
andendDay
are the same.Consider handling single-day events differently:
const eventDaysCountIndicator = () => { const shortMonth = formatDate(eventDates[0], 'LLL'); const startDay = formatDate(eventDates[0], 'd'); const endDay = formatDate(eventDates[eventDates.length - 1], 'd'); - return `${shortMonth}. ${startDay}-${endDay}`; + return eventDates.length === 1 + ? `${shortMonth}. ${startDay}` + : `${shortMonth}. ${startDay}-${endDay}`; };src/views/activities/upcoming_events/UpcomingEvent.tsx (1)
72-90
: Consider simplifying complex conditional rendering logic.The nested ternary operators make the code harder to read and maintain. Consider extracting the date rendering logic into a separate function.
Consider refactoring to improve readability:
+ {(() => { + if (event.duration === UpcomingEventDuration.SingleDay) { + return <UpcomingEventDate date={new Date(event.start)} title={event.time} />; + } + + if (event.category === UpcomingEventCategory.SpecialCampaignWeek) { + return ( + <UpcomingEventDate + date={event.dates[0]} + title={t('tr_everyDay')} + description={t('tr_days', { daysCount: event.dates.length })} + dayIndicatorText={event.eventDaysCountIndicator} + /> + ); + } + + return event.dates.map((eventDate, eventDateIndex) => ( + <UpcomingEventDate + key={new Date(eventDate).toISOString()} + date={eventDate} + title={t('tr_wholeDay')} + description={`${t('tr_day')} ${eventDateIndex + 1}/${event.dates.length}`} + /> + )); + })()} - {event.duration === UpcomingEventDuration.SingleDay ? ( - <UpcomingEventDate date={new Date(event.start)} title={event.time} /> - ) : event.category !== UpcomingEventCategory.SpecialCampaignWeek ? ( - event.dates.map((eventDate, eventDateIndex) => ( - <UpcomingEventDate - key={new Date(eventDate).toISOString()} - date={eventDate} - title={t('tr_wholeDay')} - description={`${t('tr_day')} ${eventDateIndex + 1}/${event.dates.length}`} - /> - )) - ) : ( - <UpcomingEventDate - date={event.dates[0]} - title={t('tr_everyDay')} - description={t('tr_days', { daysCount: event.dates.length })} - dayIndicatorText={event.eventDaysCountIndicator} - /> - )}
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
src/locales/en/general.json
is excluded by!**/*.json
📒 Files selected for processing (11)
src/features/activities/upcoming_events/export_upcoming_events/index.tsx
(1 hunks)src/features/activities/upcoming_events/export_upcoming_events/useExportUpcomingEvents.tsx
(1 hunks)src/features/activities/upcoming_events/upcoming_event/useUpcomingEvent.tsx
(2 hunks)src/pages/activities/upcoming_events/index.tsx
(2 hunks)src/utils/date.ts
(1 hunks)src/views/activities/upcoming_events/UpcomingEvent.tsx
(1 hunks)src/views/activities/upcoming_events/UpcomingEventDate.tsx
(1 hunks)src/views/activities/upcoming_events/UpcomingEventsList.tsx
(1 hunks)src/views/activities/upcoming_events/decoration_for_event.tsx
(1 hunks)src/views/activities/upcoming_events/index.tsx
(1 hunks)src/views/activities/upcoming_events/index.types.ts
(1 hunks)
✅ Files skipped from review due to trivial changes (2)
- src/views/activities/upcoming_events/decoration_for_event.tsx
- src/views/activities/upcoming_events/index.types.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- src/utils/date.ts
🧰 Additional context used
🧠 Learnings (1)
src/features/activities/upcoming_events/upcoming_event/useUpcomingEvent.tsx (1)
Learnt from: nobodyzero1
PR: #4326
File: src/utils/enrollments.ts:20-25
Timestamp: 2025-07-09T14:24:33.861Z
Learning: In src/utils/enrollments.ts, the enrollmentStartDateChange function already includes a null check for the current variable to handle cases where the find operation returns undefined.
🧬 Code Graph Analysis (6)
src/features/activities/upcoming_events/upcoming_event/useUpcomingEvent.tsx (1)
src/utils/date.ts (1)
getDatesBetweenDates
(453-470)
src/views/activities/upcoming_events/UpcomingEventDate.tsx (4)
src/views/activities/upcoming_events/index.types.ts (1)
UpcomingEventDateProps
(34-39)src/services/i18n/translation.ts (1)
generateWeekday
(21-33)src/utils/common.ts (1)
getCSSPropertyValue
(261-265)src/utils/date.ts (1)
formatDateShortMonth
(492-505)
src/views/activities/upcoming_events/UpcomingEventsList.tsx (1)
src/views/activities/upcoming_events/index.types.ts (1)
UpcomingEventsListProps
(26-28)
src/views/activities/upcoming_events/index.tsx (2)
src/views/activities/upcoming_events/index.types.ts (1)
TemplateUpcomingEventsProps
(19-24)src/constants/index.ts (1)
LANGUAGE_LIST
(31-361)
src/features/activities/upcoming_events/export_upcoming_events/useExportUpcomingEvents.tsx (6)
src/states/settings.ts (4)
JWLangLocaleState
(209-217)congNameState
(28-32)hour24FormatState
(104-113)shortDateFormatState
(93-102)src/states/upcoming_events.ts (1)
upcomingEventsState
(10-16)src/definition/upcoming_events.ts (1)
UpcomingEventType
(25-38)src/views/activities/upcoming_events/index.types.ts (1)
TemplateUpcomingEventType
(6-17)src/utils/date.ts (2)
formatDate
(16-18)getDatesBetweenDates
(453-470)src/services/i18n/translation.ts (1)
getMessageByCode
(43-45)
src/views/activities/upcoming_events/UpcomingEvent.tsx (2)
src/views/activities/upcoming_events/index.types.ts (1)
UpcomingEventProps
(30-32)src/views/activities/upcoming_events/decoration_for_event.tsx (1)
decorationsForEvent
(20-85)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
- GitHub Check: Code QL
- GitHub Check: Summary
🔇 Additional comments (9)
src/pages/activities/upcoming_events/index.tsx (2)
9-9
: LGTM!Clean import addition for the new export component.
37-37
: LGTM!The integration of the
ExportUpcomingEvents
component is well-placed within the admin-only buttons section, replacing the previous placeholder implementation.src/features/activities/upcoming_events/upcoming_event/useUpcomingEvent.tsx (2)
5-5
: LGTM!Good addition of the utility function import to support the refactored date range logic.
27-30
: Excellent refactor using the date utility function.Replacing the manual date iteration with
getDatesBetweenDates
improves code maintainability and reduces duplication. The utility function handles the date range generation logic correctly and theuseMemo
dependencies are properly updated.src/features/activities/upcoming_events/export_upcoming_events/index.tsx (1)
1-29
: Well-structured export component.The implementation follows React best practices with proper separation of concerns, loading state handling, and consistent styling patterns. The use of the custom hook keeps the component clean and focused on presentation.
src/views/activities/upcoming_events/index.tsx (3)
9-9
: LGTM!Font registration at module level is appropriate for PDF generation setup.
18-20
: Good font selection logic with fallback.The language-based font selection using
LANGUAGE_LIST
with a fallback to 'Inter' is robust and handles cases where no specific font is configured for a language.
22-36
: Well-structured PDF template component.The component properly composes PDF view elements with appropriate localization, styling, and data passing. The structure is clean and follows the established patterns for PDF document generation.
src/views/activities/upcoming_events/UpcomingEventDate.tsx (1)
15-20
: LGTM!The weekday calculation correctly handles Sunday adjustment from index 0 to 6, properly mapping to the Monday-first weekday array.
src/features/activities/upcoming_events/export_upcoming_events/useExportUpcomingEvents.tsx
Show resolved
Hide resolved
src/features/activities/upcoming_events/export_upcoming_events/useExportUpcomingEvents.tsx
Show resolved
Hide resolved
|
organized-app
|
Project |
organized-app
|
Branch Review |
main
|
Run status |
|
Run duration | 00m 11s |
Commit |
|
Committer | Max Makaluk |
View all properties for this run ↗︎ |
Test results | |
---|---|
|
0
|
|
0
|
|
0
|
|
0
|
|
1
|
View all changes introduced in this branch ↗︎ |
🎉 This PR is included in version 3.32.0 🎉 The release is available on GitHub release Your semantic-release bot 📦🚀 |
Description
In this PR, I’ve added a new PDF template for exporting upcoming events and refactored the folder structure related to this feature for better clarity and maintainability.
Apologies for exceeding the 30-file change limit 🙏
Most of the changes are static assets (like icons), and the actual logic changes are minimal.
Also, I had to recreate some of the changes due to earlier errors, which caused extra file diffs in this PR. Sorry for the noise — everything should be working smoothly now.
Let me know if you'd like me to split or revise anything!
Fixes # (issue)
Type of change
Checklist: