[#398] COMPONENTS - Added creation/edit dialog component#421
[#398] COMPONENTS - Added creation/edit dialog component#421
Conversation
📝 WalkthroughWalkthroughAdds a new CreateEditDialog React component (modal) for creating/editing issues in Event or Task modes, plus related types/constants (CreateEditDialogProps, IssueFormValues, EventFormValues, DetailSectionKey, SECTION_TABS, status/priority types) consumed by the dialog. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant Dialog as CreateEditDialog
participant Parent as ParentComponent
participant API as onSubmit/onDelete
User->>Dialog: open(intent=create|edit, initialValues?)
Dialog-->>User: render modal (tabs, Event/Task fields, controls)
User->>Dialog: change fields / toggle isEvent / add/remove links
Dialog->>Dialog: update internal form state
User->>Dialog: Submit
Dialog->>Parent: onSubmit(formValues)
Parent->>API: persist create/update
API-->>Parent: success/failure
Parent-->>Dialog: onClose() or surface errors
User->>Dialog: Delete (when editing)
Dialog->>Parent: onDelete(id)
Parent->>API: delete
API-->>Parent: success
Parent-->>Dialog: onClose()
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~30 minutes Suggested labels
🚥 Pre-merge checks | ✅ 5 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
📝 Coding Plan
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🧹 Nitpick comments (3)
apps/blade/src/app/_components/issues/create-edit-dialog.tsx (3)
706-718: Add accessible labels to dynamic link inputs.The link label and URL inputs lack associated
<Label>elements oraria-labelattributes. Screen reader users won't know what these fields are for.Add aria-labels to link inputs
<Input className={cn(baseField, "h-11")} placeholder="Label (e.g., Notion doc)" + aria-label={`Link ${formValues.links.indexOf(link) + 1} label`} value={link.label} onChange={(event) => handleLinkUpdate( link.id, "label", event.target.value, ) } /><Input className={cn(baseField, "h-11 pl-9")} placeholder="URL" type="url" + aria-label={`Link ${formValues.links.indexOf(link) + 1} URL`} value={link.url} onChange={(event) => handleLinkUpdate( link.id, "url", event.target.value, ) } />🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx` around lines 706 - 718, The dynamic link inputs rendered inside the create-edit dialog are missing accessible labels; update the Input elements (the ones using value={link.label} and value={link.url} and onChange calling handleLinkUpdate(link.id,...)) to include accessible labeling — either wrap each input with the existing Label component or add descriptive aria-label attributes (e.g., aria-label="Link label" and aria-label="Link URL") and keep the existing className={cn(baseField, "h-11")}; ensure the label text or aria-label uniquely identifies the field when iterating multiple links so screen readers can distinguish them (you can include the link.id or index in the aria-label if needed).
300-331: Addaria-labelledbyto improve screen reader accessibility.The dialog has
role="dialog"andaria-modal, but screen readers benefit fromaria-labelledbypointing to the title. This helps users understand the dialog's purpose when it opens.Add aria-labelledby
+ const titleId = `${baseId}-dialog-title`; + // ... in JSX: <div aria-modal role="dialog" + aria-labelledby={titleId} className="fixed inset-0 z-50 ..." onMouseDown={handleOverlayPointerDown} > ... - <h2 className="text-2xl font-semibold text-white"> + <h2 id={titleId} className="text-2xl font-semibold text-white">🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx` around lines 300 - 331, The dialog container with role="dialog" lacks aria-labelledby; add aria-labelledby to the outer div returned by createPortal (the element with role="dialog") and give the title h2 a matching id (e.g., id="create-edit-dialog-title") so screen readers announce the dialog title; update the h2 inside the header (the element rendering "Update the event details below" / "Enter the event details below") and the createPortal div (the element with aria-modal and role="dialog") accordingly.
285-288: Consider validating date range before submission.The form allows
endDate/endTimeto be beforestartDate/startTime. Adding client-side validation prevents users from submitting logically invalid date ranges.Example validation in handleSubmit
const handleSubmit = (event: React.FormEvent<HTMLFormElement>) => { event.preventDefault(); + + if (!formValues.allDay) { + const start = new Date(`${formValues.startDate}T${formValues.startTime}`); + const end = new Date(`${formValues.endDate}T${formValues.endTime}`); + if (end <= start) { + // Handle error - could add error state and display message + return; + } + } + onSubmit?.(formValues); };🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx` around lines 285 - 288, The handleSubmit function currently submits formValues without checking that the end date/time is after the start; update handleSubmit to validate the date range by constructing comparable Date objects from formValues.startDate/formValues.startTime and formValues.endDate/formValues.endTime, and if the end is not after the start prevent submission (call event.preventDefault() already present), set a validation error state or invoke existing error handler to show a user-facing message, and only call onSubmit(formValues) when the date-range check passes; reference the handleSubmit function, formValues fields (startDate, startTime, endDate, endTime), and onSubmit when implementing this change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx`:
- Around line 737-744: The delete button that renders the Trash2 icon lacks an
accessible name; update the Button element that calls handleRemoveLink(link.id)
to include an aria-label (for example aria-label={`Delete link${link.title ? `:
${link.title}` : ''}`} or a static "Delete link") so screen readers get context
when they encounter the icon-only button.
- Around line 821-827: formatDateForInput currently uses date.toISOString()
(UTC) while formatTimeForInput uses date.toTimeString() (local), causing
timezone drift; change formatDateForInput to produce a local YYYY-MM-DD string
(e.g., via date.getFullYear()/getMonth()+1/getDate with zero-padding or
date.toLocaleDateString('sv')/ 'en-CA') so both formatDateForInput and
formatTimeForInput use the same local time basis and remain consistent across
timezones.
- Around line 31-49: IssueFormValues fields and STATUS_OPTIONS values do not
match the Issue DB enum (ISSUE.ISSUE_STATUS) and other form fields don't map to
the Issue model; before calling createIssue you must transform the form payload
to the DB shape: map form status values (from STATUS_OPTIONS) to the DB enum
values (e.g., "confirmed"/"tentative"/"draft"/"cancelled" -> one of
BACKLOG/PLANNING/IN_PROGRESS/FINISHED), combine startDate+startTime and
endDate+endTime into the single timestamp column (date) or otherwise produce the
expected timestamp(s), convert LinkItem[] into a string[] (text[])
representation, and drop or persist the extra properties (priority,
requiresRoom, needsDesignAssets, needsOutreach, requirements, notes) either by
removing them from the payload sent to createIssue or by adding corresponding DB
columns if intended; update the code path that builds the mutation payload
(where IssueFormValues is serialized for createIssue) to perform these mappings
and validations.
---
Nitpick comments:
In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx`:
- Around line 706-718: The dynamic link inputs rendered inside the create-edit
dialog are missing accessible labels; update the Input elements (the ones using
value={link.label} and value={link.url} and onChange calling
handleLinkUpdate(link.id,...)) to include accessible labeling — either wrap each
input with the existing Label component or add descriptive aria-label attributes
(e.g., aria-label="Link label" and aria-label="Link URL") and keep the existing
className={cn(baseField, "h-11")}; ensure the label text or aria-label uniquely
identifies the field when iterating multiple links so screen readers can
distinguish them (you can include the link.id or index in the aria-label if
needed).
- Around line 300-331: The dialog container with role="dialog" lacks
aria-labelledby; add aria-labelledby to the outer div returned by createPortal
(the element with role="dialog") and give the title h2 a matching id (e.g.,
id="create-edit-dialog-title") so screen readers announce the dialog title;
update the h2 inside the header (the element rendering "Update the event details
below" / "Enter the event details below") and the createPortal div (the element
with aria-modal and role="dialog") accordingly.
- Around line 285-288: The handleSubmit function currently submits formValues
without checking that the end date/time is after the start; update handleSubmit
to validate the date range by constructing comparable Date objects from
formValues.startDate/formValues.startTime and
formValues.endDate/formValues.endTime, and if the end is not after the start
prevent submission (call event.preventDefault() already present), set a
validation error state or invoke existing error handler to show a user-facing
message, and only call onSubmit(formValues) when the date-range check passes;
reference the handleSubmit function, formValues fields (startDate, startTime,
endDate, endTime), and onSubmit when implementing this change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: 5cc81bde-1b80-4cdc-9cd4-6d1246535d03
📒 Files selected for processing (1)
apps/blade/src/app/_components/issues/create-edit-dialog.tsx
| <Button | ||
| variant="ghost" | ||
| type="button" | ||
| className="h-11 w-11 rounded-2xl border border-white/10 bg-transparent text-white/70 hover:border-white/30 hover:text-white" | ||
| onClick={() => handleRemoveLink(link.id)} | ||
| > | ||
| <Trash2 className="h-4 w-4" /> | ||
| </Button> |
There was a problem hiding this comment.
Add aria-label to the delete link button.
The button only contains an icon. Screen readers will announce it as "button" with no context.
Add aria-label
<Button
variant="ghost"
type="button"
className="h-11 w-11 rounded-2xl border border-white/10 bg-transparent text-white/70 hover:border-white/30 hover:text-white"
onClick={() => handleRemoveLink(link.id)}
+ aria-label={`Remove link ${link.label || "item"}`}
>
<Trash2 className="h-4 w-4" />
</Button>📝 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.
| <Button | |
| variant="ghost" | |
| type="button" | |
| className="h-11 w-11 rounded-2xl border border-white/10 bg-transparent text-white/70 hover:border-white/30 hover:text-white" | |
| onClick={() => handleRemoveLink(link.id)} | |
| > | |
| <Trash2 className="h-4 w-4" /> | |
| </Button> | |
| <Button | |
| variant="ghost" | |
| type="button" | |
| className="h-11 w-11 rounded-2xl border border-white/10 bg-transparent text-white/70 hover:border-white/30 hover:text-white" | |
| onClick={() => handleRemoveLink(link.id)} | |
| aria-label={`Remove link ${link.label || "item"}`} | |
| > | |
| <Trash2 className="h-4 w-4" /> | |
| </Button> |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx` around lines
737 - 744, The delete button that renders the Trash2 icon lacks an accessible
name; update the Button element that calls handleRemoveLink(link.id) to include
an aria-label (for example aria-label={`Delete link${link.title ? `:
${link.title}` : ''}`} or a static "Delete link") so screen readers get context
when they encounter the icon-only button.
| function formatDateForInput(date: Date) { | ||
| return date.toISOString().slice(0, 10); | ||
| } | ||
|
|
||
| function formatTimeForInput(date: Date) { | ||
| return date.toTimeString().slice(0, 5); | ||
| } |
There was a problem hiding this comment.
Timezone inconsistency between date and time formatting.
formatDateForInput uses toISOString() which returns UTC, but formatTimeForInput uses toTimeString() which returns local time. This mismatch can cause the displayed date to be off by one day near midnight in certain timezones.
Use consistent local time formatting
function formatDateForInput(date: Date) {
- return date.toISOString().slice(0, 10);
+ const year = date.getFullYear();
+ const month = String(date.getMonth() + 1).padStart(2, "0");
+ const day = String(date.getDate()).padStart(2, "0");
+ return `${year}-${month}-${day}`;
}📝 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.
| function formatDateForInput(date: Date) { | |
| return date.toISOString().slice(0, 10); | |
| } | |
| function formatTimeForInput(date: Date) { | |
| return date.toTimeString().slice(0, 5); | |
| } | |
| function formatDateForInput(date: Date) { | |
| const year = date.getFullYear(); | |
| const month = String(date.getMonth() + 1).padStart(2, "0"); | |
| const day = String(date.getDate()).padStart(2, "0"); | |
| return `${year}-${month}-${day}`; | |
| } | |
| function formatTimeForInput(date: Date) { | |
| return date.toTimeString().slice(0, 5); | |
| } |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx` around lines
821 - 827, formatDateForInput currently uses date.toISOString() (UTC) while
formatTimeForInput uses date.toTimeString() (local), causing timezone drift;
change formatDateForInput to produce a local YYYY-MM-DD string (e.g., via
date.getFullYear()/getMonth()+1/getDate with zero-padding or
date.toLocaleDateString('sv')/ 'en-CA') so both formatDateForInput and
formatTimeForInput use the same local time basis and remain consistent across
timezones.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (3)
apps/blade/src/app/_components/issues/create-edit-dialog.tsx (3)
854-861:⚠️ Potential issue | 🟡 MinorAdd an accessible name to the icon-only delete button.
At Line 854, the trash-icon button has no
aria-label, so assistive tech lacks context.Suggested patch
<Button variant="ghost" type="button" className="h-11 w-11 rounded-2xl border border-white/10 bg-transparent text-white/70 hover:border-white/30 hover:text-white" onClick={() => handleRemoveLink(link.id)} + aria-label={`Remove link ${link.label || "item"}`} > <Trash2 className="h-4 w-4" /> </Button>As per coding guidelines,
apps/blade/**requires accessibility-safe UI patterns (including ARIA coverage for actionable controls).🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx` around lines 854 - 861, The trash-icon-only Button (Button with onClick={() => handleRemoveLink(link.id)} rendering <Trash2 />) is missing an accessible name; add an aria-label (or aria-labelledby) to the Button so screen readers have context (e.g., aria-label={`Delete link`} or a dynamic label like aria-label={`Delete link ${link.title || link.url || link.id}`}) while keeping the existing onClick handler and classes; update the Button that wraps <Trash2 className="h-4 w-4" /> to include this aria attribute so the control is accessible.
938-944:⚠️ Potential issue | 🟡 MinorUse a consistent local-time basis for date/time formatting.
Line 939 uses UTC (
toISOString) while Line 943 uses local time (toTimeString), which can shift the displayed date near midnight/timezone boundaries.Suggested patch
function formatDateForInput(date: Date) { - return date.toISOString().slice(0, 10); + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, "0"); + const day = String(date.getDate()).padStart(2, "0"); + return `${year}-${month}-${day}`; }In JavaScript, does Date.prototype.toISOString() always output UTC while Date.prototype.toTimeString() outputs local time?🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx` around lines 938 - 944, formatDateForInput uses UTC via toISOString() while formatTimeForInput uses local time via toTimeString(), causing inconsistent results near timezone boundaries; change both to use the same local-time basis by deriving date and time from the Date object's local getters (e.g., getFullYear, getMonth, getDate for formatDateForInput and getHours, getMinutes for formatTimeForInput) and zero-pad as needed so both functions consistently format based on local time; update the implementations of formatDateForInput and formatTimeForInput accordingly.
68-93:⚠️ Potential issue | 🟠 MajorAlign status/priority option values with
@forge/constsenums.The select options use values outside
ISSUE_STATUS/PRIORITY(confirmed,tentative, lowercase priorities), and casts at Line 463 mask the mismatch. This can submit values the backend does not accept.Suggested patch
-const STATUS_OPTIONS = [ - { value: "confirmed", label: "Confirmed", caption: "Everything is locked in", dotClass: "bg-emerald-400" }, - { value: "tentative", label: "Tentative", caption: "Waiting on a few details", dotClass: "bg-amber-400" }, - { value: "draft", label: "Draft", caption: "Still being scoped", dotClass: "bg-slate-400" }, - { value: "cancelled", label: "Cancelled", caption: "No longer happening", dotClass: "bg-rose-400" }, -] as const; +const STATUS_OPTIONS: { value: IssueStatus; label: string; caption: string; dotClass: string }[] = [ + { value: "BACKLOG", label: "Backlog", caption: "Not started yet", dotClass: "bg-slate-400" }, + { value: "PLANNING", label: "Planning", caption: "Being scoped", dotClass: "bg-amber-400" }, + { value: "IN_PROGRESS", label: "In Progress", caption: "Actively underway", dotClass: "bg-sky-400" }, + { value: "FINISHED", label: "Finished", caption: "Completed", dotClass: "bg-emerald-400" }, +]; @@ -const PRIORITY_OPTIONS = ["High", "Medium", "Low"]; +const PRIORITY_OPTIONS: IssuePriority[] = [...PRIORITY]; @@ - onValueChange={(value) => - updateForm("status", value as IssueStatus) - } + onValueChange={(value) => updateForm("status", value as IssueStatus)} @@ - {PRIORITY_OPTIONS.map((priority) => ( - <SelectItem - key={priority} - value={priority.toLowerCase()} - > + {PRIORITY_OPTIONS.map((priority) => ( + <SelectItem key={priority} value={priority}> {priority} </SelectItem> ))}#!/bin/bash # Verify enum sources vs local options (read-only). echo "=== Canonical enums ===" sed -n '1,40p' packages/consts/src/issue.ts echo echo "=== Local options and select value wiring ===" sed -n '68,120p' apps/blade/src/app/_components/issues/create-edit-dialog.tsx sed -n '455,705p' apps/blade/src/app/_components/issues/create-edit-dialog.tsxAlso applies to: 110-111, 461-464, 677-693
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx` around lines 68 - 93, STATUS_OPTIONS (and the Priority options referenced around create-edit-dialog.tsx) use non-canonical string values and then get force-cast when submitting; update the option objects so their value fields match the canonical enums exported from `@forge/consts` (ISSUE_STATUS and PRIORITY) instead of "confirmed"/"tentative" or lowercase priorities, and update any select wiring that currently casts values (see the cast near the submit handler and the SELECT value props around create-edit-dialog.tsx) to rely on the real enum types; in short, replace the value strings in STATUS_OPTIONS (and the priority options) with the corresponding ISSUE_STATUS/PRIORITY enum members and remove the unsafe type casts so submitted payloads use the backend-accepted enum values.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx`:
- Line 927: The submit button copy currently uses intent to render "Create
Event"/"Update Event" but doesn't respect task mode; update the text generation
in the CreateEditDialog component to also consider the task vs event flag (e.g.,
use isTask, mode, or itemType used in this component) and return "Create
Task"/"Update Task" when in task mode and "Create Event"/"Update Event"
otherwise, keeping the existing intent-based switch for create vs update.
---
Duplicate comments:
In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx`:
- Around line 854-861: The trash-icon-only Button (Button with onClick={() =>
handleRemoveLink(link.id)} rendering <Trash2 />) is missing an accessible name;
add an aria-label (or aria-labelledby) to the Button so screen readers have
context (e.g., aria-label={`Delete link`} or a dynamic label like
aria-label={`Delete link ${link.title || link.url || link.id}`}) while keeping
the existing onClick handler and classes; update the Button that wraps <Trash2
className="h-4 w-4" /> to include this aria attribute so the control is
accessible.
- Around line 938-944: formatDateForInput uses UTC via toISOString() while
formatTimeForInput uses local time via toTimeString(), causing inconsistent
results near timezone boundaries; change both to use the same local-time basis
by deriving date and time from the Date object's local getters (e.g.,
getFullYear, getMonth, getDate for formatDateForInput and getHours, getMinutes
for formatTimeForInput) and zero-pad as needed so both functions consistently
format based on local time; update the implementations of formatDateForInput and
formatTimeForInput accordingly.
- Around line 68-93: STATUS_OPTIONS (and the Priority options referenced around
create-edit-dialog.tsx) use non-canonical string values and then get force-cast
when submitting; update the option objects so their value fields match the
canonical enums exported from `@forge/consts` (ISSUE_STATUS and PRIORITY) instead
of "confirmed"/"tentative" or lowercase priorities, and update any select wiring
that currently casts values (see the cast near the submit handler and the SELECT
value props around create-edit-dialog.tsx) to rely on the real enum types; in
short, replace the value strings in STATUS_OPTIONS (and the priority options)
with the corresponding ISSUE_STATUS/PRIORITY enum members and remove the unsafe
type casts so submitted payloads use the backend-accepted enum values.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: dd1ecf33-f938-403d-ae85-54fa8e50ccf6
📒 Files selected for processing (1)
apps/blade/src/app/_components/issues/create-edit-dialog.tsx
| export interface IssueFormValues { | ||
| status: IssueStatus; | ||
| name: string; | ||
| description: string; | ||
| links: LinkItem[]; | ||
| date: string; // ISO string | ||
| priority: IssuePriority; | ||
| team: string; // UUID or name | ||
| parent?: string; | ||
| // UI only fields | ||
| isEvent: boolean; | ||
| // For event, we store event form values | ||
| event?: EventFormValues; | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Verify missing type and key drift inside the dialog file (read-only).
echo "=== IssueFormValues declaration ==="
sed -n '44,90p' apps/blade/src/app/_components/issues/create-edit-dialog.tsx
echo
echo "=== updateForm key usage ==="
rg -nP 'updateForm\("([^"]+)"' apps/blade/src/app/_components/issues/create-edit-dialog.tsx
echo
echo "=== Direct formValues accesses for UI-only fields ==="
rg -nP 'formValues\.(details|notes|requiresRoom|isHackathonCritical|needsDesignAssets|needsOutreach)' apps/blade/src/app/_components/issues/create-edit-dialog.tsx
echo
echo "=== LinkItem declaration check ==="
rg -nP '\b(interface|type)\s+LinkItem\b' apps/blade/src/app/_components/issues/create-edit-dialog.tsxRepository: KnightHacks/forge
Length of output: 2150
🏁 Script executed:
#!/bin/bash
echo "=== LinkItem import/type in file ==="
head -50 apps/blade/src/app/_components/issues/create-edit-dialog.tsx | grep -E "import|LinkItem"
echo
echo "=== Search for needsDesignAssets usage ==="
rg -n 'needsDesignAssets' apps/blade/src/app/_components/issues/create-edit-dialog.tsx
echo
echo "=== Delete button around line 854-861 ==="
sed -n '854,870p' apps/blade/src/app/_components/issues/create-edit-dialog.tsx
echo
echo "=== Check STATUS enum from consts ==="
rg -A10 'export.*STATUS|export.*enum.*Status' packages/consts/src/issue.ts
echo
echo "=== Check PRIORITY enum from consts ==="
rg -A10 'export.*PRIORITY|export.*enum.*Priority' packages/consts/src/issue.tsRepository: KnightHacks/forge
Length of output: 1888
🏁 Script executed:
#!/bin/bash
echo "=== Full imports section (first 80 lines) ==="
sed -n '1,80p' apps/blade/src/app/_components/issues/create-edit-dialog.tsx
echo
echo "=== EventFormValues interface (around 113-127) ==="
sed -n '110,135p' apps/blade/src/app/_components/issues/create-edit-dialog.tsx
echo
echo "=== PRIORITY_OPTIONS definition ==="
rg -B2 -A15 'const PRIORITY_OPTIONS' apps/blade/src/app/_components/issues/create-edit-dialog.tsx
echo
echo "=== Form submission - what gets sent to API ==="
rg -B5 -A10 'onSubmit\?.*values' apps/blade/src/app/_components/issues/create-edit-dialog.tsx | head -40Repository: KnightHacks/forge
Length of output: 3943
🏁 Script executed:
#!/bin/bash
echo "=== Search for LinkItem definition across codebase ==="
rg -n 'interface LinkItem|type LinkItem' --type ts --type tsx
echo
echo "=== Submit handler and form value processing ==="
sed -n '900,950p' apps/blade/src/app/_components/issues/create-edit-dialog.tsx
echo
echo "=== How STATUS_OPTIONS is used in form ==="
rg -B3 -A3 'SelectItem.*value.*confirmed' apps/blade/src/app/_components/issues/create-edit-dialog.tsx | head -30Repository: KnightHacks/forge
Length of output: 1538
🏁 Script executed:
#!/bin/bash
echo "=== Search for LinkItem definition (no type filter) ==="
rg -n 'LinkItem' apps/blade/src/app/_components/issues/create-edit-dialog.tsx | head -5
echo
echo "=== Check if LinkItem is in shared types ==="
find . -path ./node_modules -prune -o -name '*.ts' -o -name '*.tsx' | xargs grep -l 'interface LinkItem\|type LinkItem' 2>/dev/null | head -10
echo
echo "=== Check handleSubmit and formValues usage ==="
rg -B5 -A8 'const handleSubmit|form.handleSubmit' apps/blade/src/app/_components/issues/create-edit-dialog.tsx
echo
echo "=== Check the default/initial formValues structure ==="
rg -B2 -A15 'const getDefaultValues|initialValues' apps/blade/src/app/_components/issues/create-edit-dialog.tsx | head -50Repository: KnightHacks/forge
Length of output: 2037
Define LinkItem type and sync IssueFormValues with actual form field usage—currently missing required fields causing TypeScript errors and form data loss.
The interface declares links: LinkItem[] without defining LinkItem, and is missing five fields actively bound in the form: requiresRoom, isHackathonCritical, notes, needsDesignAssets, and needsOutreach. Additionally, the form binds to formValues.details but the interface defines description—the submitted data will lack a description field.
Also, fix enum value mismatches: STATUS_OPTIONS values ("confirmed", "tentative", "draft", "cancelled") don't match the imported ISSUE_STATUS constants ("BACKLOG", "PLANNING", "IN_PROGRESS", "FINISHED"), and PRIORITY_OPTIONS (["High", "Medium", "Low"]) don't match PRIORITY (["LOWEST", "LOW", "MEDIUM", "HIGH", "HIGHEST"]). These mismatches will cause API validation failures at runtime.
Finally, the submit button always shows "Create Event" / "Update Event" regardless of isEvent mode, and the delete-link icon button (line 854–861) lacks an accessible name.
Suggested fixes
+ interface LinkItem {
+ id: string;
+ label: string;
+ url: string;
+ }
+
export interface IssueFormValues {
status: IssueStatus;
name: string;
description: string;
links: LinkItem[];
date: string; // ISO string
priority: IssuePriority;
team: string; // UUID or name
parent?: string;
+ requiresRoom: boolean;
+ isHackathonCritical: boolean;
+ notes: string;
+ needsDesignAssets: boolean;
+ needsOutreach: boolean;
// UI only fields
isEvent: boolean;
// For event, we store event form values
event?: EventFormValues;
}At form binding (line 716–719):
- value={formValues.details}
+ value={formValues.description}
onChange={(event) =>
- updateForm("details", event.target.value)
+ updateForm("description", event.target.value)
}For enums, align STATUS_OPTIONS and PRIORITY_OPTIONS with the imported constants rather than hardcoded strings.
Delete button (line 854–861):
<Button
variant="ghost"
type="button"
className="h-11 w-11 rounded-2xl border border-white/10 bg-transparent text-white/70 hover:border-white/30 hover:text-white"
+ aria-label="Remove link"
onClick={() => handleRemoveLink(link.id)}
>Submit button text (line 927):
{intent === "edit"
- ? "Update Event"
- : "Create Event"
+ ? formValues.isEvent ? "Update Event" : "Update Issue"
+ : formValues.isEvent ? "Create Event" : "Create Issue"
}| className="w-full disabled:opacity-40 sm:w-auto" | ||
| disabled={isSubmitDisabled} | ||
| > | ||
| {intent === "edit" ? "Update Event" : "Create Event"} |
There was a problem hiding this comment.
Use task/event-aware submit copy.
Line 927 always renders event text, which is incorrect in task mode.
Suggested patch
- {intent === "edit" ? "Update Event" : "Create Event"}
+ {intent === "edit"
+ ? formValues.isEvent
+ ? "Update Event"
+ : "Update Task"
+ : formValues.isEvent
+ ? "Create Event"
+ : "Create Task"}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx` at line 927,
The submit button copy currently uses intent to render "Create Event"/"Update
Event" but doesn't respect task mode; update the text generation in the
CreateEditDialog component to also consider the task vs event flag (e.g., use
isTask, mode, or itemType used in this component) and return "Create
Task"/"Update Task" when in task mode and "Create Event"/"Update Event"
otherwise, keeping the existing intent-based switch for create vs update.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (2)
apps/blade/src/app/_components/issues/create-edit-dialog.tsx (1)
534-553:⚠️ Potential issue | 🟠 MajorUse the enum value as the select value.
formValues.prioritystoresISSUE.PRIORITYmembers like"LOWEST", but eachSelectItempublishespriority.toLowerCase(). After the first selection, the state contains a value outsideIssuePriority, the current option no longer matches, and any upstream enum validation will fail. Keep thevalueuppercase and only format the label for display.Suggested patch
{ISSUE.PRIORITY.map((priority) => ( - <SelectItem key={priority} value={priority.toLowerCase()}> - {priority} + <SelectItem key={priority} value={priority}> + {getStatusLabel(priority)} </SelectItem> ))}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx` around lines 534 - 553, The Select is storing lowercase strings (priority.toLowerCase()) while formValues.priority expects ISSUE.PRIORITY enum members (e.g., "LOWEST"), causing mismatches; update the SelectItem value to use the enum member (priority) instead of priority.toLowerCase(), keep the displayed label formatted (e.g., render priority.toLowerCase() or humanize it inside the SelectItem children) and ensure updateForm("priority", value) continues to receive the uppercase enum value so formValues.priority and any upstream IssuePriority validation remain consistent.packages/consts/src/issue.ts (1)
39-50:⚠️ Potential issue | 🔴 CriticalSync
IssueFormValueswith what the dialog actually edits.
CreateEditDialogreads/writesdetails,notes,requiresRoom,isHackathonCritical,needsDesignAssets, andneedsOutreachinapps/blade/src/app/_components/issues/create-edit-dialog.tsx(for example Lines 574-576, 594-596, 616-618, and 718-720), but those keys do not exist here. BecauseupdateFormis keyed off this interface, the component will not type-check, and the currentdetailsbinding also means the dialog never populates the existingdescriptionfield. Either add the missing state keys here or rename the component bindings to the existing schema before merge.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/consts/src/issue.ts` around lines 39 - 50, The IssueFormValues interface is missing fields that CreateEditDialog reads/writes (details, notes, requiresRoom, isHackathonCritical, needsDesignAssets, needsOutreach) causing type errors and incorrect binding of description; update the IssueFormValues interface to include these properties with appropriate types (e.g., details: string, notes: string, requiresRoom: boolean, isHackathonCritical: boolean, needsDesignAssets: boolean, needsOutreach: boolean and keep existing fields like description) so that updateForm and CreateEditDialog bindings compile and the dialog correctly populates description, or alternatively change CreateEditDialog’s bindings to the existing schema (e.g., use description instead of details) but be sure to update all references in CreateEditDialog and any callers (including updateForm) to match the chosen schema.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx`:
- Around line 53-70: The event form currently leaves required fields tag and
description empty because defaultEventForm sets them but the Event branch UI (in
create-edit-dialog.tsx) never renders inputs for them and handleSubmit forwards
formValues unchanged to onSubmit; update the Event branch to either (a) render
controlled inputs for tag and description and validate them before submission
(modify the JSX where event mode is handled to include these fields and their
handlers) or (b) if you intend defaults, populate formValues.tag and
formValues.description with sensible non-empty values just prior to calling
handleSubmit/onSubmit (update the handleSubmit path that prepares the payload),
and add client-side validation in the submit flow to reject empty
tag/description so the required server schema is satisfied (referencing
defaultEventForm, handleSubmit, and onSubmit in this file).
In `@packages/consts/src/issue.ts`:
- Around line 52-65: EventFormValues currently requires discordId and googleId
even though the dialog never edits them and createEvent omits them; update the
form model by making discordId and googleId optional (discordId?: string;
googleId?: string) or removing them from EventFormValues and defaultEventForm
entirely, and adjust any usages (e.g., defaultEventForm and form initialization)
so they don't fabricate empty strings; also ensure the API shape in createEvent
(packages/api/src/routers/event.ts, createEvent handler) remains consistent with
the revised EventFormValues so there is no mismatch between the form type and
the create payload.
---
Duplicate comments:
In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx`:
- Around line 534-553: The Select is storing lowercase strings
(priority.toLowerCase()) while formValues.priority expects ISSUE.PRIORITY enum
members (e.g., "LOWEST"), causing mismatches; update the SelectItem value to use
the enum member (priority) instead of priority.toLowerCase(), keep the displayed
label formatted (e.g., render priority.toLowerCase() or humanize it inside the
SelectItem children) and ensure updateForm("priority", value) continues to
receive the uppercase enum value so formValues.priority and any upstream
IssuePriority validation remain consistent.
In `@packages/consts/src/issue.ts`:
- Around line 39-50: The IssueFormValues interface is missing fields that
CreateEditDialog reads/writes (details, notes, requiresRoom,
isHackathonCritical, needsDesignAssets, needsOutreach) causing type errors and
incorrect binding of description; update the IssueFormValues interface to
include these properties with appropriate types (e.g., details: string, notes:
string, requiresRoom: boolean, isHackathonCritical: boolean, needsDesignAssets:
boolean, needsOutreach: boolean and keep existing fields like description) so
that updateForm and CreateEditDialog bindings compile and the dialog correctly
populates description, or alternatively change CreateEditDialog’s bindings to
the existing schema (e.g., use description instead of details) but be sure to
update all references in CreateEditDialog and any callers (including updateForm)
to match the chosen schema.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: 7d55970f-f0d2-4c1d-b439-169511cd1df2
📒 Files selected for processing (2)
apps/blade/src/app/_components/issues/create-edit-dialog.tsxpackages/consts/src/issue.ts
| const defaultEventForm = (): ISSUE.EventFormValues => { | ||
| const now = new Date(); | ||
| const end = new Date(now.getTime() + 60 * 60 * 1000); | ||
| return { | ||
| discordId: "", | ||
| googleId: "", | ||
| name: "", | ||
| tag: "", | ||
| description: "", | ||
| startDate: formatDateForInput(now), | ||
| startTime: formatTimeForInput(now), | ||
| endDate: formatDateForInput(end), | ||
| endTime: formatTimeForInput(end), | ||
| location: "", | ||
| dues_paying: false, | ||
| points: undefined, | ||
| hackathonId: undefined, | ||
| }; |
There was a problem hiding this comment.
Event mode never collects a complete event payload.
defaultEventForm initializes tag and description, but the event branch only renders name/date/time/location controls, and handleSubmit forwards formValues unchanged. That means a new event can reach onSubmit with event.tag === "", and event.description is never updated anywhere in this component even though the Event schema/API treat both fields as required in packages/db/src/schemas/knight-hacks.ts:165-189 and packages/api/src/routers/event.ts:168-200. Add event-specific inputs for these fields or populate them before calling onSubmit.
As per coding guidelines apps/blade/**: Form validation on both client and server.
Also applies to: 224-231, 370-459
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx` around lines 53
- 70, The event form currently leaves required fields tag and description empty
because defaultEventForm sets them but the Event branch UI (in
create-edit-dialog.tsx) never renders inputs for them and handleSubmit forwards
formValues unchanged to onSubmit; update the Event branch to either (a) render
controlled inputs for tag and description and validate them before submission
(modify the JSX where event mode is handled to include these fields and their
handlers) or (b) if you intend defaults, populate formValues.tag and
formValues.description with sensible non-empty values just prior to calling
handleSubmit/onSubmit (update the handleSubmit path that prepares the payload),
and add client-side validation in the submit flow to reject empty
tag/description so the required server schema is satisfied (referencing
defaultEventForm, handleSubmit, and onSubmit in this file).
| export interface EventFormValues { | ||
| discordId: string; | ||
| googleId: string; | ||
| name: string; | ||
| tag: string; | ||
| description: string; | ||
| startDate: string; | ||
| startTime: string; | ||
| endDate: string; | ||
| endTime: string; | ||
| location: string; | ||
| dues_paying: boolean; | ||
| points?: number; | ||
| hackathonId?: string; |
There was a problem hiding this comment.
Make provider IDs optional or move them out of the form model.
The dialog never edits discordId or googleId, but EventFormValues requires both, so defaultEventForm has to fabricate "" values. That makes new forms start with fake IDs and makes edit flows unable to distinguish “unchanged” from “cleared”. packages/api/src/routers/event.ts:168-200 also omits these fields from createEvent, so they are not part of the create payload shape.
Suggested shape
export interface EventFormValues {
- discordId: string;
- googleId: string;
+ discordId?: string;
+ googleId?: string;
name: string;
tag: string;
description: 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.
| export interface EventFormValues { | |
| discordId: string; | |
| googleId: string; | |
| name: string; | |
| tag: string; | |
| description: string; | |
| startDate: string; | |
| startTime: string; | |
| endDate: string; | |
| endTime: string; | |
| location: string; | |
| dues_paying: boolean; | |
| points?: number; | |
| hackathonId?: string; | |
| export interface EventFormValues { | |
| discordId?: string; | |
| googleId?: string; | |
| name: string; | |
| tag: string; | |
| description: string; | |
| startDate: string; | |
| startTime: string; | |
| endDate: string; | |
| endTime: string; | |
| location: string; | |
| dues_paying: boolean; | |
| points?: number; | |
| hackathonId?: string; |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/consts/src/issue.ts` around lines 52 - 65, EventFormValues currently
requires discordId and googleId even though the dialog never edits them and
createEvent omits them; update the form model by making discordId and googleId
optional (discordId?: string; googleId?: string) or removing them from
EventFormValues and defaultEventForm entirely, and adjust any usages (e.g.,
defaultEventForm and form initialization) so they don't fabricate empty strings;
also ensure the API shape in createEvent (packages/api/src/routers/event.ts,
createEvent handler) remains consistent with the revised EventFormValues so
there is no mismatch between the form type and the create payload.
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (4)
apps/blade/src/app/_components/issues/create-edit-dialog.tsx (4)
692-699:⚠️ Potential issue | 🟡 MinorAdd
aria-labelto the delete link button for accessibility.The button only contains an icon (
Trash2). Screen readers will announce "button" without context.Fix: Add accessible label
<Button variant="ghost" type="button" className="h-11 w-11 rounded-2xl border border-white/10 bg-transparent text-white/70 hover:border-white/30 hover:text-white" onClick={() => handleRemoveLink(i)} + aria-label="Remove link" > <Trash2 className="h-4 w-4" /> </Button>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx` around lines 692 - 699, The delete button that renders the Trash2 icon lacks an accessible label; update the Button rendered in create-edit-dialog.tsx (the Button with onClick={() => handleRemoveLink(i)}) to include an aria-label (for example aria-label={`Remove link ${i + 1}`} or a static "Remove link") so screen readers receive context about the button's purpose while keeping the existing onClick and styling.
774-780:⚠️ Potential issue | 🟡 MinorTimezone inconsistency between date and time formatting.
formatDateForInputusestoISOString()(UTC), butformatTimeForInputusestoTimeString()(local). Near midnight, this can cause the displayed date to be off by one day.Example: At 11 PM in UTC-5,
toISOString()returns tomorrow's date whiletoTimeString()returns today's time.Fix: Use consistent local time formatting
function formatDateForInput(date: Date) { - return date.toISOString().slice(0, 10); + const year = date.getFullYear(); + const month = String(date.getMonth() + 1).padStart(2, "0"); + const day = String(date.getDate()).padStart(2, "0"); + return `${year}-${month}-${day}`; }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx` around lines 774 - 780, The date/time formatting is inconsistent: formatDateForInput uses UTC via toISOString() while formatTimeForInput uses local time via toTimeString(), which can produce off-by-one-day dates near midnight; update formatDateForInput to use local date fields (e.g., getFullYear(), getMonth()+1, getDate()) and zero-pad to produce a "YYYY-MM-DD" string consistent with formatTimeForInput (or alternatively make both use toLocaleDateString('en-CA') and a local time formatter) so both functions operate in the same timezone (functions: formatDateForInput and formatTimeForInput).
758-764:⚠️ Potential issue | 🟡 MinorSubmit button always shows "Event" text regardless of mode.
Line 763 hardcodes "Event" but should adapt based on
formValues.isEvent.Fix: Use task/event-aware copy
<Button type="submit" className="w-full disabled:opacity-40 sm:w-auto" disabled={isSubmitDisabled} > - {intent === "edit" ? "Update Event" : "Create Event"} + {intent === "edit" + ? formValues.isEvent ? "Update Event" : "Update Task" + : formValues.isEvent ? "Create Event" : "Create Task"} </Button>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx` around lines 758 - 764, The submit button currently hardcodes "Event" in its label; update the Button render (inside create-edit-dialog.tsx) to pick "Task" vs "Event" based on formValues.isEvent and still respect intent. Replace the current label expression ({intent === "edit" ? "Update Event" : "Create Event"}) with a conditional that uses formValues.isEvent to produce "Update Task"/"Create Task" when false and "Update Event"/"Create Event" when true, referencing the existing intent and formValues.isEvent variables so the button text adapts to both mode and type.
71-89:⚠️ Potential issue | 🟠 MajorEvent mode lacks inputs for required
taganddescriptionfields.The
defaultEventForm()initializestaganddescriptionto empty strings, but the event UI branch (lines 372-459) doesn't render inputs for these fields. PerEventFormValues, both are required—submitting with empty values will fail server validation.Why it matters: The API expects non-empty
taganddescriptionfor events. Users have no way to fill these fields.Suggested fix: Add inputs for tag and description in event mode
Add these fields inside the event date/time section or in the Details tab when
isEventis true:+ {formValues.isEvent && ( + <div className="space-y-4"> + <div className="space-y-2"> + <Label className="text-sm text-white/70">Event Tag</Label> + <Input + className={cn(baseField, "h-11")} + placeholder="e.g., workshop, social, hackathon" + value={formValues.event?.tag ?? ""} + onChange={(e) => updateEventForm("tag", e.target.value)} + /> + </div> + <div className="space-y-2"> + <Label className="text-sm text-white/70">Event Description</Label> + <Textarea + className={cn(baseField, "min-h-[100px] resize-none")} + placeholder="Describe the event..." + value={formValues.event?.description ?? ""} + onChange={(e) => updateEventForm("description", e.target.value)} + /> + </div> + </div> + )}🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx` around lines 71 - 89, defaultEventForm() sets required EventFormValues.tag and .description to empty strings but the event UI branch (the isEvent branch in create-edit-dialog.tsx that renders the event date/time and details) does not render inputs for these fields; add form inputs for "tag" and "description" to the event mode UI (either inside the event date/time section or the Details tab shown when isEvent is true) and wire them to the same form state handlers used elsewhere (the form field names must match EventFormValues.tag and EventFormValues.description and use the existing onChange/onBlur or form register functions so server validation can receive non-empty values on submit).
🧹 Nitpick comments (1)
apps/blade/src/app/_components/issues/create-edit-dialog.tsx (1)
677-680: Consider stable keys for link items.Using array index as
key(line 679) can cause React to misassociate DOM state when items are removed mid-list. Since links are simple strings, you could generate stable IDs when adding items.Why it matters: If a user deletes link 2 of 3, the input for link 3 might retain link 2's focus/cursor state.
Optional: Use stable IDs
- const createLinkItem = (): string => ""; + interface LinkEntry { + id: string; + url: string; + } + const createLinkItem = (): LinkEntry => ({ id: crypto.randomUUID(), url: "" });Then update the links array type and map by
link.id.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx` around lines 677 - 680, The map over formValues.links is using the array index as key (key={i}) which can break React reconciliation; change the links items to objects with a stable id and value (e.g., {id: string, url: string}) when creating/initializing links, generate the id in the add-link handler (use nanoid/uuid or a simple incrementer), update all consumers (the form state initialization, onChange handler, and remove handler) to read/write link.url and link.id, and then map using key={link.id} instead of the index so inputs keep stable identity when items are inserted/removed.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx`:
- Around line 547-557: The SelectItem values use priority.toLowerCase(), which
mismatches ISSUE.PRIORITY and formValues.priority (uppercase) and breaks
selection and onValueChange typing; update the SelectItem value to use the
original priority casing (value={priority}) or alternatively normalize values
consistently by converting incoming onValueChange to the enum casing inside the
handler (update the handler used by onValueChange in the create/edit dialog),
ensuring SelectItem, formValues.priority and onValueChange all use the same enum
casing (reference SelectItem, SelectContent, ISSUE.PRIORITY,
formValues.priority, and the onValueChange handler).
---
Duplicate comments:
In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx`:
- Around line 692-699: The delete button that renders the Trash2 icon lacks an
accessible label; update the Button rendered in create-edit-dialog.tsx (the
Button with onClick={() => handleRemoveLink(i)}) to include an aria-label (for
example aria-label={`Remove link ${i + 1}`} or a static "Remove link") so screen
readers receive context about the button's purpose while keeping the existing
onClick and styling.
- Around line 774-780: The date/time formatting is inconsistent:
formatDateForInput uses UTC via toISOString() while formatTimeForInput uses
local time via toTimeString(), which can produce off-by-one-day dates near
midnight; update formatDateForInput to use local date fields (e.g.,
getFullYear(), getMonth()+1, getDate()) and zero-pad to produce a "YYYY-MM-DD"
string consistent with formatTimeForInput (or alternatively make both use
toLocaleDateString('en-CA') and a local time formatter) so both functions
operate in the same timezone (functions: formatDateForInput and
formatTimeForInput).
- Around line 758-764: The submit button currently hardcodes "Event" in its
label; update the Button render (inside create-edit-dialog.tsx) to pick "Task"
vs "Event" based on formValues.isEvent and still respect intent. Replace the
current label expression ({intent === "edit" ? "Update Event" : "Create Event"})
with a conditional that uses formValues.isEvent to produce "Update Task"/"Create
Task" when false and "Update Event"/"Create Event" when true, referencing the
existing intent and formValues.isEvent variables so the button text adapts to
both mode and type.
- Around line 71-89: defaultEventForm() sets required EventFormValues.tag and
.description to empty strings but the event UI branch (the isEvent branch in
create-edit-dialog.tsx that renders the event date/time and details) does not
render inputs for these fields; add form inputs for "tag" and "description" to
the event mode UI (either inside the event date/time section or the Details tab
shown when isEvent is true) and wire them to the same form state handlers used
elsewhere (the form field names must match EventFormValues.tag and
EventFormValues.description and use the existing onChange/onBlur or form
register functions so server validation can receive non-empty values on submit).
---
Nitpick comments:
In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx`:
- Around line 677-680: The map over formValues.links is using the array index as
key (key={i}) which can break React reconciliation; change the links items to
objects with a stable id and value (e.g., {id: string, url: string}) when
creating/initializing links, generate the id in the add-link handler (use
nanoid/uuid or a simple incrementer), update all consumers (the form state
initialization, onChange handler, and remove handler) to read/write link.url and
link.id, and then map using key={link.id} instead of the index so inputs keep
stable identity when items are inserted/removed.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yml
Review profile: CHILL
Plan: Pro
Run ID: e745c88b-6e8c-4626-bbda-a945a5324001
📒 Files selected for processing (2)
apps/blade/src/app/_components/issues/create-edit-dialog.tsxpackages/consts/src/issue.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/consts/src/issue.ts
| <SelectContent> | ||
| {ISSUE.PRIORITY.map((priority) => ( | ||
| <SelectItem | ||
| key={priority} | ||
| value={priority.toLowerCase()} | ||
| > | ||
| {priority} | ||
| </SelectItem> | ||
| ))} | ||
| </SelectContent> | ||
| </Select> |
There was a problem hiding this comment.
Priority select value casing mismatch will break selection state.
SelectItem values are set to priority.toLowerCase() (line 551), but formValues.priority stores uppercase values from ISSUE.PRIORITY. This causes two problems:
- The current selection won't display (values don't match)
onValueChangereceives lowercase but the type expects uppercase
Fix: Keep values consistent with the enum:
Proposed fix
<SelectContent>
{ISSUE.PRIORITY.map((priority) => (
<SelectItem
key={priority}
- value={priority.toLowerCase()}
+ value={priority}
>
{priority}
</SelectItem>
))}
</SelectContent>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/blade/src/app/_components/issues/create-edit-dialog.tsx` around lines
547 - 557, The SelectItem values use priority.toLowerCase(), which mismatches
ISSUE.PRIORITY and formValues.priority (uppercase) and breaks selection and
onValueChange typing; update the SelectItem value to use the original priority
casing (value={priority}) or alternatively normalize values consistently by
converting incoming onValueChange to the enum casing inside the handler (update
the handler used by onValueChange in the create/edit dialog), ensuring
SelectItem, formValues.priority and onValueChange all use the same enum casing
(reference SelectItem, SelectContent, ISSUE.PRIORITY, formValues.priority, and
the onValueChange handler).
Why
For the Calendar/Task Manager sprint.
What
Issue(s): #398
Dialog to create or edit a new issue.
Test Plan
Merge me twin.
Checklist
db:pushbefore mergingSummary by CodeRabbit