-
Notifications
You must be signed in to change notification settings - Fork 61
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
feat(skilavottord): Add municipality #17109
base: main
Are you sure you want to change the base?
Conversation
WalkthroughThe pull request introduces significant changes to the role and permission management within the application. The 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
Documentation and Community
|
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #17109 +/- ##
==========================================
- Coverage 35.73% 35.70% -0.03%
==========================================
Files 6926 6950 +24
Lines 147681 148060 +379
Branches 42062 42108 +46
==========================================
+ Hits 52776 52871 +95
- Misses 94905 95189 +284
Flags with carried forward coverage won't be shown. Click here to find out more.
... and 276 files with indirect coverage changes Continue to review full report in Codecov by Sentry.
|
Datadog ReportAll test runs ✅ 4 Total Test Services: 0 Failed, 4 Passed Test Services
🔻 Code Coverage Decreases vs Default Branch (1)
|
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: 20
🧹 Outside diff range and nitpick comments (34)
apps/skilavottord/web/screens/AccessControl/components/AccessControlModal/AccessControlModal.tsx (5)
7-7
: Remove duplicate Option importThe
Option
type is imported individually and also as part of the destructured import from '@island.is/island-ui/core'.-import { Box, Button, Option, Select, Stack } from '@island.is/island-ui/core' +import { Box, Button, Select, Stack } from '@island.is/island-ui/core'
Line range hint
52-56
: Clarify the empty onContinue handlerThe empty onContinue handler in the Modal component could be confusing. Consider removing it if not needed, as the form submission is handled by the onSubmit prop.
- onContinue={() => { - // Intentionally left empty - }} + onContinue={undefined}
Line range hint
124-131
: Simplify email validation patternThe current email validation regex is complex and might miss some valid email formats. Consider using a simpler pattern or a dedicated email validation library.
pattern: { - value: - /^[\w!#$%&'*+/=?`{|}~^-]+(?:\.[\w!#$%&'*+/=?`{|}~^-]+)*@(?:[A-Z0-9-]+\.)+[A-Z]{2,6}$/i, + value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i, message: t.modal.inputs.email.rules?.validate, },
Line range hint
196-207
: Improve responsive design implementationThe Box component uses hardcoded padding values which might not scale well across different screen sizes. Consider using theme-based spacing values for better maintainability.
- <Box paddingX={[3, 3, 3, 15]}></Box> + <Box paddingX={[2, 3, 4, 5]}></Box>
Line range hint
30-209
: Add loading state handlingThe form submission lacks loading state handling, which could lead to multiple submissions. Consider adding a loading state to disable the form during submission.
You could:
- Add a loading prop to the component
- Disable the submit button and form inputs during submission
- Show a loading indicator
Would you like me to provide a detailed implementation?
apps/skilavottord/ws/seeders/20201010211010-seed-recycling-request.js (1)
Line range hint
1-96
: Consider adding documentation for test data scenariosThe seeder file contains various test scenarios (different request_types and recycling_partner_id states) but lacks documentation explaining the purpose of each scenario. Consider adding comments to explain:
- The significance of null vs non-null recycling_partner_id
- The progression of request_types
- The relationship between dates and states
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (3)
55-70
: Simplify conditional logic for route variablesThe logic setting
breadcrumbTitle
,title
,info
,activeSection
, androute
can be simplified for better readability and maintainability.Consider refactoring as follows:
const isMunicipality = router.route === routes.municipalities.add const { t: { recyclingCompanies: t, municipalities: mt, routes }, } = useI18n() const breadcrumbTitle = isMunicipality ? mt.title : t.title const title = isMunicipality ? mt.municipality.add.title : t.recyclingCompany.add.title const info = isMunicipality ? mt.municipality.add.info : t.recyclingCompany.add.info const activeSection = isMunicipality ? 1 : 2 const route = isMunicipality ? routes.municipalities.baseRoute : routes.recyclingCompanies.baseRoute
117-125
: Duplicate code in navigation after creationThe routing logic after a successful creation is duplicated for municipalities and recycling companies.
Refactor to eliminate duplication:
if (!errors) { - if (isMunicipality) { - router.push(routes.municipalities.baseRoute).then(() => { - toast.success(t.recyclingCompany.add.added) - }) - } else { - router.push(routes.recyclingCompanies.baseRoute).then(() => { - toast.success(t.recyclingCompany.add.added) - }) - } + router.push(route).then(() => { + toast.success(t.recyclingCompany.add.added) + }) }
129-135
: SimplifyhandleCancel
routing logicThe
handleCancel
function contains duplicated routing logic based onisMunicipality
.Refactor to use the
route
variable:const handleCancel = () => { - if (isMunicipality) { - router.push(routes.municipalities.baseRoute) - } else { - router.push(routes.recyclingCompanies.baseRoute) - } + router.push(route) }apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanies.tsx (2)
59-72
: Simplify context-based variablesThe variables
isMunicipality
,buttonText
,activeSection
,title
, andinfo
can be consolidated for clearer logic.Consider refactoring:
const isMunicipality = router.route === routes.municipalities.baseRoute const buttonText = isMunicipality ? t.buttons.addMunicipality : t.buttons.add const activeSection = isMunicipality ? 1 : 2 const title = isMunicipality ? mt.title : t.title const info = isMunicipality ? '' : t.info
101-109
: Duplicate code inhandleCreate
functionThe
handleCreate
function contains duplicated routing logic.Refactor to use the
routes
object based onisMunicipality
:const handleCreate = () => { router.push({ - pathname: isMunicipality ? routes.municipalities.add : routes.recyclingCompanies.add, + pathname: route.add, }) }Ensure you define
route
similarly to how it's done in other components.apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (3)
53-57
: Avoid unnecessary default assignmentThe default assignment
|| []
is unnecessary when usingskip
in the query.Remove the redundant assignment.
const { data } = - useQuery<Query>(SkilavottordAllRecyclingPartnersByTypeQuery, { + useQuery<Query>(SkilavottordAllRecyclingPartnersByTypeQuery, { skip: isMunicipality, variables: { isMunicipality: true }, }) - || []
278-311
: Conditional rendering might cause layout shiftConditional rendering of the
Select
component may cause layout shifts. Consider rendering the component but disabling it or hiding it with CSS to maintain consistent layout.Alternatively, adjust the layout to accommodate the dynamic content.
374-375
: Button icon mismatchThe
Button
component's icon has been changed tosave
. Ensure this aligns with the action, and consider using thearrowForward
icon for consistency unless saving is appropriate here.apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (1)
125-147
: Unused imports and variablesThere are unused imports and variables, such as
municipalities
,use
from 'dd-trace', and potentially others.Remove unused imports and variables to clean up the code.
apps/skilavottord/web/pages/en/municipalities/index.tsx (1)
1-5
: Consider improving type safety and import pathsWhile the implementation is functional, consider these improvements:
- Define the Screen type explicitly on the RecyclingCompanies component instead of using type casting
- Consider using path aliases for imports to improve maintainability
Example implementation:
- import { Screen } from '@island.is/skilavottord-web/types' + import { Screen } from '@types' - import { withLocale } from '@island.is/skilavottord-web/i18n' + import { withLocale } from '@i18n' - import { RecyclingCompanies } from '@island.is/skilavottord-web/screens' + import { RecyclingCompanies } from '@screens' - export default withLocale('en')(RecyclingCompanies as Screen) + export default withLocale('en')<Screen>(RecyclingCompanies)apps/skilavottord/web/pages/en/municipalities/add.tsx (1)
1-5
: Apply consistent type safety improvementsSimilar to the index page, consider improving type safety and import paths:
Example implementation:
- import { Screen } from '@island.is/skilavottord-web/types' + import { Screen } from '@types' - import { withLocale } from '@island.is/skilavottord-web/i18n' + import { withLocale } from '@i18n' - import { RecyclingCompanyCreate } from '@island.is/skilavottord-web/screens/RecyclingCompanies/RecyclingCompanyCreate' + import { RecyclingCompanyCreate } from '@screens/RecyclingCompanies/Create' - export default withLocale('en')(RecyclingCompanyCreate as Screen) + export default withLocale('en')<Screen>(RecyclingCompanyCreate)apps/skilavottord/web/pages/en/municipalities/[id].tsx (1)
1-5
: Consider creating a shared page componentThe code is identical to the Icelandic version except for the locale parameter. Consider creating a shared page component to reduce duplication:
+ // shared/MunicipalityPage.tsx + import { Screen } from '@island.is/skilavottord-web/types' + import { withLocale } from '@island.is/skilavottord-web/i18n' + import { RecyclingCompanyUpdate } from '@island.is/skilavottord-web/screens/RecyclingCompanies/RecyclingCompanyUpdate' + + export const createMunicipalityPage = (locale: string) => + withLocale(locale)(RecyclingCompanyUpdate as Screen)Then both locale pages could simply import and use this shared component:
import { createMunicipalityPage } from '../shared/MunicipalityPage' export default createMunicipalityPage('en') // or 'is'apps/skilavottord/ws/src/app/modules/auth/user.model.ts (1)
Line range hint
1-28
: Consider adding role documentationThe Role enum would benefit from JSDoc comments describing the permissions and responsibilities of each role, especially the newly added municipality role.
export enum Role { + /** System administrator with full access */ developer = 'developer', + /** Company that processes recycled vehicles */ recyclingCompany = 'recyclingCompany', + /** Administrative user for recycling companies */ recyclingCompanyAdmin = 'recyclingCompanyAdmin', + /** Recycling fund administrator */ recyclingFund = 'recyclingFund', + /** Regular user accessing the system */ citizen = 'citizen', + /** Municipality administrator with specific access rights */ municipality = 'municipality', }apps/skilavottord/web/components/PageHeader/PageHeader.tsx (2)
11-14
: Consider enhancing props interface documentationThe props interface could be more descriptive to improve maintainability.
-export const PageHeader: FC<{ title: string; info: string }> = ({ +interface PageHeaderProps { + /** Main heading text for the page */ + title: string; + /** Additional information to display in tooltip */ + info: string; +} + +export const PageHeader: FC<PageHeaderProps> = ({ title, info, }) => {
17-26
: Consider layout shift optimizationThe current order switching between mobile and desktop might cause layout shift during page load.
Consider using CSS Grid's
grid-template-areas
instead of order properties for a more stable layout that doesn't cause Content Layout Shift (CLS).apps/skilavottord/web/utils/roleUtils.ts (2)
18-19
: Enhance default case handlingThe default case using
startCase
might not be ideal for all future role values.- default: - return startCase(role) + default: { + console.warn(`Translation missing for role: ${role}`); + return startCase(role); + }
Missing test coverage for role translations
The codebase lacks dedicated test coverage for the
getRoleTranslation
utility function. While there is a test file in the web directory (locales.spec.ts
), it doesn't cover the role translations. The function handles critical UI text for different user roles, including the newly added municipality role, and should be properly tested for both Icelandic and English translations.Suggested actions:
- Create a new test file
roleUtils.spec.ts
inapps/skilavottord/web/utils/
- Add test cases covering all role translations in both languages
- Include specific test cases for the new municipality role translations ('Sveitarfélag'/'Municipality')
🔗 Analysis chain
Line range hint
6-20
: Verify test coverage for new role translationThe new municipality role translation needs test coverage to ensure correct behavior.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash # Check for existing test files and their coverage fd -e test.ts -e spec.ts roleUtils apps/skilavottord/web/utils/Length of output: 65
Script:
#!/bin/bash # Let's try a broader search for test files in the web directory fd -e test.ts -e spec.ts apps/skilavottord/web # Also search for any usage of getRoleTranslation in test files rg "getRoleTranslation" -t ts --glob "*test*" --glob "*spec*" # Search for any test files containing "role" or "Role" to ensure we don't miss any rg "role|Role" -t ts --glob "*test*" --glob "*spec*" apps/skilavottord/webLength of output: 577
Script:
#!/bin/bash # Search for test files in the correct way fd . apps/skilavottord/web -e test.ts -e spec.ts # Look for any test files containing Role enum ast-grep --pattern 'enum Role { $$$ }' # Search for any files importing roleUtils to see test coverage rg -l "from ['|\"].*roleUtils"Length of output: 1261
apps/skilavottord/web/components/NavigationLinks/NavigationLinks.tsx (2)
29-30
: Remove unnecessary template literalsTemplate literals are used unnecessarily for static string values. Since these strings don't contain any interpolation, they can be simplified.
- title: `${sidenavText.recycled}`, - link: `${routes.recycledVehicles}`, + title: sidenavText.recycled, + link: routes.recycledVehicles,Apply similar changes to other occurrences.
Also applies to: 34-35, 40-41, 45-46
7-11
: Define interface for component propsConsider extracting the props interface for better type documentation and reusability.
+interface NavigationLinksProps { + activeSection: number; +} + -export const NavigationLinks = ({ - activeSection, -}: { - activeSection: number -}) => { +export const NavigationLinks = ({ activeSection }: NavigationLinksProps) => {apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.model.ts (2)
108-108
: Standardize comment styleThe inline comment style differs from the rest of the file. Consider removing it since the
@Field
decorator withnullable: true
is self-documenting.- @Field({ nullable: true }) // Ensure this field is nullable in GraphQL + @Field({ nullable: true })
101-115
: Consider grouping related fieldsThe new municipality-related fields could be grouped with other identifying fields at the top of the model for better organization.
Consider moving these fields after the
companyId
field to keep related identifying fields together.apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.service.ts (1)
32-32
: Remove redundant commentThe comment restates what's evident from the code and parameter names.
- // If Role.municipality, return all recycling partners that are not municipalities
apps/skilavottord/ws/src/app/modules/vehicle/vehicle.resolver.ts (1)
21-32
: Consider improving role-based filtering logicWhile the role-based filtering is functionally correct, the logic could be more explicit and maintainable.
Consider refactoring to:
- partnerId: user.role === Role.municipality ? user.partnerId : null, + partnerId: user.role === Role.municipality + ? user.partnerId + : (user.role === Role.recyclingFund ? null : user.partnerId),This makes the intent clearer for each role and improves maintainability.
apps/skilavottord/ws/src/app/modules/vehicle/vehicle.service.ts (1)
Line range hint
43-65
: Consider implementing pagination optimizationThe current implementation might face performance issues with large datasets, especially when filtering across multiple partners.
Consider these optimizations:
- Add database indexes for frequently filtered columns
- Implement cursor-based pagination instead of offset-based
- Consider caching frequently accessed partner relationships
apps/skilavottord/ws/src/app/modules/accessControl/accessControl.resolver.ts (1)
20-25
: Consider organizing roles by privilege levelThe roles array would be more maintainable if organized by privilege level.
Consider reorganizing roles:
roles: [ Role.developer, Role.recyclingFund, + Role.municipality, Role.recyclingCompanyAdmin, - Role.municipality, ],apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (1)
149-151
: Add type validation for municipalityId.The current type checking could be more robust.
- if (typeof input.municipalityId !== 'string') { - input.municipalityId = input.municipalityId?.value || '' - } + input.municipalityId = typeof input.municipalityId === 'string' + ? input.municipalityId + : input.municipalityId?.value || ''apps/skilavottord/web/i18n/locales/is.json (2)
368-372
: Ensure consistent navigation structure.The new municipality-related entries in the sidenav section should maintain hierarchy consistency with other sections.
Consider this structure for better consistency:
"recyclingFundSidenav": { "title": "Úrvinnslusjóður", - "municipalityTitle": "Sveitarfélag", "recycled": "Meðhöndluð ökutæki", "companies": "Móttökuaðilar", "accessControl": "Aðgangsstýring", "municipalities": "Sveitarfélög" + "municipality": { + "title": "Sveitarfélag" + } }
415-425
: Improve form field labels and placeholders.The form input labels and placeholders for company ID and name could be more descriptive.
Consider these improvements:
"companyId": { - "label": "Auðkenni (ID)", - "placeholder": "Auðkenni", + "label": "Auðkenni fyrirtækis (ID)", + "placeholder": "Sláðu inn einkvæmt auðkenni", "rules": { "required": "Skylda er að fylla út auðkenni" } }, "companyName": { - "label": "Nafn", - "placeholder": "Nafn", + "label": "Nafn fyrirtækis", + "placeholder": "Sláðu inn nafn fyrirtækis", "rules": { "required": "Skylda er að fylla út nafn" } }
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
📒 Files selected for processing (33)
apps/skilavottord/web/auth/utils.ts
(1 hunks)apps/skilavottord/web/components/NavigationLinks/NavigationLinks.tsx
(1 hunks)apps/skilavottord/web/components/PageHeader/PageHeader.tsx
(1 hunks)apps/skilavottord/web/components/Sidenav/Sidenav.tsx
(3 hunks)apps/skilavottord/web/i18n/locales/en.json
(5 hunks)apps/skilavottord/web/i18n/locales/is.json
(5 hunks)apps/skilavottord/web/i18n/locales/translation.d.ts
(6 hunks)apps/skilavottord/web/pages/en/municipalities/[id].tsx
(1 hunks)apps/skilavottord/web/pages/en/municipalities/add.tsx
(1 hunks)apps/skilavottord/web/pages/en/municipalities/index.tsx
(1 hunks)apps/skilavottord/web/pages/municipalities/[id].tsx
(1 hunks)apps/skilavottord/web/pages/municipalities/add.tsx
(1 hunks)apps/skilavottord/web/pages/municipalities/index.tsx
(1 hunks)apps/skilavottord/web/screens/AccessControl/AccessControl.tsx
(8 hunks)apps/skilavottord/web/screens/AccessControl/components/AccessControlModal/AccessControlModal.tsx
(1 hunks)apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanies.tsx
(3 hunks)apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx
(5 hunks)apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx
(8 hunks)apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx
(5 hunks)apps/skilavottord/web/screens/RecyclingFund/Overview/Overview.tsx
(4 hunks)apps/skilavottord/web/utils/roleUtils.ts
(1 hunks)apps/skilavottord/ws/migrations/202412013210715-addcolumns-recycling-partners-municipality.js
(1 hunks)apps/skilavottord/ws/seeders/20201010211010-seed-recycling-request.js
(6 hunks)apps/skilavottord/ws/src/app/modules/accessControl/accessControl.resolver.ts
(2 hunks)apps/skilavottord/ws/src/app/modules/accessControl/accessControl.service.ts
(2 hunks)apps/skilavottord/ws/src/app/modules/auth/auth.guard.ts
(1 hunks)apps/skilavottord/ws/src/app/modules/auth/user.model.ts
(1 hunks)apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.input.ts
(2 hunks)apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.model.ts
(1 hunks)apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts
(4 hunks)apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.service.ts
(2 hunks)apps/skilavottord/ws/src/app/modules/vehicle/vehicle.resolver.ts
(1 hunks)apps/skilavottord/ws/src/app/modules/vehicle/vehicle.service.ts
(2 hunks)
🧰 Additional context used
📓 Path-based instructions (33)
apps/skilavottord/web/pages/en/municipalities/index.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/pages/municipalities/index.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/pages/municipalities/[id].tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/pages/en/municipalities/[id].tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/pages/en/municipalities/add.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/components/PageHeader/PageHeader.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/auth/user.model.ts (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/components/NavigationLinks/NavigationLinks.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/accessControl/accessControl.service.ts (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.service.ts (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/pages/municipalities/add.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/accessControl/accessControl.resolver.ts (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/migrations/202412013210715-addcolumns-recycling-partners-municipality.js (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.model.ts (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/auth/auth.guard.ts (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/AccessControl/components/AccessControlModal/AccessControlModal.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/utils/roleUtils.ts (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/components/Sidenav/Sidenav.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/vehicle/vehicle.service.ts (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.input.ts (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanies.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingFund/Overview/Overview.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/seeders/20201010211010-seed-recycling-request.js (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/auth/utils.ts (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/i18n/locales/is.json (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/vehicle/vehicle.resolver.ts (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/i18n/locales/en.json (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/i18n/locales/translation.d.ts (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
🔇 Additional comments (32)
apps/skilavottord/web/screens/AccessControl/components/AccessControlModal/AccessControlModal.tsx (1)
Line range hint 13-28
: Well-structured interface definition
The interface follows TypeScript best practices with proper type safety, clear prop definitions, and appropriate use of generics and utility types.
apps/skilavottord/ws/seeders/20201010211010-seed-recycling-request.js (2)
10-10
: Verify the new vehicle ID format against validation rules
The vehicle ID format has been changed from lowercase with hyphens (e.g., 'ftm-522') to uppercase without hyphens (e.g., 'VM006', 'LT579'). Please ensure this new format:
- Matches any validation rules in the application
- Aligns with the actual vehicle registration number format in Iceland
Also applies to: 19-19, 28-28, 46-46, 55-55, 64-64
✅ Verification successful
Based on the search results, I can see that:
-
The codebase has both old and new vehicle ID formats:
- Old format: lowercase with hyphens (e.g., 'jfk-433', 'ftm-522', 'mhs-583')
- New format: uppercase without hyphens (e.g., 'VM006', 'LT579', 'AE135')
-
The database schema and indexes support both formats as they use VARCHAR type.
-
There are no explicit validation rules found for vehicle ID format in the codebase.
Let me generate the final response:
Vehicle ID format change appears safe to proceed
The new uppercase format without hyphens is consistent with other vehicle IDs in the seeder files and is supported by the database schema. No explicit validation rules were found that would conflict with this format change.
- The database uses VARCHAR type for vehicle_id columns, which accommodates both formats
- Indexes are format-agnostic:
idx_vehicle_id
andidx_request_vehicle_id
- The repeated use of 'AE135' appears intentional for testing scenarios
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for vehicle ID validation patterns in the codebase
rg -g '!*.{json,md,lock}' -i 'vehicle.*validation|vehicle.*pattern|vehicle.*format'
# Look for any existing vehicle ID usage to confirm format consistency
rg -g '!*/seeders/*' 'vehicle_id.*[A-Z0-9]{2,}'
Length of output: 43261
28-28
: Confirm if repeated vehicle ID 'AE135' is intentional
The vehicle ID 'AE135' is used in three different recycling requests with different states:
- Line 28: Default state
- Line 46: 'pendingRecycle' state
- Line 55: 'handOver' state
This might be intentional for testing different states of the same vehicle, but please verify if this accurately represents your test scenarios.
Also applies to: 46-46, 55-55
✅ Verification successful
Multiple recycling requests for vehicle 'AE135' are intentionally seeded for testing state transitions
Looking at the seeder and migration files, this is a deliberate test data setup:
- The vehicle 'AE135' exists in the vehicle table (as 'aes-135')
- The recycling_request table has a foreign key constraint to vehicle table
- Multiple requests for the same vehicle show the progression through different states:
- Default state (initial request)
- 'pendingRecycle' state (in progress)
- 'handOver' state (completed)
This pattern is also seen with vehicle 'FZG90' which has both 'pendingRecycle' and 'handOver' states, confirming this is an intentional testing pattern.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check if multiple requests for the same vehicle are handled in the application
ast-grep --pattern 'function $FUNC($PARAMS) {
$$$
vehicle_id
$$$
}'
Length of output: 75
Script:
#!/bin/bash
# Search for files that handle recycling requests and vehicle IDs
rg -l "vehicle_id" --type js
# Check the content of relevant files for vehicle ID handling
rg "vehicle_id" -A 3 -B 3 --type js
# Look for any unique constraints or validations on vehicle_id
rg "unique.*vehicle_id|vehicle_id.*unique" --type js
Length of output: 15593
apps/skilavottord/web/pages/municipalities/index.tsx (2)
1-3
: LGTM! Clean and well-structured imports.
The imports are properly organized using absolute paths, which is good for maintainability.
5-5
: 🛠️ Refactor suggestion
Component name inconsistency and missing NextJS page structure.
- The component name
RecyclingCompanies
seems inconsistent with the page's purpose (municipalities). - The page lacks proper NextJS structure:
- Missing static or server-side data fetching methods
- Missing TypeScript interface for page props
- Type casting might indicate potential type safety issues
Consider refactoring to follow NextJS best practices:
import { Screen } from '@island.is/skilavottord-web/types'
import { withLocale } from '@island.is/skilavottord-web/i18n'
-import { RecyclingCompanies } from '@island.is/skilavottord-web/screens'
+import { Municipalities } from '@island.is/skilavottord-web/screens'
+
+interface MunicipalitiesPageProps {
+ // Add required props here
+}
+
+export const getServerSideProps = async () => {
+ // Fetch required data
+ return {
+ props: {
+ // Return fetched data
+ },
+ }
+}
-export default withLocale('is')(RecyclingCompanies as Screen)
+const MunicipalitiesPage: Screen<MunicipalitiesPageProps> = (props) => {
+ return <Municipalities {...props} />
+}
+
+export default withLocale('is')(MunicipalitiesPage)
Let's verify the component naming consistency and type safety:
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (1)
36-37
: Verify server-side handling of new mutation fields
The new fields isMunicipality
and municipalityId
have been added to the GraphQL mutation. Ensure that the server-side schema and resolvers are updated accordingly to handle these fields.
Run the following script to verify that the server-side schema includes the new fields:
✅ Verification successful
Server-side schema and resolvers are properly updated for new mutation fields
The server-side implementation correctly handles the new fields isMunicipality
and municipalityId
:
- The fields are properly defined in the database model (
RecyclingPartnerModel
) - They are included in the mutation input type (
CreateRecyclingPartnerInput
) - The resolver (
RecyclingPartnerResolver
) is configured to handle these fields in the create mutation
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check if the server-side GraphQL schema includes 'isMunicipality' and 'municipalityId' in the 'createSkilavottordRecyclingPartner' mutation.
# Fetch the GraphQL schema and search for the fields in the mutation input type.
curl -s http://localhost:3333/api/graphql -H "Content-Type: application/json" \
-d '{"query": "query { __type(name: \"CreateRecyclingPartnerInput\") { inputFields { name } } }"}' \
| jq '.data.__type.inputFields[].name' \
| grep -E 'isMunicipality|municipalityId'
Length of output: 259
Script:
#!/bin/bash
# Let's search for GraphQL schema files and mutations related to recycling partners
fd -e graphql -e gql | xargs cat
# Also search for TypeScript files that might contain the schema definition
rg -l "createSkilavottordRecyclingPartner|CreateRecyclingPartnerInput" --type=typescript
# Search for resolver implementations
ast-grep --pattern 'class $_ {
$$$
createSkilavottordRecyclingPartner($_) {
$$$
}
$$$
}'
Length of output: 69739
Script:
#!/bin/bash
# Let's try a different approach to find the schema and resolver files
fd -e ts | xargs rg -l "createSkilavottordRecyclingPartner|CreateRecyclingPartnerInput|isMunicipality|municipalityId"
# Also search for any GraphQL schema files
fd -e graphql | xargs rg "createSkilavottordRecyclingPartner|CreateRecyclingPartnerInput|isMunicipality|municipalityId"
Length of output: 4163
Script:
#!/bin/bash
# Let's examine the relevant files in the skilavottord app
cat apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.model.ts
cat apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.input.ts
cat apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts
Length of output: 6657
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanies.tsx (1)
80-88
:
Handle potential undefined user role
When accessing user.role
, ensure that user
is defined to prevent potential runtime errors.
Apply this diff to add a null check for user
:
const { data, error, loading } = useQuery<Query>(
SkilavottordAllRecyclingPartnersByTypeQuery,
{
variables: {
isMunicipality,
municipalityId: partnerId,
},
+ skip: !user,
},
)
Likely invalid or redundant comment.
apps/skilavottord/web/pages/municipalities/add.tsx (1)
1-5
: Verify language switching and apply consistent improvements
Similar improvements needed as the English version, plus ensure proper language switching is configured:
Example implementation:
- import { Screen } from '@island.is/skilavottord-web/types'
+ import { Screen } from '@types'
- import { withLocale } from '@island.is/skilavottord-web/i18n'
+ import { withLocale } from '@i18n'
- import { RecyclingCompanyCreate } from '@island.is/skilavottord-web/screens/RecyclingCompanies/RecyclingCompanyCreate'
+ import { RecyclingCompanyCreate } from '@screens/RecyclingCompanies/Create'
- export default withLocale('is')(RecyclingCompanyCreate as Screen)
+ export default withLocale('is')<Screen>(RecyclingCompanyCreate)
Let's verify the language switching configuration:
✅ Verification successful
Language switching is properly configured, but import paths can be improved
The language switching implementation is correctly set up:
- Both English and Icelandic versions exist with proper locale configuration
- The
withLocale
HOC is correctly implemented and used - Both versions use the same component with different locale parameters
The suggested import path improvements are valid and can be applied:
@island.is/skilavottord-web/types
→@types
@island.is/skilavottord-web/i18n
→@i18n
@island.is/skilavottord-web/screens/RecyclingCompanies/RecyclingCompanyCreate
→@screens/RecyclingCompanies/Create
The TypeScript generic syntax improvement (withLocale('is')<Screen>(RecyclingCompanyCreate)
) is also valid and would provide better type safety.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check if language switching is properly configured in next.config.js
echo "Checking Next.js i18n configuration..."
cat next.config.js | grep -A 10 "i18n:"
# Verify that both language versions are properly linked
echo "Checking for language switcher component usage..."
rg -l "LanguageSwitcher" apps/skilavottord/web/
Length of output: 330
Script:
#!/bin/bash
# Let's try to find the Next.js config file with different possible names and locations
echo "Searching for Next.js config files..."
fd -t f "next.config" apps/skilavottord/web/
# Check for i18n configuration in package.json as an alternative
echo "Checking package.json for i18n config..."
fd -t f "package.json" apps/skilavottord/web/ -x cat {} | jq -r '.i18n'
# Let's check for language-related components and configurations
echo "Checking for language-related files..."
rg -l "i18n|locale|language" apps/skilavottord/web/
# Check for the English version of the same page
echo "Checking for English version of municipalities/add..."
fd -t f "add.tsx" apps/skilavottord/web/pages/en/
Length of output: 5243
Script:
#!/bin/bash
# Let's check the Next.js config content for i18n settings
echo "Checking Next.js config content..."
cat apps/skilavottord/web/next.config.js
# Let's examine the i18n implementation
echo "Checking i18n implementation..."
cat apps/skilavottord/web/i18n/withLocale.tsx
# Compare both language versions of the add page
echo "Comparing both language versions..."
echo "=== Icelandic version ==="
cat apps/skilavottord/web/pages/municipalities/add.tsx
echo "=== English version ==="
cat apps/skilavottord/web/pages/en/municipalities/add.tsx
Length of output: 3552
apps/skilavottord/web/pages/municipalities/[id].tsx (1)
1-5
: Verify the reuse of RecyclingCompanyUpdate component
While the code follows NextJS conventions, we should verify if reusing the RecyclingCompanyUpdate component for municipalities is intentional and handles municipality-specific requirements correctly.
Additionally, consider adding error boundaries and loading states for better user experience.
✅ Verification successful
Let me gather more information about the RecyclingCompanyUpdate component to verify its usage.
Let me try a different approach to locate and verify the component usage.
Let me check the actual implementation of the RecyclingCompanyUpdate component.
Reuse of RecyclingCompanyUpdate component is intentional and properly implemented
The component is correctly designed to handle both recycling companies and municipalities through the isMunicipality
flag. It includes:
- Proper route detection (
router.route === routes.municipalities.edit
) - Municipality-specific UI adaptations (titles, breadcrumbs, navigation)
- Correct data handling for municipality role
- Proper permission checks
The component safely handles both use cases with appropriate conditional logic and type checking. No architectural changes are needed.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check if RecyclingCompanyUpdate component handles municipality role
ast-grep --pattern 'interface $_ {
$$$
municipality?: $_
$$$
}'
Length of output: 5527
Script:
#!/bin/bash
# Check RecyclingCompanyUpdate component implementation
ast-grep --pattern 'export const RecyclingCompanyUpdate = $_'
# Search for municipality-related props or types in the component
rg -A 5 "RecyclingCompanyUpdate" apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate.tsx
# Check if there are other municipality-specific components
fd "Municipality" apps/skilavottord/web
Length of output: 328
Script:
#!/bin/bash
# Find all files containing RecyclingCompanyUpdate
rg -l "RecyclingCompanyUpdate"
# Find municipality-related components and pages
fd -e tsx -e ts "municipality" -i
# Check imports in the municipality page
cat apps/skilavottord/web/pages/municipalities/[id].tsx
Length of output: 3650
Script:
#!/bin/bash
# Check the implementation of RecyclingCompanyUpdate component
cat apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx
# Check if there are separate components for municipalities
cat apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/index.tsx
Length of output: 6021
apps/skilavottord/ws/src/app/modules/auth/user.model.ts (1)
9-9
: Verify role-based access control implementation
The addition of the municipality role needs careful verification of access control implementation across the application.
✅ Verification successful
Let me gather more specific information about the RBAC implementation.
Let me check the specific roles guard implementation for the skilavottord application.
Role-based access control is properly implemented for the municipality role
The municipality role is correctly integrated into the existing RBAC system:
- The RolesGuard implementation properly validates user roles
- The role is used consistently in @authorize decorators alongside other administrative roles (developer, recyclingFund)
- All recycling partner operations (queries and mutations) properly include the municipality role in their access control
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check for proper RBAC implementation for municipality role
echo "Checking resolvers for municipality role authorization..."
rg -l "Role.municipality" --type ts
echo "\nChecking guards and decorators..."
ast-grep --pattern '@$_($$$)
export class $_ {
$$$
@$_([Role.municipality])
$$$
}'
Length of output: 1081
Script:
#!/bin/bash
# Check resolver implementations for municipality role
echo "Checking vehicle resolver implementation..."
rg -B 2 -A 5 "Role\.municipality" apps/skilavortord/ws/src/app/modules/vehicle/vehicle.resolver.ts
echo "\nChecking access control resolver implementation..."
rg -B 2 -A 5 "Role\.municipality" apps/skilavortord/ws/src/app/modules/accessControl/accessControl.resolver.ts
echo "\nChecking for role-based guards..."
rg -l "RolesGuard" --type ts
echo "\nChecking guard implementations..."
ast-grep --pattern 'class $_ implements CanActivate {
$$$
canActivate($$$) {
$$$
}
}'
Length of output: 9011
Script:
#!/bin/bash
# Check roles guard implementation in skilavottord
echo "Checking roles guard implementation..."
rg -B 2 -A 10 "class RolesGuard" apps/skilavottord/ws/src/app/modules/auth/roles.guard.ts
echo "\nChecking for roles decorator usage..."
rg -B 2 -A 5 "@Roles" apps/skilavottord/ws/src/app/modules/
echo "\nChecking recycling partner resolver for role checks..."
rg -B 2 -A 5 "Role\.municipality" apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts
Length of output: 2185
apps/skilavottord/ws/migrations/202412013210715-addcolumns-recycling-partners-municipality.js (1)
4-10
: Consider adding foreign key constraint
The municipality_id
column appears to reference municipalities but lacks a foreign key constraint.
Consider adding a foreign key constraint to ensure referential integrity:
ALTER TABLE recycling_partner
ADD CONSTRAINT fk_recycling_partner_municipality
FOREIGN KEY (municipality_id)
REFERENCES municipality(id);
Let's verify if the municipality table exists:
apps/skilavottord/web/auth/utils.ts (3)
21-28
: LGTM: Permission updates for recycling company roles
The removal of 'deregisterVehicleKM' from recycling company roles while maintaining essential permissions follows the principle of least privilege.
34-34
: LGTM: New municipality role with appropriate permissions
The new municipality role has been granted appropriate permissions for viewing recycled vehicles, recycling companies, and access control.
28-34
: Verify the impact of adding 'municipalities' permission
The addition of 'municipalities' to recyclingFund role's permissions needs verification to ensure all related UI components handle this new permission correctly.
✅ Verification successful
The addition of 'municipalities' permission is properly handled in the codebase
The codebase already has comprehensive support for the 'municipalities' permission:
- The permission is correctly added to the
recyclingFund
role inauth/utils.ts
- The UI components handling municipalities are properly implemented with permission checks:
- Navigation links in
NavigationLinks.tsx
handle municipality-related routes - Dedicated screens for municipalities exist with proper permission checks
- Form components in
RecyclingCompanyForm
handle municipality-specific fields - Role-based access control is implemented throughout the codebase
- Navigation links in
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for UI components that might need updates for the new 'municipalities' permission
rg -t tsx -t ts "municipalities" apps/skilavottord/web/
Length of output: 83
Script:
#!/bin/bash
# Search for UI components that might need updates for the new 'municipalities' permission
# Using ripgrep without file type restrictions and checking the entire web directory
rg "municipalities" apps/skilavottord/web/
# Also search for any components or code handling permissions
rg -A 3 "hasPermission|usePermissions" apps/skilavottord/web/
# Check for any routes or components related to municipalities
rg -i "municipality|municipalities" apps/skilavottord/web/
Length of output: 29796
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.input.ts (1)
44-45
: LGTM: Nullable configuration for municipalityId
The municipalityId
field is correctly configured as nullable in both the decorator and type.
apps/skilavottord/web/components/Sidenav/Sidenav.tsx (3)
3-7
: LGTM: Clean interface extension
The addition of the optional hidden
property to SidenavSection
interface follows TypeScript best practices.
16-16
: LGTM: Type extension for municipality icon
The SidenavIcon
type has been correctly extended to include the new municipality icon.
26-26
: LGTM: Clean conditional rendering
The section rendering logic has been updated to handle the new hidden
property while maintaining readability.
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.service.ts (1)
28-52
: Verify the handling of null values
The current implementation might need additional validation for edge cases.
✅ Verification successful
Null handling is properly implemented in the codebase
The code correctly handles null values for both isMunicipality
and municipalityId
fields:
- The model definition explicitly marks
municipalityId
as nullable withallowNull: true
- The GraphQL schema properly defines nullable fields with
@Field({ nullable: true })
- The service method correctly handles the OR condition for
isMunicipality: null
- The resolver properly defines nullable arguments with
nullable: true
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Check for potential null handling issues in the codebase
# Check for explicit null checks in similar service methods
rg -A 2 "findAll.*null" apps/skilavottord/ws/src/app/modules
# Check for related model validations
ast-grep --pattern 'allowNull: true' apps/skilavottord/ws/src/app/modules
Length of output: 138
Script:
#!/bin/bash
# Let's check the model definition and related files for null handling
# Find the recycling partner model definition
fd "recyclingPartner.*model" apps/skilavottord/ws/src
# Check for null handling in the model and related files
rg -g "*.ts" "isMunicipality.*null|municipalityId.*null" apps/skilavottord/ws/src/app/modules
# Check for any validation or type definitions
rg -g "*.ts" "interface.*RecyclingPartner|type.*RecyclingPartner" apps/skilavottord/ws/src
Length of output: 1598
Script:
#!/bin/bash
# Let's examine the model definition and input types
# Check the model definition
cat apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.model.ts
# Check the input types
rg -g "*.ts" -A 5 "RecyclingPartnerInput|CreateRecyclingPartnerInput|UpdateRecyclingPartnerInput" apps/skilavottord/ws/src/app/modules/recyclingPartner/
Length of output: 10114
apps/skilavottord/ws/src/app/modules/auth/auth.guard.ts (1)
80-80
:
Verify security implications of removing IdsUserGuard
The removal of IdsUserGuard
from the UseGuards
decorator could potentially impact authentication security. Please ensure this change aligns with the application's security requirements.
Consider keeping IdsUserGuard
for additional security layer or document why it's safe to remove.
apps/skilavottord/ws/src/app/modules/recyclingPartner/recyclingPartner.resolver.ts (1)
20-20
: Verify role-based access control implementation
The addition of Role.municipality
to multiple methods needs verification:
- Ensure proper access restrictions
- Verify that municipality users can only access their own data
Also applies to: 55-55, 66-66, 87-87
✅ Verification successful
Let me gather more information about the access control implementation specific to municipality role.
Let me check the recycling partner service implementation to understand how municipality data access is restricted.
Role-based access control is properly implemented for municipality users
The codebase shows appropriate access restrictions for municipality users:
- Municipality users can only access recycling partners that are not municipalities and belong to their municipality (filtered by municipalityId)
- Vehicle queries are restricted by partnerId when the user has municipality role
- The @authorize decorator properly enforces role-based access across resolvers
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for role checks in the codebase
rg "Role\.municipality" --type ts
# Look for access control implementations
ast-grep --pattern 'class $_ implements CanActivate {
$$$
canActivate($_) {
$$$
}
}'
Length of output: 4745
Script:
#!/bin/bash
# Check how municipality access is restricted in services
rg "Role\.municipality.*partnerId" -A 5 --type ts
# Look for partnerId checks in resolvers
ast-grep --pattern 'if ($user.role === Role.municipality) {
$$$
}'
# Check authorization decorator implementation
rg "@Authorize" -A 3 --type ts
Length of output: 9492
Script:
#!/bin/bash
# Check recycling partner service implementation
rg -A 10 "class RecyclingPartnerService" --type ts
# Look for municipality-specific filtering in the service
rg -A 10 "Role\.municipality.*return" --type ts
# Check how partnerId is used in queries
ast-grep --pattern 'findOne({
$$$
partnerId: $user.partnerId
$$$
})'
Length of output: 2637
apps/skilavottord/ws/src/app/modules/vehicle/vehicle.resolver.ts (1)
Line range hint 1-24
: Verify access control implications of new municipality role
The addition of the municipality role requires verification of access control boundaries.
✅ Verification successful
Let me gather more information about the authorization patterns in the codebase.
Municipality role access control implementation is properly bounded
The municipality role has been consistently implemented with appropriate access controls across the codebase:
- Access to
skilavottordAllDeregisteredVehicles
is properly restricted to[Role.developer, Role.recyclingFund, Role.municipality]
- Municipality role access is limited to specific endpoints in recycling partner operations
- The role's access is properly filtered using
partnerId
when querying vehicle data - No security implications found as the role follows the same authorization patterns as other roles in the system
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check for potential security implications of municipality role
# Look for other endpoints that might need municipality role
# Search for @Authorize decorators
rg -B 2 -A 2 "@Authorize\({"
# Search for role-based checks
rg "user\.role === "
Length of output: 4935
Script:
#!/bin/bash
# Search for Authorize decorators with better regex
rg "@Authorize\(" -A 2
# Search for municipality role usage
rg "Role\.municipality"
# Search for role-based mutations/queries in vehicle resolver
ast-grep --pattern $'@Authorize({ roles: [$$$] })
@$_($$$) $$$'
Length of output: 9010
apps/skilavottord/web/screens/RecyclingFund/Overview/Overview.tsx (2)
27-28
: LGTM: Component modernization improves maintainability.
The replacement of Sidenav
with NavigationLinks
and Box
with PageHeader
aligns with modern component architecture, improving code maintainability and reusability.
Also applies to: 121-121, 141-141
31-36
: Verify the impact of the required municipalityId parameter.
The GraphQL query now requires a municipalityId
parameter. This change could affect existing query implementations.
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (2)
122-124
: 🛠️ Refactor suggestion
Consider using useEffect dependency array properly.
The useEffect hook should include all dependencies it uses.
- React.useEffect(() => {
- setValue('isMunicipality', isMunicipality)
- }, [isMunicipality, setValue])
+ React.useEffect(() => {
+ setValue('isMunicipality', isMunicipality)
+ }, [isMunicipality, setValue])
Likely invalid or redundant comment.
81-87
: Verify role-based access control for municipality users.
The component now handles municipality-specific logic. Ensure proper access control is maintained.
✅ Verification successful
Let me analyze the role-based access control implementation for municipality users based on the search results. I can see comprehensive evidence of proper RBAC implementation across the codebase, but let me verify the specific authorization checks for recycling company operations.
Role-based access control for municipality users is properly implemented
The verification shows comprehensive and consistent RBAC implementation:
- Backend authorization is properly enforced through
@Authorize
decorators that explicitly includeRole.municipality
for relevant recycling partner operations - Frontend components correctly handle municipality-specific logic by:
- Filtering recycling companies based on
partnerId
- Implementing proper role checks before rendering components
- Maintaining proper access control in navigation and views
- Filtering recycling companies based on
The implementation in RecyclingCompanyUpdate.tsx
aligns with the overall RBAC architecture of the system.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check for proper role definitions and access control
rg -A 5 "Role.municipality"
Length of output: 12054
Script:
#!/bin/bash
# Check for authorization decorators and role checks in recycling partner related files
ast-grep --pattern 'Authorize({ roles: [$$$] })'
Length of output: 5015
apps/skilavottord/web/i18n/locales/en.json (1)
638-642
: LGTM: Well-structured route definitions.
The new municipality routes are properly structured and consistent with existing patterns.
apps/skilavottord/web/i18n/locales/translation.d.ts (5)
33-33
: LGTM! Proper type definition for municipalities.
The municipalities
property is correctly added to the Translation
interface.
477-492
: LGTM! Well-structured municipality interfaces.
The Municipalities
and Municipality
interfaces are properly defined with all necessary properties and follow the existing pattern.
517-517
: LGTM! Optional municipality field in form inputs.
The municipality
field is correctly added to the FormInputs
interface as an optional field.
560-564
: LGTM! Proper sidenav type definitions.
The municipalityTitle
and municipalities
properties are correctly added to the RecyclingFundSidenav
interface.
577-577
: LGTM! Route type definition for municipalities.
The municipalities
property is correctly added to the Routes
interface using the existing RecyclingCompaniesClass
type.
query: SkilavottordAllRecyclingPartnersByTypeQuery, | ||
variables: { isMunicipality, municipalityId: partnerId }, |
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.
Ensure refetchQueries variables are correctly set
In the refetchQueries
option of the useMutation
hook, confirm that the variables passed match the expected parameters of the query.
Verify that SkilavottordAllRecyclingPartnersByTypeQuery
accepts isMunicipality
and municipalityId
as variables and that they are correctly provided.
} = useForm({ | ||
mode: 'onChange', | ||
defaultValues: { isMunicipality, municipalityId: partnerId }, | ||
}) |
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.
Fix default values in useForm
The defaultValues
object should match the form's field names. Currently, municipalityId
is included even when isMunicipality
is true, which may cause unexpected behavior.
Apply this diff to conditionally set municipalityId
based on isMunicipality
:
useForm({
mode: 'onChange',
- defaultValues: { isMunicipality, municipalityId: partnerId },
+ defaultValues: isMunicipality
+ ? { isMunicipality }
+ : { isMunicipality, municipalityId: partnerId },
})
Committable suggestion skipped: line range outside the PR's diff.
let partnerId = null | ||
if (user?.role === Role.municipality) { | ||
partnerId = user?.partnerId | ||
} | ||
|
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.
Potential misalignment in partner ID assignment
Ensure that partnerId
is properly assigned when the user is a municipality to avoid unintended data fetching.
Confirm that user.partnerId
is correctly set and used.
...tord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx
Outdated
Show resolved
Hide resolved
const partners = | ||
recyclingPartnerData?.skilavottordAllRecyclingPartners || | ||
recyclingPartnerByIdData?.skilavottordAllRecyclingPartnersByType || | ||
[] |
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.
Potential confusion with partners data
The merger of data from different queries into partners
may lead to inconsistent data structures.
Ensure that the data from recyclingPartnerData
and recyclingPartnerByIdData
are compatible and properly handled.
let partnerIds = [] | ||
|
||
// Get all sub recycling partners of the municipality | ||
// else get all | ||
if (filter.partnerId) { | ||
// Get all sub recycling partners of the municipality | ||
const subRecyclingPartners = await RecyclingPartnerModel.findAll({ | ||
where: { municipalityId: filter.partnerId }, | ||
}) | ||
|
||
partnerIds = [ | ||
filter.partnerId, | ||
...subRecyclingPartners.map((partner) => partner.companyId), | ||
] | ||
} else { | ||
partnerIds = null | ||
} |
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 error handling and optimize database query
The current implementation has two issues:
- Missing error handling for the database query
- Potential N+1 query problem when fetching sub-partners
Consider refactoring to:
if (filter.partnerId) {
- // Get all sub recycling partners of the municipality
- const subRecyclingPartners = await RecyclingPartnerModel.findAll({
- where: { municipalityId: filter.partnerId },
- })
-
- partnerIds = [
- filter.partnerId,
- ...subRecyclingPartners.map((partner) => partner.companyId),
- ]
+ try {
+ const subRecyclingPartners = await RecyclingPartnerModel.findAll({
+ where: { municipalityId: filter.partnerId },
+ attributes: ['companyId'],
+ });
+
+ partnerIds = [
+ filter.partnerId,
+ ...subRecyclingPartners.map((partner) => partner.companyId),
+ ];
+ } catch (error) {
+ this.logger.error('Failed to fetch sub-partners:', error);
+ throw new Error('Failed to process municipality partners');
+ }
Committable suggestion skipped: line range outside the PR's diff.
|
||
if (user.role === Role.municipality) { | ||
return this.accessControlService.findByRecyclingPartner(user.partnerId) | ||
} | ||
|
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 error handling for municipality access control
The municipality-specific logic lacks error handling for the service call.
Consider adding error handling:
if (user.role === Role.municipality) {
+ try {
return this.accessControlService.findByRecyclingPartner(user.partnerId)
+ } catch (error) {
+ throw new ApolloError(
+ 'Failed to fetch municipality access controls',
+ 'MUNICIPALITY_ACCESS_ERROR'
+ )
+ }
}
📝 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.
if (user.role === Role.municipality) { | |
return this.accessControlService.findByRecyclingPartner(user.partnerId) | |
} | |
if (user.role === Role.municipality) { | |
try { | |
return this.accessControlService.findByRecyclingPartner(user.partnerId) | |
} catch (error) { | |
throw new ApolloError( | |
'Failed to fetch municipality access controls', | |
'MUNICIPALITY_ACCESS_ERROR' | |
) | |
} | |
} |
"view": { | ||
"title": "Municipality", | ||
"breadcrumb": "View", | ||
"info": "Þú getur annaðhvort uppfært eða eytt móttökuaðila. Vinsamlegast staðfestið að upplýsingar fyrirtækis séu rétt slegnar inn.", |
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.
Fix non-English content in English locale file.
These strings are in Icelandic instead of English:
- Line 650: "Þú getur annaðhvort uppfært eða eytt móttökuaðila..."
- Line 657: "Þegar nýju sveitarfélagi er bætt við..."
Also applies to: 657-657
"municipality": { | ||
"label": "Sveitarfélag", | ||
"placeholder": "Sveitarfélag" | ||
} |
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 validation rules for municipality field.
The municipality field in the recycling company form lacks validation rules, unlike other required fields.
Add validation rules:
"municipality": {
"label": "Sveitarfélag",
- "placeholder": "Sveitarfélag"
+ "placeholder": "Sveitarfélag",
+ "rules": {
+ "required": "Skylda er að fylla út sveitarfélag"
+ }
}
📝 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.
"municipality": { | |
"label": "Sveitarfélag", | |
"placeholder": "Sveitarfélag" | |
} | |
"municipality": { | |
"label": "Sveitarfélag", | |
"placeholder": "Sveitarfélag", | |
"rules": { | |
"required": "Skylda er að fylla út sveitarfélag" | |
} | |
} |
"municipalities": { | ||
"baseRoute": "/municipalities", | ||
"add": "/municipalities/add", | ||
"edit": "/municipalities/[id]" | ||
} | ||
}, | ||
"municipalities": { | ||
"title": "Sveitarfélög", | ||
"municipality": { | ||
"view": { | ||
"title": "Sveitarfélag", | ||
"breadcrumb": "Skoða", | ||
"info": "Þú getur annaðhvort uppfært eða eytt móttökuaðila. Vinsamlegast staðfestið að upplýsingar fyrirtækis séu rétt slegnar inn.", | ||
"updated": "Uppfært", | ||
"deleted": "Eytt" | ||
}, | ||
"add": { | ||
"title": "Bæta við sveitarfélagi", | ||
"breadcrumb": "Bæta við", | ||
"info": "Þegar nýju sveitarfélagi er bætt við, verður það aðgengilegt í aðgangsstýringu. Vinsamlegast staðfestið að upplýsingar sveitarfélags séu rétt slegnar inn.", | ||
"added": "Bætt við" | ||
} |
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.
Complete the municipality management section.
The municipality section is missing several essential elements:
- Table headers for the municipality list view
- Status indicators
- Action button translations
- Form input definitions
Add the missing translations:
"municipalities": {
"title": "Sveitarfélög",
+ "info": "Upplýsingar um skráð sveitarfélög.",
+ "empty": "Ekkert sveitarfélag fannst",
+ "tableHeaders": {
+ "name": "Nafn",
+ "address": "Heimilisfang",
+ "postnumber": "Póstnúmer",
+ "email": "Netfang",
+ "status": "Staða"
+ },
+ "status": {
+ "active": "Virkt",
+ "inactive": "Óvirkt"
+ },
+ "buttons": {
+ "add": "Bæta við sveitarfélagi",
+ "edit": "Breyta",
+ "delete": "Eyða"
+ },
"municipality": {
"view": {
"title": "Sveitarfélag",
"breadcrumb": "Skoða",
- "info": "Þú getur annaðhvort uppfært eða eytt móttökuaðila. Vinsamlegast staðfestið að upplýsingar fyrirtækis séu rétt slegnar inn.",
+ "info": "Þú getur annaðhvort uppfært eða eytt sveitarfélagi. Vinsamlegast staðfestið að upplýsingar sveitarfélags séu rétt slegnar inn.",
"updated": "Uppfært",
"deleted": "Eytt"
},
"add": {
"title": "Bæta við sveitarfélagi",
"breadcrumb": "Bæta við",
"info": "Þegar nýju sveitarfélagi er bætt við, verður það aðgengilegt í aðgangsstýringu. Vinsamlegast staðfestið að upplýsingar sveitarfélags séu rétt slegnar inn.",
"added": "Bætt við"
- }
+ },
+ "form": {
+ "inputs": {
+ "name": {
+ "label": "Nafn",
+ "placeholder": "Nafn sveitarfélags",
+ "rules": {
+ "required": "Skylda er að fylla út nafn"
+ }
+ },
+ "email": {
+ "label": "Netfang",
+ "placeholder": "Netfang",
+ "rules": {
+ "required": "Skylda er að fylla út netfang",
+ "validate": "Netfang er ekki á réttu formi"
+ }
+ }
+ }
+ }
}
}
📝 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.
"municipalities": { | |
"baseRoute": "/municipalities", | |
"add": "/municipalities/add", | |
"edit": "/municipalities/[id]" | |
} | |
}, | |
"municipalities": { | |
"title": "Sveitarfélög", | |
"municipality": { | |
"view": { | |
"title": "Sveitarfélag", | |
"breadcrumb": "Skoða", | |
"info": "Þú getur annaðhvort uppfært eða eytt móttökuaðila. Vinsamlegast staðfestið að upplýsingar fyrirtækis séu rétt slegnar inn.", | |
"updated": "Uppfært", | |
"deleted": "Eytt" | |
}, | |
"add": { | |
"title": "Bæta við sveitarfélagi", | |
"breadcrumb": "Bæta við", | |
"info": "Þegar nýju sveitarfélagi er bætt við, verður það aðgengilegt í aðgangsstýringu. Vinsamlegast staðfestið að upplýsingar sveitarfélags séu rétt slegnar inn.", | |
"added": "Bætt við" | |
} | |
"municipalities": { | |
"baseRoute": "/municipalities", | |
"add": "/municipalities/add", | |
"edit": "/municipalities/[id]" | |
} | |
}, | |
"municipalities": { | |
"title": "Sveitarfélög", | |
"info": "Upplýsingar um skráð sveitarfélög.", | |
"empty": "Ekkert sveitarfélag fannst", | |
"tableHeaders": { | |
"name": "Nafn", | |
"address": "Heimilisfang", | |
"postnumber": "Póstnúmer", | |
"email": "Netfang", | |
"status": "Staða" | |
}, | |
"status": { | |
"active": "Virkt", | |
"inactive": "Óvirkt" | |
}, | |
"buttons": { | |
"add": "Bæta við sveitarfélagi", | |
"edit": "Breyta", | |
"delete": "Eyða" | |
}, | |
"municipality": { | |
"view": { | |
"title": "Sveitarfélag", | |
"breadcrumb": "Skoða", | |
"info": "Þú getur annaðhvort uppfært eða eytt sveitarfélagi. Vinsamlegast staðfestið að upplýsingar sveitarfélags séu rétt slegnar inn.", | |
"updated": "Uppfært", | |
"deleted": "Eytt" | |
}, | |
"add": { | |
"title": "Bæta við sveitarfélagi", | |
"breadcrumb": "Bæta við", | |
"info": "Þegar nýju sveitarfélagi er bætt við, verður það aðgengilegt í aðgangsstýringu. Vinsamlegast staðfestið að upplýsingar sveitarfélags séu rétt slegnar inn.", | |
"added": "Bætt við" | |
}, | |
"form": { | |
"inputs": { | |
"name": { | |
"label": "Nafn", | |
"placeholder": "Nafn sveitarfélags", | |
"rules": { | |
"required": "Skylda er að fylla út nafn" | |
} | |
}, | |
"email": { | |
"label": "Netfang", | |
"placeholder": "Netfang", | |
"rules": { | |
"required": "Skylda er að fylla út netfang", | |
"validate": "Netfang er ekki á réttu formi" | |
} | |
} | |
} | |
} | |
} |
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
🧹 Outside diff range and nitpick comments (8)
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (3)
84-90
: Consider a more robust route checkThe current route check for
isMunicipality
is tightly coupled to the exact route path. Consider using a more maintainable approach.Consider this alternative:
- const isMunicipality = router.route === routes.municipalities.edit + const isMunicipality = router.route.startsWith(routes.municipalities.baseRoute)
119-124
: Move string literals to translation constantsConsider moving the hardcoded section number and route to translation constants for better maintainability.
Example approach:
const SECTIONS = { RECYCLING_COMPANIES: 2, MUNICIPALITIES: 1, } as const
Line range hint
156-164
: Enhance error handling in mutation responseThe current error handling doesn't provide user feedback when the mutation fails.
Add error handling:
const { errors } = await updateSkilavottordRecyclingPartner({ variables: { input }, }) if (!errors) { router.push(routes.recyclingCompanies.baseRoute).then(() => { toast.success(t.recyclingCompany.view.updated) }) + } else { + toast.error(t.recyclingCompany.view.updateError) }🧰 Tools
🪛 Biome (1.9.4)
[error] 150-150: Avoid the delete operator which can impact performance.
Unsafe fix: Use an undefined assignment instead.
(lint/performance/noDelete)
apps/skilavottord/web/components/NavigationLinks/NavigationLinks.tsx (2)
12-21
: Consider adding null safety to role checkThe role check could be made more robust by adding null safety:
- if (hasMunicipalityRole(user?.role)) { + if (user?.role && hasMunicipalityRole(user.role)) {
23-52
: Remove unnecessary template literalsTemplate literals are used unnecessarily for static strings in the sections array.
- title: `${sidenavText.recycled}`, - link: `${routes.recycledVehicles}`, + title: sidenavText.recycled, + link: routes.recycledVehicles,apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (1)
58-73
: Consider extracting route comparison logicThe route comparison could be made more maintainable by using a constant.
+const MUNICIPALITY_ROUTE = routes.municipalities.add; + -const isMunicipality = router.route === routes.municipalities.add +const isMunicipality = router.route === MUNICIPALITY_ROUTEapps/skilavottord/web/screens/AccessControl/AccessControl.tsx (2)
123-145
: Consolidate data fetching logic for recycling partnersThe current implementation uses two separate
useLazyQuery
hooks (getAllRecyclingPartner
andgetAllRecyclingPartnersByMunicipality
) to fetch recycling partner data based on the user's role. This can be simplified by combining the logic into a single hook or function that handles the condition internally. This will reduce code duplication and improve maintainability.Consider refactoring as follows:
- const [ - getAllRecyclingPartner, - { - data: recyclingPartnerData, - error: recyclingPartnerError, - loading: recyclingPartnerLoading, - }, - ] = useLazyQuery<Query>(SkilavottordAllRecyclingPartnersQuery, { - ssr: false, - }) - - const [ - getAllRecyclingPartnersByMunicipality, - { - data: recyclingPartnerByIdData, - error: recyclingPartnerByIdError, - loading: recyclingPartnerByIdLoading, - }, - ] = useLazyQuery<Query>(SkilavottordAllRecyclingPartnersByTypeQuery, { - ssr: false, - variables: { isMunicipality: false, municipalityId: user?.partnerId }, - }) + const [ + getRecyclingPartners, + { + data: recyclingPartnerData, + error: recyclingPartnerError, + loading: recyclingPartnerLoading, + }, + ] = useLazyQuery<Query>( + user.role === Role.municipality + ? SkilavottordAllRecyclingPartnersByTypeQuery + : SkilavottordAllRecyclingPartnersQuery, + { + ssr: false, + variables: + user.role === Role.municipality + ? { isMunicipality: false, municipalityId: user?.partnerId } + : {}, + }, + )
226-228
: Handle undefinedmunicipalityId
safely in labelsIn constructing the
label
forrecyclingPartners
, the ternary check onpartner.municipalityId
should ensure that undefined or null values are handled properly to avoid displayingundefined - companyName
.Consider using a more robust nullish coalescing operator:
- label: partner.municipalityId + label: partner.municipalityId ?? ''Or adjust the ternary condition:
- label: partner.municipalityId + label: partner.municipalityId
📜 Review details
Configuration used: .coderabbit.yaml
Review profile: CHILL
📒 Files selected for processing (9)
apps/skilavottord/web/auth/utils.ts
(1 hunks)apps/skilavottord/web/components/NavigationLinks/NavigationLinks.tsx
(1 hunks)apps/skilavottord/web/screens/AccessControl/AccessControl.tsx
(9 hunks)apps/skilavottord/web/screens/AccessControlCompany/AccessControlCompany.tsx
(2 hunks)apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanies.tsx
(3 hunks)apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx
(5 hunks)apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx
(8 hunks)apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx
(5 hunks)apps/skilavottord/ws/src/app/modules/accessControl/accessControl.service.ts
(2 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- apps/skilavottord/web/auth/utils.ts
👮 Files not reviewed due to content moderation or server errors (2)
- apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx
- apps/skilavottord/web/screens/AccessControlCompany/AccessControlCompany.tsx
🧰 Additional context used
📓 Path-based instructions (8)
apps/skilavottord/web/components/NavigationLinks/NavigationLinks.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/ws/src/app/modules/accessControl/accessControl.service.ts (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/AccessControlCompany/AccessControlCompany.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanies.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (1)
Pattern apps/**/*
: "Confirm that the code adheres to the following:
- NextJS best practices, including file structure, API routes, and static generation methods.
- Efficient state management and server-side rendering techniques.
- Optimal use of TypeScript for component and utility type safety."
📓 Learnings (1)
apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx (1)
Learnt from: birkirkristmunds
PR: island-is/island.is#17109
File: apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx:336-360
Timestamp: 2024-12-10T15:10:49.998Z
Learning: In the `RecyclingCompanyForm` component (`apps/skilavottord/web/screens/RecyclingCompanies/components/RecyclingCompanyForm/RecyclingCompanyForm.tsx`), the `isMunicipality` checkbox must remain in the DOM for all users since its value is stored in the database. However, only users with the developer role can manipulate it through the UI. This ensures that the checkbox value is maintained correctly while restricting interaction to authorized users.
🔇 Additional comments (12)
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyUpdate/RecyclingCompanyUpdate.tsx (2)
Line range hint 169-205
: Well-structured component rendering
The component rendering follows NextJS best practices with:
- Proper loading state handling
- Consistent layout structure
- Clear component composition
112-114
: Add null check for partnerId in refetchQueries
The partnerId
could be undefined when passed to the refetch query, which might cause unexpected behavior.
Let's verify the handling of undefined partnerId in the codebase:
apps/skilavottord/web/components/NavigationLinks/NavigationLinks.tsx (1)
1-11
: LGTM! Clean imports and well-typed props.
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanyCreate/RecyclingCompanyCreate.tsx (1)
39-40
: LGTM! Proper mutation field additions
The new fields isMunicipality
and municipalityId
are correctly added to the mutation response type.
apps/skilavottord/web/screens/RecyclingCompanies/RecyclingCompanies.tsx (3)
33-49
: LGTM! Well-structured GraphQL query
The new query properly handles type-specific filtering with correct variable types.
77-81
: Add null check for municipality role handling
This addresses a previously identified issue with partner ID assignment.
- if (hasMunicipalityRole(user?.role)) {
+ if (user?.role && hasMunicipalityRole(user.role)) {
104-126
: 🛠️ Refactor suggestion
Refactor routing logic and investigate BASE-PATH issue
- The routing logic is duplicated between
handleCreate
andhandleUpdate
- There's a comment about BASE-PATH duplication that needs investigation
Suggested refactor:
+ const getRoutePath = (type: 'create' | 'edit', id?: string) => {
+ const base = isMunicipality ? routes.municipalities : routes.recyclingCompanies;
+ const path = type === 'create' ? base.add : base.edit;
+ return id ? { pathname: path, query: { id } } : { pathname: path };
+ }
const handleCreate = () => {
- if (isMunicipality) {
- router.push({
- pathname: routes.municipalities.add,
- })
- } else {
- router.push({
- pathname: routes.recyclingCompanies.add,
- })
- }
+ router.push(getRoutePath('create'));
}
const handleUpdate = (id: string) => {
- if (isMunicipality) {
- router.push({
- pathname: routes.municipalities.edit,
- query: { id },
- })
- } else {
- router.push({
- pathname: routes.recyclingCompanies.edit,
- query: { id },
- })
- }
+ router.push(getRoutePath('edit', id));
}
apps/skilavottord/web/screens/AccessControl/AccessControl.tsx (3)
221-224
: Ensure consistency of partners
data structure
Merging data from recyclingPartnerData
and recyclingPartnerByIdData
into partners
may lead to inconsistent data structures if the returned data differs. Verify that both data sources return data in the same format and handle any discrepancies to prevent runtime errors.
234-247
: Simplify roles filtering logic for better readability
The current roles filtering logic involves multiple filters and conditions, which can be simplified to enhance readability and maintainability.
Consider refactoring:
const roles = Object.keys(AccessControlRole)
.filter((role) => {
if (!hasDeveloperRole(user?.role) && role === Role.developer) {
return false
}
if (user.role === Role.municipality) {
return [Role.recyclingCompany, Role.recyclingCompanyAdmin, Role.municipality].includes(role)
}
return true
})
.map((role) => ({
label: getRoleTranslation(role as Role, activeLocale),
value: role,
}))
255-263
: Ensure partners data is fetched before opening modal
When opening the create access control modal, ensure that the partners data is fetched before rendering the modal to prevent potential undefined data issues.
Consider adding a loading state or disabling the button until data is ready.
apps/skilavottord/ws/src/app/modules/accessControl/accessControl.service.ts (2)
68-69
: Optimize database query for large partnerIds
arrays
Using the IN
operator with a potentially large partnerIds
array can lead to performance issues. Consider implementing pagination, batching, or alternative querying strategies for handling large datasets.
37-66
:
Add safeguards to recursive getAllCompanyIds
function
The recursive getAllCompanyIds
function lacks protection against circular references and unchecked recursion depth, which could lead to stack overflows or performance issues.
Implement safeguards by tracking visited partnerId
s and limiting recursion depth:
- const getAllCompanyIds = async (partnerId: string) => {
- partnerIds.push(partnerId)
- const subCompanies = await RecyclingPartnerModel.findAll({
- where: { municipalityId: partnerId },
- })
- for (const subCompany of subCompanies) {
- await getAllCompanyIds(subCompany.companyId)
- }
- }
+ const getAllCompanyIds = async (
+ partnerId: string,
+ visited = new Set<string>(),
+ depth = 0,
+ ) => {
+ const MAX_DEPTH = 100
+ if (depth > MAX_DEPTH || visited.has(partnerId)) return
+ visited.add(partnerId)
+ partnerIds.push(partnerId)
+ const subCompanies = await RecyclingPartnerModel.findAll({
+ where: { municipalityId: partnerId },
+ })
+ for (const subCompany of subCompanies) {
+ await getAllCompanyIds(subCompany.companyId, visited, depth + 1)
+ }
+ }
phone | ||
active | ||
municipalityId |
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 municipalityId to the mutation response
The municipalityId
field is included in the query response but missing in the mutation response. This inconsistency could lead to stale data after updates.
Apply this diff to add the missing field:
mutation updateSkilavottordRecyclingPartnerMutation(
$input: UpdateRecyclingPartnerInput!
) {
updateSkilavottordRecyclingPartner(input: $input) {
companyId
companyName
nationalId
email
address
postnumber
city
website
phone
active
+ municipalityId
}
}
Also applies to: 47-63
if (typeof input.municipalityId !== 'string') { | ||
input.municipalityId = input.municipalityId?.value || '' | ||
} |
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
Improve municipalityId type handling
The current type conversion could be more robust with explicit type checking.
Consider this safer approach:
- if (typeof input.municipalityId !== 'string') {
- input.municipalityId = input.municipalityId?.value || ''
- }
+ const municipalityId = input.municipalityId
+ input.municipalityId = typeof municipalityId === 'object' && municipalityId?.value
+ ? municipalityId.value
+ : (municipalityId as string) || ''
📝 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.
if (typeof input.municipalityId !== 'string') { | |
input.municipalityId = input.municipalityId?.value || '' | |
} | |
const municipalityId = input.municipalityId | |
input.municipalityId = typeof municipalityId === 'object' && municipalityId?.value | |
? municipalityId.value | |
: (municipalityId as string) || '' |
if (typeof input.municipalityId !== 'string') { | ||
input.municipalityId = input.municipalityId?.value || '' | ||
} | ||
|
||
const { errors } = await createSkilavottordRecyclingPartner({ | ||
variables: { input: { ...input, active: !!input.active } }, | ||
variables: { | ||
input: { | ||
...input, | ||
active: !!input.active, | ||
isMunicipality: !!input.isMunicipality, | ||
}, | ||
}, | ||
}) | ||
if (!errors) { | ||
router.push(routes.recyclingCompanies.baseRoute).then(() => { | ||
toast.success(t.recyclingCompany.add.added) | ||
}) | ||
if (isMunicipality) { | ||
router.push(routes.municipalities.baseRoute).then(() => { | ||
toast.success(t.recyclingCompany.add.added) | ||
}) | ||
} else { | ||
router.push(routes.recyclingCompanies.baseRoute).then(() => { | ||
toast.success(t.recyclingCompany.add.added) | ||
}) | ||
} |
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
Refactor success handling and type conversion
Two improvements could be made:
- The success message is duplicated
- The type conversion could be more robust
- if (isMunicipality) {
- router.push(routes.municipalities.baseRoute).then(() => {
- toast.success(t.recyclingCompany.add.added)
- })
- } else {
- router.push(routes.recyclingCompanies.baseRoute).then(() => {
- toast.success(t.recyclingCompany.add.added)
- })
- }
+ const route = isMunicipality
+ ? routes.municipalities.baseRoute
+ : routes.recyclingCompanies.baseRoute;
+ router.push(route).then(() => {
+ toast.success(t.recyclingCompany.add.added)
+ })
Also, consider adding type validation:
- if (typeof input.municipalityId !== 'string') {
+ if (input.municipalityId && typeof input.municipalityId !== 'string') {
📝 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.
if (typeof input.municipalityId !== 'string') { | |
input.municipalityId = input.municipalityId?.value || '' | |
} | |
const { errors } = await createSkilavottordRecyclingPartner({ | |
variables: { input: { ...input, active: !!input.active } }, | |
variables: { | |
input: { | |
...input, | |
active: !!input.active, | |
isMunicipality: !!input.isMunicipality, | |
}, | |
}, | |
}) | |
if (!errors) { | |
router.push(routes.recyclingCompanies.baseRoute).then(() => { | |
toast.success(t.recyclingCompany.add.added) | |
}) | |
if (isMunicipality) { | |
router.push(routes.municipalities.baseRoute).then(() => { | |
toast.success(t.recyclingCompany.add.added) | |
}) | |
} else { | |
router.push(routes.recyclingCompanies.baseRoute).then(() => { | |
toast.success(t.recyclingCompany.add.added) | |
}) | |
} | |
if (input.municipalityId && typeof input.municipalityId !== 'string') { | |
input.municipalityId = input.municipalityId?.value || '' | |
} | |
const { errors } = await createSkilavottordRecyclingPartner({ | |
variables: { | |
input: { | |
...input, | |
active: !!input.active, | |
isMunicipality: !!input.isMunicipality, | |
}, | |
}, | |
}) | |
if (!errors) { | |
const route = isMunicipality | |
? routes.municipalities.baseRoute | |
: routes.recyclingCompanies.baseRoute; | |
router.push(route).then(() => { | |
toast.success(t.recyclingCompany.add.added) | |
}) | |
} |
recyclingPartnerError || accessControlsError || recyclingPartnerByIdError | ||
const loading = | ||
recyclingPartnerLoading || | ||
accessControlsLoading || | ||
recyclingPartnerByIdLoading | ||
const isData = !!recyclingPartnerData || !!accessControlsData |
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
Include all data sources in isData
check
The isData
constant currently checks for recyclingPartnerData
and accessControlsData
. Since recyclingPartnerByIdData
is also a potential data source for partners, it should be included in the isData
condition to ensure that all necessary data is loaded before rendering.
Apply this diff to include recyclingPartnerByIdData
:
- const isData = !!recyclingPartnerData || !!accessControlsData
+ const isData = !!recyclingPartnerData || !!recyclingPartnerByIdData || !!accessControlsData
📝 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.
recyclingPartnerError || accessControlsError || recyclingPartnerByIdError | |
const loading = | |
recyclingPartnerLoading || | |
accessControlsLoading || | |
recyclingPartnerByIdLoading | |
const isData = !!recyclingPartnerData || !!accessControlsData | |
recyclingPartnerError || accessControlsError || recyclingPartnerByIdError | |
const loading = | |
recyclingPartnerLoading || | |
accessControlsLoading || | |
recyclingPartnerByIdLoading | |
const isData = !!recyclingPartnerData || !!recyclingPartnerByIdData || !!accessControlsData |
...
Attach a link to issue if relevant
What
Specify what you're trying to achieve
Why
Specify why you need to achieve this
Screenshots / Gifs
Attach Screenshots / Gifs to help reviewers understand the scope of the pull request
Checklist:
Summary by CodeRabbit
Release Notes
New Features
Enhancements
Bug Fixes
Documentation