Skip to content

Conversation

@JustinTan-1
Copy link
Contributor

@JustinTan-1 JustinTan-1 commented Feb 5, 2026

Created frontend form for trip surveys.

image

Summary by CodeRabbit

  • New Features

    • Responsive survey modal that expands to full-screen on small devices.
    • Trip survey form capturing destination, departure/arrival times, odometer readings, location-change toggle, passenger rating, and comments.
    • New visual rating icons for passenger satisfaction feedback.
  • Style

    • Custom styling and layout tweaks for the survey modal and form controls.

@vercel
Copy link

vercel bot commented Feb 5, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
salvationarmy Ready Ready Preview, Comment Feb 9, 2026 9:45pm

@JustinTan-1 JustinTan-1 changed the title Implement trip survey frontend modal SANC 31 - Implement trip survey frontend modal Feb 5, 2026
@JustinTan-1 JustinTan-1 changed the title SANC 31 - Implement trip survey frontend modal SANC-31: Implement trip survey frontend modal Feb 5, 2026
@coderabbitai
Copy link

coderabbitai bot commented Feb 5, 2026

📝 Walkthrough

Walkthrough

Adds a new TripSurveyModal component with styles and five rating SVG icons, integrates it into the survey notification flow, and makes the common modal responsive by enabling fullscreen on viewports <=50em via a media query.

Changes

Cohort / File(s) Summary
Modal Responsiveness
src/app/_components/common/modal/modal.tsx
Imported useMediaQuery and pass isMobile to MantineModal fullScreen to enable fullscreen on small viewports.
Trip Survey Modal
src/app/_components/drivercomponents/TripSurveyModal.tsx, src/app/_components/drivercomponents/TripSurveyModal.module.scss
New named export TripSurveyModal: full driver survey form (trip status, destination, departure/arrival DateTimePickers with constraints, odometer fields, location-changed control, passenger rating with custom icons, notes) plus SCSS module with layout and Mantine overrides.
Rating Icons
src/assets/icons/rating1.tsx, src/assets/icons/rating2.tsx, src/assets/icons/rating3.tsx, src/assets/icons/rating4.tsx, src/assets/icons/rating5.tsx
Five new memoized SVG React components (default exports) for rating icons with accessibility attributes and configurable size.
Notification Integration
src/app/_components/drivercomponents/surveyNotification/surveyNotification.tsx
Replaced previous SurveyForm usage with the new TripSurveyModal component in the survey notification modal.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • themaxboucher
  • promatty
  • burtonjong
  • wesleylui
  • Yemyam
  • Lujarios
  • tanvimahal
  • jason-duong4509

Poem

🐰 I hopped in with icons five and bright,
A modal stretched to fit the night,
Forms lined up with times and lore,
Ratings, notes, and miles to store —
A tiny hop for UI delight.

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'SANC-31: Implement trip survey frontend modal' accurately describes the main purpose of the changeset, which adds a new TripSurveyModal component and related UI elements for the trip survey form.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch SANC-31-Build-Driver-Trip-Survey-Modal-Component-Frontend-Only

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/app/_components/common/modal/modal.tsx (1)

1-61: ⚠️ Potential issue | 🟠 Major

Add "use client" directive for hook usage.

The component uses useMediaQuery from @mantine/hooks at line 43. In Next.js app directory, all components using React hooks must be marked as client components. All comparable components in this directory (Button, calendar-view, DatePicker) include the "use client" directive—this file needs it as well.

Suggested fix
+"use client";
 import { Group, Modal as MantineModal, type ModalBaseOverlayProps } from "@mantine/core";
 import { useMediaQuery } from "@mantine/hooks";
