-
Notifications
You must be signed in to change notification settings - Fork 74
[Feature] Weekly Limit | Export PDF Weekly limit report #3716
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
[Feature] Weekly Limit | Export PDF Weekly limit report #3716
Conversation
WalkthroughThis pull request makes the Changes
Sequence Diagram(s)sequenceDiagram
participant U as User
participant EM as WeeklyLimitExportMenu
participant PDF as PDFDownloadLink/WeeklyLimitPDFDocument
U->>EM: Clicks "EXPORT" button
EM->>EM: Display dropdown options (PDF, CSV)
U->>EM: Selects "PDF" export option
EM->>PDF: Trigger PDF generation
PDF-->>EM: Return generated PDF document
EM->>U: Initiate PDF download
Assessment against linked issues
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
apps/web/app/[locale]/reports/weekly-limit/components/time-report-table.tsxOops! Something went wrong! :( ESLint: 8.46.0 ESLint couldn't find the config "next/core-web-vitals" to extend from. Please check that the name of the config is correct. The config "next/core-web-vitals" was referenced from the config file in "/apps/web/.eslintrc.json". If you still have problems, please stop by https://eslint.org/chat/help to chat with the team. apps/web/app/[locale]/reports/weekly-limit/export-formats/pdf/index.tsxOops! Something went wrong! :( ESLint: 8.46.0 ESLint couldn't find the config "next/core-web-vitals" to extend from. Please check that the name of the config is correct. The config "next/core-web-vitals" was referenced from the config file in "/apps/web/.eslintrc.json". If you still have problems, please stop by https://eslint.org/chat/help to chat with the team. ✨ Finishing Touches
🪧 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 (
|
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.
PR Summary
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here: https://app.greptile.com/review/github.
4 file(s) reviewed, no comment(s)
Edit PR Review Bot Settings | Greptile
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: 1
🧹 Nitpick comments (1)
apps/web/app/[locale]/reports/weekly-limit/components/weekly-limit-report-export-menu.tsx (1)
21-101
: Well-implemented export menu with PDF and future CSV support.The
WeeklyLimitExportMenu
component:
- Uses Headless UI's Menu and Transition for a professional dropdown effect
- Integrates PDFDownloadLink correctly for PDF generation
- Handles loading states appropriately
- Provides clear placeholder for future CSV implementation
- Uses translations consistently
Consider enhancing this implementation in the future with:
- A visual indicator (like a spinner) while PDF is generating
- Progress on the CSV export implementation
- Additional export formats if needed by users
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
apps/web/app/[locale]/reports/weekly-limit/components/time-report-table.tsx
(1 hunks)apps/web/app/[locale]/reports/weekly-limit/components/weekly-limit-report-export-menu.tsx
(1 hunks)apps/web/app/[locale]/reports/weekly-limit/export-formats/pdf/index.tsx
(1 hunks)apps/web/app/[locale]/reports/weekly-limit/page.tsx
(3 hunks)
🧰 Additional context used
🧬 Code Definitions (2)
apps/web/app/[locale]/reports/weekly-limit/page.tsx (1)
apps/web/app/[locale]/reports/weekly-limit/components/weekly-limit-report-export-menu.tsx (1)
WeeklyLimitExportMenu
(21-101)
apps/web/app/[locale]/reports/weekly-limit/components/weekly-limit-report-export-menu.tsx (1)
apps/web/app/[locale]/reports/weekly-limit/export-formats/pdf/index.tsx (1)
WeeklyLimitPDFDocument
(32-114)
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: Codacy Static Code Analysis
🔇 Additional comments (8)
apps/web/app/[locale]/reports/weekly-limit/components/time-report-table.tsx (1)
6-6
: Excellent update to make the interface exportable.Making the
ITimeReportTableProps
interface exportable is a good change that allows it to be reused by other components, particularly the new export functionality introduced in this PR.apps/web/app/[locale]/reports/weekly-limit/page.tsx (3)
22-22
: LGTM! New import for export functionality.This import allows the use of the new export menu component that enables PDF report generation.
126-142
: Successfully implemented the export menu component.The export menu is properly integrated with conditional rendering based on the existence of
organizationLimits
. The data filtering logic seems to match what's used elsewhere in the component.
180-186
: Improved header formatting for better readability.The date range in the weekly view is now better structured with appropriate spacing and styling.
apps/web/app/[locale]/reports/weekly-limit/export-formats/pdf/index.tsx (3)
11-30
: Well-structured PDF styling.The styles are well-organized and cover all necessary elements for the PDF layout, with appropriate widths and formatting for different cell types in the table.
32-114
: Well-implemented PDF document component.The
WeeklyLimitPDFDocument
component is properly structured and handles:
- Filtering reports based on display mode
- Creating appropriate date headers
- Generating tables with employee data
- Calculating time metrics correctly
The component provides a professional-looking report with good organization and visual hierarchy.
116-160
: Clean implementation of the Table component.The Table component is well-structured with:
- Clear separation of headers and rows
- Proper formatting of time values
- Logical handling of negative remaining time when percentage exceeds 100%
- Consistent styling applied to all elements
apps/web/app/[locale]/reports/weekly-limit/components/weekly-limit-report-export-menu.tsx (1)
11-19
: Well-defined interface for the export menu.The interface clearly specifies all required props for the export functionality, including data, team information, display mode, and organization limits.
apps/web/app/[locale]/reports/weekly-limit/export-formats/pdf/index.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: 4
🧹 Nitpick comments (3)
apps/web/app/[locale]/reports/weekly-limit/export-formats/pdf/index.tsx (3)
11-30
: Consider consolidating style properties for similar elements.The style definitions are clear, but there are opportunities to improve maintainability. Styles for shared properties like
display: 'flex'
andflexDirection: 'row'
appear in multiple places.Consider extracting common style properties into base styles that can be extended:
const styles = StyleSheet.create({ page: { padding: 20 }, + flexColumn: { display: 'flex', flexDirection: 'column' }, + flexRow: { display: 'flex', flexDirection: 'row' }, - table: { display: 'flex', flexDirection: 'column', width: '100%', fontWeight: '400', fontSize: '10px' }, + table: { width: '100%', fontWeight: '400', fontSize: '10px' }, - row: { display: 'flex', flexDirection: 'row' }, rowHeader: { backgroundColor: 'rgba(0, 0, 0, 0.1)', height: '10px', - display: 'flex', alignItems: 'center', paddingHorizontal: '4px' }, // rest of the styles... });Then apply these base styles where needed:
-<View style={styles.table}> +<View style={[styles.flexColumn, styles.table]}> -<View style={styles.row}> +<View style={styles.flexRow}>
46-53
: Consider adding metadata to the Document component.The PDF document lacks metadata properties which are important for document identification and accessibility.
Add metadata to provide more context about the document:
-<Document style={{ width: '100%', height: '40rem' }}> +<Document + style={{ width: '100%', height: '40rem' }} + title={title} + author="Ever Teams" + creator="Ever Teams Weekly Limit Report" + producer="Ever Teams Application" +>
140-159
: Add pagination or overflow handling for large data sets.The table doesn't handle pagination or overflow if there are many employees in a single report, which could lead to content being cut off in the PDF.
Consider adding pagination support or a mechanism to handle overflow:
return ( <View style={styles.table}> {/** * Header */} <View key={0} style={[styles.headerRow, styles.row]}> {/* header cells */} </View> {/** * Body */} + {data.length === 0 ? ( + <View style={[styles.row, { justifyContent: 'center', padding: 10 }]}> + <Text>No data available</Text> + </View> + ) : ( {data.map((el, i) => ( <Row {...el} key={i} /> ))} + )} </View> );
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
apps/web/app/[locale]/reports/weekly-limit/export-formats/pdf/index.tsx
(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (2)
- GitHub Check: Codacy Static Code Analysis
- GitHub Check: deploy
🔇 Additional comments (1)
apps/web/app/[locale]/reports/weekly-limit/export-formats/pdf/index.tsx (1)
1-44
: Overall structure and imports look good.The file correctly imports necessary dependencies for a PDF export feature, defines styles using StyleSheet, and properly structures the component with appropriate props. The typings are well-defined and provide good documentation for what the component expects.
apps/web/app/[locale]/reports/weekly-limit/export-formats/pdf/index.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: 0
🧹 Nitpick comments (6)
apps/web/app/[locale]/reports/weekly-limit/export-formats/pdf/index.tsx (6)
56-62
: Handle potential edge cases in data filtering and mapping.The code doesn't handle the possibility of empty data arrays or undefined values within the data.
<View> {data + ?.filter((report) => { - ?.filter((report) => + if (!report || !report.date) return false; return displayMode === 'week' ? moment(report.date).isSame(moment(report.date).startOf('isoWeek'), 'date') : true + }) - ) ?.map((el, idx) => {
88-104
: Handle potential undefined employees array.The code doesn't check if
el.employees
exists before mapping over it, which could lead to runtime errors.<Table - data={el.employees?.map((item) => { + data={el.employees ? el.employees.map((item) => { const limit = item.limit || organizationLimits[displayMode] || DEFAULT_WORK_HOURS_PER_DAY; const percentageUsed = (item.duration / limit) * 100; const remaining = limit - item.duration; return { indexValue: item.employee.fullName, limit, percentageUsed, timeSpent: item.duration, remaining }; - })} + }) : []} headers={headers} />
155-157
: Add a check for empty data in the Table component.The Table component should handle cases where data is empty or undefined.
{/** * Body */} -{data.map((el, i) => ( +{data?.length > 0 ? data.map((el, i) => ( <Row {...el} key={i} /> -)) +)) : ( + <View style={styles.row}> + <Text style={[styles.cell, { width: '100%', textAlign: 'center', padding: 10 }]}> + No data available + </Text> + </View> +)}
46-47
: Consider adding more document metadata.For better accessibility and document management, consider adding metadata to the PDF document.
-<Document style={{ width: '100%', height: '40rem' }}> +<Document + style={{ width: '100%', height: '40rem' }} + title={`${title} - Weekly Limit Report`} + author="Ever Teams" + creator="Ever Teams" +> <Page size="A4" orientation="landscape" style={styles.page}>
123-138
: Create a separate Row component for better code organization.The Row function inside the Table component would be clearer as either a separate component or a memoized function outside the Table component.
+const TableRow = React.memo(({ row }: { row: WeeklyLimitTableDataType }) => ( + <View style={styles.row}> + <Text style={[styles.cell, styles.indexValue]}>{row.indexValue}</Text> + <Text style={[styles.cell, styles.timeSpent]}> + {formatTimeString(formatIntegerToHour(Number(row.timeSpent) / 3600))} + </Text> + <Text style={[styles.cell, styles.limit]}> + {formatTimeString(formatIntegerToHour(Number(row.limit) / 3600))} + </Text> + <Text style={[styles.cell, styles.percentageUsed]}>{`${Number(row.percentageUsed).toFixed(2)}%`}</Text> + <Text style={[styles.cell, styles.remaining]}> + {Number(row.remaining) < 0 + ? `-${formatTimeString(formatIntegerToHour(Math.abs(Number(row.remaining)) / 3600))}` + : formatTimeString(formatIntegerToHour(Number(row.remaining) / 3600)) + } + </Text> + </View> +)); function Table({ data, headers }: { data: WeeklyLimitTableDataType[]; headers: Record<keyof WeeklyLimitTableDataType, DottedLanguageObjectStringPaths>; }) { - const Row = (row: WeeklyLimitTableDataType) => ( - <View style={styles.row}> - <Text style={[styles.cell, styles.indexValue]}>{row.indexValue}</Text> - <Text style={[styles.cell, styles.timeSpent]}> - {formatTimeString(formatIntegerToHour(Number(row.timeSpent) / 3600))} - </Text> - <Text style={[styles.cell, styles.limit]}> - {formatTimeString(formatIntegerToHour(Number(row.limit) / 3600))} - </Text> - <Text style={[styles.cell, styles.percentageUsed]}>{`${Number(row.percentageUsed).toFixed(2)}%`}</Text> - <Text style={[styles.cell, styles.remaining]}> - {Number(row.percentageUsed) > 100 && '-'} - {formatTimeString(formatIntegerToHour(Number(row.remaining) / 3600))} - </Text> - </View> - );
132-132
: Format percentage values consistently.Consider standardizing the percentage display with a fixed number of decimal places for better readability.
-<Text style={[styles.cell, styles.percentageUsed]}>{`${Number(row.percentageUsed).toFixed(2)}%`}</Text> +<Text style={[styles.cell, styles.percentageUsed]}>{`${Math.min(Number(row.percentageUsed), 999.99).toFixed(2)}%`}</Text>
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
apps/web/app/[locale]/reports/weekly-limit/components/time-report-table.tsx
(2 hunks)apps/web/app/[locale]/reports/weekly-limit/export-formats/pdf/index.tsx
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/web/app/[locale]/reports/weekly-limit/components/time-report-table.tsx
⏰ Context from checks skipped due to timeout of 90000ms (1)
- GitHub Check: deploy
🔇 Additional comments (3)
apps/web/app/[locale]/reports/weekly-limit/export-formats/pdf/index.tsx (3)
90-96
: Improve variable calculations with appropriate type handling.The calculation of
limit
,percentageUsed
, andremaining
doesn't handle NaN or negative values.Add more robust checks for numeric calculations:
const limit = item.limit || organizationLimits[displayMode] || DEFAULT_WORK_HOURS_PER_DAY; -const percentageUsed = (item.duration / limit) * 100; +const percentageUsed = limit > 0 ? (item.duration / limit) * 100 : 0; -const remaining = limit - item.duration; +const remaining = Math.max(0, limit - item.duration);
133-136
: Fix inconsistent time formatting for negative values.The logic to display negative values is inconsistent with how the actual time is formatted. When the percentage used exceeds 100%, you're adding a "-" character, but the remaining time calculation might still be positive.
<Text style={[styles.cell, styles.remaining]}> - {Number(row.percentageUsed) > 100 && '-'} - {formatTimeString(formatIntegerToHour(Number(row.remaining) / 3600))} + {Number(row.remaining) < 0 + ? `-${formatTimeString(formatIntegerToHour(Math.abs(Number(row.remaining)) / 3600))}` + : formatTimeString(formatIntegerToHour(Number(row.remaining) / 3600)) + } </Text>
16-16
: Fix missing closing parenthesis in the backgroundColor style.There appears to be a syntax error in the rgba color definition.
- backgroundColor: 'rgba(0, 0, 0, 0.1)', + backgroundColor: 'rgba(0, 0, 0, 0.1)',Looking at the code, this issue appears to be already fixed in the current version.
Description
Type of Change
Checklist
Current screenshots
Loom
Summary by CodeRabbit
New Features
Refactor