-
Notifications
You must be signed in to change notification settings - Fork 5
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
Refactor Congratulations component and update SQL queries and localization support #1362
Conversation
…ter layout and text handling
WalkthroughThis pull request encompasses a diverse set of changes across multiple services and modules, focusing on improving user experience, localization, and data integrity. The modifications span course material rendering, reference handling, localization updates, and backend data management. Key areas of change include refactoring subtitle generation logic, enhancing reference parsing, adding marketing consent localization, and updating database query management for peer review configurations. Changes
Sequence DiagramsequenceDiagram
participant User
participant CongratulationsBlock
participant CourseModule
User->>CongratulationsBlock: Complete Course
CongratulationsBlock->>CourseModule: Check Module Completion
CourseModule-->>CongratulationsBlock: Return Completion Status
CongratulationsBlock->>CongratulationsBlock: Determine Subtitle Text
CongratulationsBlock->>User: Display Congratulations
Possibly related PRs
Suggested Labels
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (2)
⏰ Context from checks skipped due to timeout of 90000ms (4)
🔇 Additional comments (4)
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 (
|
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
🔭 Outside diff range comments (2)
shared-module/packages/common/src/components/Reference.tsx (1)
Line range hint
1-238
: Consider modernizing the implementation for better maintainability and accessibility.While the component works, there are several areas where it could be improved:
Replace DOM manipulations with React patterns:
- Use refs instead of
document.querySelector
- Manage tooltip state in React instead of direct DOM manipulation
- Handle styles through emotion instead of inline styles
Enhance accessibility:
- Add proper ARIA attributes to the details/summary elements
- Implement keyboard navigation for the tooltips
- Consider touch device support for the hover interactions
Optimize performance:
- Memoize event handlers
- Reduce DOM queries
- Consider using a virtual list for large reference lists
Here's a suggested approach for the tooltip implementation:
const ReferenceTooltip: React.FC<{text: string; isVisible: boolean; position: {x: number; y: number}}> = memo(({text, isVisible, position}) => { const tooltipStyles = css` opacity: ${isVisible ? 1 : 0}; position: absolute; top: ${position.y}px; left: ${position.x}px; // ... other styles `; return isVisible ? ( <div className={tooltipStyles} role="tooltip"> {text} </div> ) : null; });And for the main component:
const Reference: React.FC<ReferenceProps> = ({data}) => { const [activeTooltip, setActiveTooltip] = useState<{id: string; position: {x: number; y: number}} | null>(null); const detailsRef = useRef<HTMLDetailsElement>(null); const handleReferenceHover = useCallback((event: React.MouseEvent, citation: Reference) => { const target = event.currentTarget.getBoundingClientRect(); setActiveTooltip({ id: citation.id, position: { x: target.left + window.scrollX, y: target.bottom + window.scrollY } }); }, []); // ... rest of the implementation };Would you like me to provide more specific implementation details for any of these improvements?
shared-module/packages/common/src/locales/uk/course-material.json (1)
Line range hint
1-1
: Missing marketing consent translations.The marketing consent related keys that are present in the Finnish localization file are missing from the Ukrainian translations:
- "marketing-consent-checkbox-text"
- "marketing-consent-privacy-policy-checkbox-text"
Add the following keys with their Ukrainian translations:
{ + "marketing-consent-checkbox-text": "Я погоджуюся отримувати оновлення про майбутні мовні версії та інформацію про нові курси. Я погоджуюся надати свою контактну інформацію для отримання персоналізованих повідомлень на сторонніх платформах. Дізнайтеся більше в нашій Політиці конфіденційності.", + "marketing-consent-privacy-policy-checkbox-text": "Я приймаю Політику конфіденційності та Умови надання послуг.", // existing translations... }
🧹 Nitpick comments (3)
services/main-frontend/src/components/forms/NewCourseForm.tsx (2)
173-173
: Consider enhancing error handlingWhile the ErrorBanner implementation improves UI consistency, consider these enhancements:
- Format error messages for better user experience instead of using raw Error.toString()
- Clear errors when form fields change to provide immediate feedback
Example implementation:
const [error, setError] = useState<string | null>(null) +const formatErrorMessage = (error: Error): string => { + // Add custom error message mapping here + return error.message || t("generic-error-message") +} + +const clearError = () => setError(null) + // In your catch block: -setError(e.toString()) +setError(formatErrorMessage(e)) + // In your field change handlers: onChangeByValue={(value) => { setName(value) setSlug(normalizePath(value)) + clearError() }}
Line range hint
1-365
: Consider architectural improvements for better maintainabilityThe form implementation could benefit from several architectural improvements:
Form Management:
- Consider using a form library like Formik or React Hook Form for more robust validation and state management
- This would eliminate the need for multiple useState calls and manual form validation
Business Logic Separation:
- Extract course creation and duplication logic into custom hooks
- Separate language code validation into a utility function
State Management:
- Consider using a reducer to manage related state variables
- This would make state transitions more predictable and easier to test
Here's a high-level example of how this could be structured:
// hooks/useNewCourseForm.ts interface NewCourseFormState { name: string; slug: string; languageCode: string; isDuplicate: boolean; // ... other form fields } interface NewCourseFormActions { setName: (name: string) => void; setLanguageCode: (code: string) => void; // ... other actions } const useNewCourseForm = (initialState: NewCourseFormState): [NewCourseFormState, NewCourseFormActions] => { const [state, dispatch] = useReducer(formReducer, initialState); // ... form logic return [state, actions]; } // utils/languageValidation.ts export const validateLanguageCode = (code: string): ValidationResult => { // ... validation logic } // NewCourseForm.tsx const NewCourseForm: React.FC<NewCourseFormProps> = (props) => { const [formState, formActions] = useNewCourseForm(initialState); const createCourseMutation = useCreateCourseMutation(); const duplicateCourseMutation = useDuplicateCourseMutation(); // ... render form }shared-module/packages/common/src/locales/ar/main-frontend.json (1)
Line range hint
1-1
: Consider moving marketing-related translations to course-material.json.For better maintainability and consistency across languages, consider:
- Moving marketing-related translations to course-material.json
- Adding the full marketing consent text translations as seen in the Finnish version
Create a new
course-material.json
file for Arabic with the following translations:// ar/course-material.json { + "marketing-consent-checkbox-text": "أوافق على تلقي تحديثات حول الإصدارات اللغوية المستقبلية ومعلومات حول الدورات الجديدة. أوافق على مشاركة معلومات الاتصال الخاصة بي لتلقي رسائل مخصصة على المنصات الخارجية. اقرأ المزيد في سياسة الخصوصية الخاصة بنا.", + "marketing-consent-privacy-policy-checkbox-text": "أوافق على سياسة الخصوصية وشروط الخدمة." }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (14)
services/course-material/src/components/ContentRenderer/moocfi/CongratulationsBlock/Congratulations.tsx
(1 hunks)services/headless-lms/models/.sqlx/query-9b0e62cfe38673577b24eb3b1d2094f147a5ef7ba99446546bdfead686df2e88.json
(1 hunks)services/headless-lms/models/.sqlx/query-c94f61a635ad062e122b9cf0ed8085858924769294d0c5d6df7b29634b8485d0.json
(0 hunks)services/headless-lms/models/.sqlx/query-cdcc2e446166b920f1af4e384e2dc03e4478afb22198d49e7acbd393359fbaeb.json
(1 hunks)services/headless-lms/models/src/library/copying.rs
(2 hunks)services/main-frontend/src/components/forms/EditReferenceForm.tsx
(0 hunks)services/main-frontend/src/components/forms/NewCourseForm.tsx
(2 hunks)shared-module/packages/common/src/components/Reference.tsx
(1 hunks)shared-module/packages/common/src/locales/ar/course-material.json
(2 hunks)shared-module/packages/common/src/locales/ar/main-frontend.json
(1 hunks)shared-module/packages/common/src/locales/en/course-material.json
(1 hunks)shared-module/packages/common/src/locales/fi/course-material.json
(2 hunks)shared-module/packages/common/src/locales/uk/course-material.json
(1 hunks)shared-module/packages/common/src/locales/uk/main-frontend.json
(1 hunks)
💤 Files with no reviewable changes (2)
- services/main-frontend/src/components/forms/EditReferenceForm.tsx
- services/headless-lms/models/.sqlx/query-c94f61a635ad062e122b9cf0ed8085858924769294d0c5d6df7b29634b8485d0.json
🔇 Additional comments (17)
shared-module/packages/common/src/components/Reference.tsx (1)
90-91
: LGTM! Good handling of long content.
The addition of both word-wrap
and overflow-wrap
properties ensures proper text wrapping for long content across different browsers.
services/main-frontend/src/components/forms/NewCourseForm.tsx (1)
10-10
: LGTM: Import statement is properly organized
The ErrorBanner import follows the existing pattern of importing shared components.
services/course-material/src/components/ContentRenderer/moocfi/CongratulationsBlock/Congratulations.tsx (2)
106-108
: LGTM: Clear and descriptive variable name with correct logic.
The variable effectively checks both module completion and certification status.
110-120
: LGTM: Well-structured conditional logic for determining subtitle text.
The function cleanly handles all possible combinations of certification and credit registration states, with proper i18n integration.
Also applies to: 128-128
shared-module/packages/common/src/locales/ar/course-material.json (2)
127-128
: LGTM: Clear and consistent marketing consent messages in Arabic.
The translations maintain proper Arabic language conventions while accurately conveying the consent requirements.
215-218
: LGTM: Well-structured course completion messages in Arabic.
The translations effectively communicate the different completion scenarios (basic completion, with credits, with certificate) while maintaining natural Arabic language flow.
shared-module/packages/common/src/locales/en/course-material.json (1)
215-218
: LGTM: Clear and comprehensive completion messages.
The messages effectively communicate:
- Basic course completion
- Steps for certificate generation
- Process for ECTS credits
- Combined certificate and credits scenario
shared-module/packages/common/src/locales/fi/course-material.json (2)
129-130
: LGTM! Marketing consent messages are well-structured.
The translations are clear and comprehensive, properly covering both marketing consent and privacy policy acceptance.
219-222
: LGTM! Course completion messages cover all scenarios.
The translations effectively handle different completion scenarios:
- Basic course completion
- Certificate generation
- Credits registration
- Combined credits and certificate
shared-module/packages/common/src/locales/uk/course-material.json (1)
220-223
: LGTM! Course completion messages are well translated.
The Ukrainian translations effectively cover all completion scenarios and maintain consistency with other language versions.
shared-module/packages/common/src/locales/ar/main-frontend.json (1)
303-303
: LGTM! Marketing consent label is properly translated.
The Arabic translation for the marketing consent label is clear and accurate.
shared-module/packages/common/src/locales/uk/main-frontend.json (1)
304-304
: LGTM! The new localization key is well-structured.
The added key "label-ask-for-marketing-consent"
follows the established naming conventions and the Ukrainian translation "Запитати згоду на маркетинг" is grammatically correct.
services/headless-lms/models/src/library/copying.rs (3)
211-211
: Invoke the new copy function in the right place
This call to copy_peer_or_self_review_questions is properly placed after copy_peer_or_self_review_configs to ensure prerequisite data is already copied. This sequencing helps avoid foreign key or orphaned data issues.
796-802
: Small consistency check
The execution and immediate return flow here looks consistent. Just ensure that any cleanup or logging happens if an insertion fails.
783-795
: Ensure correct use of LEFT JOIN
The code uses LEFT JOIN on exercises but also filters out deleted exercises in the WHERE clause with AND e.deleted_at IS NULL. As a result, rows without a matching exercise record will be excluded anyway, effectively making this an INNER JOIN. If the intention is to only copy configurations with valid exercises, an explicit INNER JOIN might be clearer.
✅ Verification successful
Based on the evidence gathered, I can now provide a final response:
LEFT JOIN is appropriate here - keep as is
The LEFT JOIN with the exercises table is actually the correct approach in this context. The table peer_or_self_review_configs
was renamed from peer_review_configs
as part of a migration that added self-review functionality. The LEFT JOIN combined with e.deleted_at IS NULL
ensures that we only copy configurations that have valid, non-deleted exercises while maintaining data integrity. An INNER JOIN would be functionally equivalent here, but the LEFT JOIN makes it clearer that we're checking for the existence of valid exercises, which is a legitimate business requirement in this copying operation.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Verifying if any peer_or_self_review_configs record has no matching exercises
# This script will list all such configurations if they exist
ast-grep --pattern $'SELECT posrc.id FROM peer_or_self_review_configs posrc LEFT JOIN exercises e ON (e.id = posrc.exercise_id)'
Length of output: 129
Script:
#!/bin/bash
# Let's search for SQL queries involving peer_or_self_review_configs and exercises tables
rg -U "peer_or_self_review_configs.*exercises" -A 5 -B 5
Length of output: 1905
Script:
#!/bin/bash
# Let's search for the SQL schema or table definitions to understand the relationship
rg -U "CREATE TABLE.*peer_or_self_review_configs" -A 10
rg -U "CREATE TABLE.*exercises" -A 10
Length of output: 2489
Script:
#!/bin/bash
# Let's search for all SQL queries involving peer_or_self_review_configs to understand the data integrity requirements
rg -U "peer_or_self_review_configs" -A 5 -B 5 "*.sql"
Length of output: 99
Script:
#!/bin/bash
# Let's search for migrations or schema files containing peer_or_self_review_configs
rg -U "peer_or_self_review_configs" -A 5 -B 5 --glob "*.sql"
# Also search for the table creation SQL
rg -U "CREATE TABLE.*peer_or_self_review_configs" -A 10 --glob "*.sql"
Length of output: 2777
services/headless-lms/models/.sqlx/query-cdcc2e446166b920f1af4e384e2dc03e4478afb22198d49e7acbd393359fbaeb.json (1)
1-12
: Copy config query logic looks consistent
This insertion query properly excludes deleted records and exercises, promoting data integrity during copy. Consider confirming that any constraints (e.g., uniqueness, foreign keys) in the database schema won’t be inadvertently violated.
services/headless-lms/models/.sqlx/query-9b0e62cfe38673577b24eb3b1d2094f147a5ef7ba99446546bdfead686df2e88.json (1)
1-12
: Query ensures only active questions are copied
The code looks correct and complements the config-copy logic by thoroughly filtering out deleted records. Ensure that the references to exercises and configs align with the newly inserted config IDs, preventing orphaned references.
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 (5)
services/main-frontend/src/components/forms/NewReferenceForm.tsx (5)
37-42
: Suggest a naming refinement for clarity.Currently, the local variable references (line 41) has the same name as the "references" field in the form data, which might be confusing when browsing the code. Consider renaming one of them to avoid collision.
- const references = watch("references") + const watchedReferences = watch("references")
46-52
: Validate naming consistency and data transformations.
- The
references
variable here may overshadow the previously declared "references" from watch.- If you anticipate large reference data, consider caching the BibTeX results or handling errors in a separate utility function to keep the component lightweight.
65-66
: Confirm intended function name.The function is spelled “useCitataionLabelsThatWillChange.” This appears to be a typo of “useCitationLabelsThatWillChange.” Renaming ensures clarity in the codebase.
- const citationLabelsThatWillChange = useCitataionLabelsThatWillChange(references) + const citationLabelsThatWillChange = useCitationLabelsThatWillChange(references)
103-108
: Consider adding error handling or returning fallback.While this function safely rebuilds the citation object, it doesn’t handle invalid references internally. If used elsewhere without a try/catch, it can throw runtime errors. Confirm that all external callers handle the potential failures, or handle them here to improve robustness.
110-123
: Rename the function for correctness and clarity.“useCitataionLabelsThatWillChange” seems to have a typographical error. Original vs. safe label logic is beneficial, but the name should be updated to avoid confusion:
-export function useCitataionLabelsThatWillChange( +export function useCitationLabelsThatWillChange( references: string, ): { original: string; safe: string }[] { ... }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
services/main-frontend/src/components/forms/EditReferenceForm.tsx
(4 hunks)services/main-frontend/src/components/forms/NewReferenceForm.tsx
(4 hunks)shared-module/packages/common/src/locales/ar/main-frontend.json
(2 hunks)shared-module/packages/common/src/locales/en/main-frontend.json
(1 hunks)shared-module/packages/common/src/locales/fi/main-frontend.json
(1 hunks)shared-module/packages/common/src/locales/uk/main-frontend.json
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
- services/main-frontend/src/components/forms/EditReferenceForm.tsx
- shared-module/packages/common/src/locales/uk/main-frontend.json
- shared-module/packages/common/src/locales/ar/main-frontend.json
🔇 Additional comments (5)
shared-module/packages/common/src/locales/en/main-frontend.json (1)
558-558
: LGTM! Clear and well-structured error message.
The English translation is clear, grammatically correct, and effectively communicates:
- What will happen: "The label {{original}} will be changed {{safe}}"
- Why it happens: "because it contains unsafe characters"
shared-module/packages/common/src/locales/fi/main-frontend.json (1)
563-563
: LGTM! Accurate and natural Finnish translation.
The Finnish translation:
- Maintains semantic equivalence with the English version
- Uses natural Finnish language constructs
- Correctly preserves the template variables
services/main-frontend/src/components/forms/NewReferenceForm.tsx (3)
88-92
: Error label messages are properly handled.
The logic to display changed citation labels is clear, helps the user see what changed, and indicates potential issues. Good job!
125-133
: Simple and effective reference validation.
The “areCitationsValid” function’s try/catch approach has good clarity: any parsing errors are gracefully handled by returning false. This is straightforward and maintains code clarity.
85-85
: Verify that "autoResize" is supported.
Please confirm that your text area component library or the underlying implementation (e.g., a custom TextAreaField) supports the "autoResize" prop. If not, it’s best to remove or replace it with a supported property.
✅ Verification successful
The search results show that autoResize
is a supported prop in the shared TextAreaField component located at shared-module/packages/common/src/components/InputFields/TextAreaField.tsx
. The component properly implements the auto-resize functionality through a prop interface and handles the resizing logic in its implementation. The prop is also being used consistently across multiple components in the codebase.
The autoResize
prop is properly supported by the TextAreaField component.
- The prop is defined in the component's interface:
autoResize?: boolean
- The implementation includes proper height adjustment logic when
autoResize
is enabled - The prop is used consistently across multiple form components in the codebase
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Searching for 'autoResize' usage in the codebase to confirm it's supported by the relevant component.
rg -A 3 'autoResize'
Length of output: 7750
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 (1)
services/course-material/src/components/exams/ExamStartBanner.tsx (1)
33-35
: Great UX improvement with the auto-scroll feature!The automatic scroll to top after exam start is a thoughtful UX enhancement. Consider adding a fallback for browsers that don't support smooth scrolling:
- window.scrollTo({ top: 0, behavior: "smooth" }) + try { + window.scrollTo({ top: 0, behavior: "smooth" }) + } catch (e) { + // Fallback for browsers that don't support smooth scrolling + window.scrollTo(0, 0) + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
services/course-material/src/components/exams/ExamStartBanner.tsx
(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
- GitHub Check: headless_lms
- GitHub Check: build
- GitHub Check: build-and-deploy
- GitHub Check: code-style
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
🔭 Outside diff range comments (1)
.github/workflows/system-tests-and-deploy.yml (1)
⚠️ Kubernetes version v1.30.0 is not recommendedThe action update to
manusa/[email protected]
is compatible, but Kubernetes v1.30.0 is a development version that hasn't been officially released yet. To ensure stability:
- Replace
kubernetes version: "v1.30.0"
withkubernetes version: "v1.29.x"
(latest stable version)🔗 Analysis chain
Line range hint
152-157
: Verify compatibility with the Minikube setup action update.The update to
manusa/[email protected]
is a significant version bump. Please ensure:
- Compatibility with the specified Minikube v1.33.1 and Kubernetes v1.30.0 versions
- Review of the changelog for any breaking changes that might affect the workflow
Run this script to check the compatibility matrix and changelog:
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Description: Check compatibility and changelog for the updated action version # Get the changelog and compatibility information gh api repos/manusa/actions-setup-minikube/releases/tags/v2.13.0 --jq '.body' || echo "Failed to fetch release notes" # Check if there are any reported issues with the specified versions gh search issues "repo:manusa/actions-setup-minikube minikube v1.33.1 kubernetes v1.30.0" --json title,body,urlLength of output: 670
Script:
#!/bin/bash # Check Minikube releases for version compatibility gh api repos/kubernetes/minikube/releases/tags/v1.33.1 --jq '.body' || echo "Failed to fetch Minikube release notes" # Search issues with correct syntax (quotes adjusted) gh search issues "repo:manusa/actions-setup-minikube is:issue kubernetes" --json title,body,url --limit 10 # Verify if v1.30.0 exists in Kubernetes releases gh api repos/kubernetes/kubernetes/releases/tags/v1.30.0 --jq '.tag_name' || echo "Kubernetes v1.30.0 not found"Length of output: 4552
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
.github/workflows/system-tests-and-deploy.yml
(1 hunks)services/headless-lms/models/src/library/progressing.rs
(1 hunks)
⏰ Context from checks skipped due to timeout of 90000ms (4)
- GitHub Check: build
- GitHub Check: headless_lms
- GitHub Check: build-and-deploy
- GitHub Check: code-style
Summary by CodeRabbit
New Features
Localization
Bug Fixes
Chores