🤖 Fix all issues with AI agents
In `@src/app/_components/drivercomponents/TripSurveyModal.tsx`:
- Around line 83-88: The handleConfirm function currently logs PII via
console.log(form.getValues()) after validation; remove that production logging
and either delete the console.log call or wrap it behind a development-only
guard (e.g., check process.env.NODE_ENV === 'development') so only
non-production builds emit the form values. Update the handleConfirm
implementation where form.validate(), form.getValues(), and console.log are
referenced to avoid exposing addresses/notes in production.
- Around line 104-143: In TripSurveyModal, two Mantine <Text> components use an
invalid size token `size="l"` (look for the headings "Drive Details" and "Fit or
Not fit"); update both to a valid token `size="lg"` so the component uses
supported Mantine sizes and avoids runtime/visual issues.
- Around line 32-38: The endReading validator in TripSurveyModal.tsx must be
converted to Mantine's cross-field signature to compare against
values.startReading: update the endReading function to accept (value, values),
keep the existing empty/number checks, and add a check that Number(value) >=
Number(values.startReading) returning an appropriate error message (e.g., "End
reading must be greater than or equal to start reading") when it fails;
reference the existing startReading and endReading validator functions to
implement this comparison and preserve the integer validation logic.
🧹 Nitpick comments (2)
src/assets/icons/rating4.tsx (1)

15-28: Remove the duplicate circle path to avoid redundant rendering.

♻️ Proposed cleanup
   <path
     stroke="#424242"
     strokeLinecap="round"
     strokeLinejoin="round"
     strokeWidth={3}
     d="M16 29.333c7.364 0 13.333-5.97 13.333-13.333 0-7.364-5.97-13.333-13.333-13.333C8.636 2.667 2.667 8.637 2.667 16c0 7.364 5.97 13.333 13.333 13.333Z"
   />
-  <path
-    stroke="#424242"
-    strokeLinecap="round"
-    strokeLinejoin="round"
-    strokeWidth={3}
-    d="M16 29.333c7.364 0 13.333-5.97 13.333-13.333 0-7.364-5.97-13.333-13.333-13.333C8.636 2.667 2.667 8.637 2.667 16c0 7.364 5.97 13.333 13.333 13.333Z"
-  />
src/app/_components/drivercomponents/TripSurveyModal.tsx (1)

117-139: Add native input type affordances for improved validation and mobile UX.

Mantine's TextInput forwards all native input element props, enabling type="time", inputMode, and pattern attributes. Using these improves mobile keyboard selection and leverages browser-native validation.

💡 Input type improvements
           <TextInput
             label="Time of Departure"
             placeholder="Enter departure time"
+            type="time"
             {...form.getInputProps("timeOfDeparture")}
             required
           />
           <TextInput
             label="Time of Arrival"
             placeholder="Enter arrival time"
+            type="time"
             {...form.getInputProps("timeOfArrival")}
             required
           />
           <TextInput
             label="Odometer start"
             placeholder="Enter odometer starting value"
+            inputMode="numeric"
+            pattern="[0-9]*"
             {...form.getInputProps("startReading")}
             required
           />
           <TextInput
             label="Odometer end"
             placeholder="Enter odometer ending value"
+            inputMode="numeric"
+            pattern="[0-9]*"
             {...form.getInputProps("endReading")}
             required
           />

Comment on lines 32 to 38
startReading: (value) =>
value.length < 1 || !Number.isInteger(Number(value))
? "Please enter a valid numerical reading"
: null,
endReading: (value) =>
value.length < 1 || !Number.isInteger(Number(value))
? "Please enter a valid numerical reading"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

fd "TripSurveyModal.tsx"

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 133


🏁 Script executed:

cat -n src/app/_components/drivercomponents/TripSurveyModal.tsx | head -50

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 2259


🌐 Web query:

Mantine useForm validate cross-field validation (value, values) signature

💡 Result:

In Mantine useForm (rules-object validation), each field validator is called with:

(value, values, path) => ReactNode | null
  • value: current field value
  • values: all form values (use this for cross-field validation)
  • path: field path (e.g. "user.email", "cart.0.price") [1]

Example (cross-field):

validate: {
  confirmPassword: (value, values) =>
    value !== values.password ? 'Passwords did not match' : null,
}
```  [1]

Sources: Mantine “Form validation” docs (current) [1] and same section in v5 docs [2].

---



</details>

**Add cross-field validation to ensure end reading ≥ start reading.**

Users can currently submit an end reading lower than the start reading. The `endReading` validator needs to compare against `values.startReading` using Mantine's cross-field validation signature.

<details>
<summary>Suggested validation update</summary>

```diff
       endReading: (value) =>
         value.length < 1 || !Number.isInteger(Number(value))
           ? "Please enter a valid numerical reading"
-          : null,
+          : null,
+      endReading: (value, values) => {
+        if (value.length < 1 || !Number.isInteger(Number(value))) {
+          return "Please enter a valid numerical reading";
+        }
+        if (Number(value) < Number(values.startReading)) {
+          return "End reading must be greater than or equal to start reading";
+        }
+        return null;
+      },
🤖 Prompt for AI Agents
In `@src/app/_components/drivercomponents/TripSurveyModal.tsx` around lines 32 -
38, The endReading validator in TripSurveyModal.tsx must be converted to
Mantine's cross-field signature to compare against values.startReading: update
the endReading function to accept (value, values), keep the existing
empty/number checks, and add a check that Number(value) >=
Number(values.startReading) returning an appropriate error message (e.g., "End
reading must be greater than or equal to start reading") when it fails;
reference the existing startReading and endReading validator functions to
implement this comparison and preserve the integer validation logic.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@src/app/_components/drivercomponents/TripSurveyModal.module.scss`:
- Around line 10-41: .formRow currently uses grid-specific properties (gap,
grid-column on :global(.mantine-InputWrapper-*)) but never sets display: grid
and is wrapped around a Radio.Group in TripSurveyModal.tsx which doesn't render
.mantine-InputWrapper-* children; either remove the .formRow wrapper from the
Radio.Group in TripSurveyModal.tsx, or make .formRow a real grid by adding
display: grid and grid-template-columns: auto 1fr and only apply it to
components that render Mantine InputWrapper children (e.g., TextInput, Textarea)
so the :global(.mantine-InputWrapper-*) selectors take effect.
🧹 Nitpick comments (1)
src/app/_components/drivercomponents/TripSurveyModal.module.scss (1)

6-8: Negative margin is fragile — consider a comment explaining why.

margin-top: -15px is a magic number that could break if the rating component's spacing changes. A brief inline comment noting what it compensates for would help future maintainers.

Comment on lines +10 to +41
.formRow {
gap: 0 1rem;
align-items: start;

// Override Mantine's default input styles
:global(.mantine-InputWrapper-root) {
display: contents;
}

:global(.mantine-InputWrapper-label) {
grid-column: 1;
margin-bottom: 0 !important;
display: flex;
align-items: center;
justify-content: flex-start;
}

:global(.mantine-InputWrapper-input) {
grid-column: 2;
}

:global(.mantine-InputWrapper-error) {
grid-column: 2;
margin-top: 0.25rem;
margin-bottom: 0;
}

// Increase textarea height
:global(.mantine-Textarea-input) {
min-height: 100px;
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Find the TripSurveyModal component to see how .formRow is used
fd "TripSurveyModal" --type f

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 198


🏁 Script executed:

# Search for .formRow usage in TSX/JSX files
rg "formRow" --type-add 'tsx:*.tsx' --type tsx -B 5 -A 5

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 22179


🏁 Script executed:

# Check if Mantine is installed and locate its InputWrapper classes
fd "node_modules/mantine" --type d | head -1

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 59


🏁 Script executed:

cat src/app/_components/drivercomponents/TripSurveyModal.tsx

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 7588


🏁 Script executed:

# Check if node_modules exists and search for Mantine InputWrapper
find . -path "*/node_modules/@mantine/*" -name "*.css" -o -name "*.module.css" 2>/dev/null | head -20

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 103


🏁 Script executed:

# Search for `@mantine` packages to understand structure
ls -la node_modules/@mantine 2>/dev/null | head -20

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 59


🏁 Script executed:

cat src/app/_components/drivercomponents/TripSurveyModal.module.scss

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 934


🏁 Script executed:

# Search for references to mantine InputWrapper or Input classes in the codebase
rg "mantine-InputWrapper" --type-add 'scss:*.scss' --type scss

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 2187


🏁 Script executed:

# Check the actual TripSurveyModal scss module to see all defined classes
cat -n src/app/_components/drivercomponents/TripSurveyModal.module.scss | head -50

Repository: Code-the-Change-YYC/salvationarmy

Length of output: 1277


.formRow lacks display: grid and is used incorrectly in TripSurveyModal.

The .formRow class applies grid gap and uses :global(.mantine-InputWrapper-*) selectors with grid-column properties, but never declares display: grid. Without this, the grid-column rules have no effect.

Additionally, in TripSurveyModal.tsx, .formRow only wraps a Radio.Group component, which doesn't produce .mantine-InputWrapper-* child elements. This means all the InputWrapper-targeting selectors (lines 19-35) are dead code here. Either:

  • Remove .formRow wrapper from the Radio.Group, or
  • If .formRow is meant for input fields, add display: grid; grid-template-columns: auto 1fr; to the class and apply it only to actual form inputs like TextInput and Textarea.
🤖 Prompt for AI Agents
In `@src/app/_components/drivercomponents/TripSurveyModal.module.scss` around
lines 10 - 41, .formRow currently uses grid-specific properties (gap,
grid-column on :global(.mantine-InputWrapper-*)) but never sets display: grid
and is wrapped around a Radio.Group in TripSurveyModal.tsx which doesn't render
.mantine-InputWrapper-* children; either remove the .formRow wrapper from the
Radio.Group in TripSurveyModal.tsx, or make .formRow a real grid by adding
display: grid and grid-template-columns: auto 1fr and only apply it to
components that render Mantine InputWrapper children (e.g., TextInput, Textarea)
so the :global(.mantine-InputWrapper-*) selectors take effect.

@burtonjong burtonjong merged commit f84bf7e into main Feb 11, 2026
4 checks passed
@burtonjong burtonjong deleted the SANC-31-Build-Driver-Trip-Survey-Modal-Component-Frontend-Only branch February 11, 2026 01:10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants