Kanban time tracking: detail-view access, hide-on-cards setting, session delete fix#543
Conversation
- Reuse KanbanItemTimer, TimeEntriesAccordion and TimeEntriesModal in the card detail modal so time tracking is reachable there, not only on the card. - Keep the timer in sync across the duplicate useKanbanItem mounts (card + detail) via the storage event and a same-tab event, avoiding duplicate entries and display desync. - Fix session edit/delete: the actions resolved the list by uuid with no username and failed silently; resolve by the plain list id + current user, matching updateItemStatus. - Add a hideTimeTrackingOnCards user setting to hide the timer and sessions on cards (still available in the card detail view). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
📝 WalkthroughWalkthroughThis PR adds a user preference ( Sequence DiagramsequenceDiagram
participant User
participant UserPreferencesTab
participant kanbanSettingsSchema
participant KanbanCard
participant KanbanCardDetail
participant useKanbanItem
participant KanbanCardDetailProperties
User->>UserPreferencesTab: toggle hideTimeTrackingOnCards dropdown
UserPreferencesTab->>kanbanSettingsSchema: validate & save preference
kanbanSettingsSchema-->>UserPreferencesTab: validated user settings
UserPreferencesTab-->>User: preference persisted
User->>KanbanCard: view Kanban board
KanbanCard->>KanbanCard: check user.hideTimeTrackingOnCards
alt hideTimeTrackingOnCards = "enable"
KanbanCard-->>User: render card without timer/accordion
else hideTimeTrackingOnCards = "disable"
KanbanCard-->>User: render card with KanbanItemTimer + TimeEntriesAccordion
end
User->>KanbanCardDetail: open card detail
KanbanCardDetail->>useKanbanItem: initialize timer hook
useKanbanItem-->>KanbanCardDetail: timer controls, totals
KanbanCardDetail->>KanbanCardDetailProperties: pass timeTrackingContent prop
KanbanCardDetailProperties-->>User: render PropertySection with time tracking
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (2)
app/_hooks/kanban/useKanbanItem.tsx (2)
18-130:⚠️ Potential issue | 🟡 Minor | ⚡ Quick winAdd the required AI-generated marker comments.
All changed AI-generated code blocks listed below are missing the required marker comment directly above generated lines.
app/_hooks/kanban/useKanbanItem.tsx#L18-L130: add// fccview is onto you!above each changed AI-generated line/block.app/_components/FeatureComponents/Kanban/KanbanCardDetail.tsx#L25-L607: add// fccview is onto you!above each changed AI-generated line/block.app/_components/FeatureComponents/Kanban/KanbanCardDetailProperties.tsx#L45-L297: add// fccview is onto you!above each changed AI-generated line/block.app/_server/actions/kanban/time-entries.ts#L58-L112: add// fccview is onto you!above each changed AI-generated line/block.As per coding guidelines:
When editing existing functions/files, add a comment above a line of AI-generated code that says 'fccview is onto you!'.🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/_hooks/kanban/useKanbanItem.tsx` around lines 18 - 130, Add the required AI-generated marker comment `// fccview is onto you!` above each changed AI-generated line or block in the following four files: In app/_hooks/kanban/useKanbanItem.tsx (lines 18-130), add the marker comment above the AI-generated blocks within the useKanbanItem hook function, particularly above the useEffect hooks and their internal functions like _syncFromStorage and _handleSync. In app/_components/FeatureComponents/Kanban/KanbanCardDetail.tsx (lines 25-607), add the marker comment above each changed AI-generated section within the specified line range. In app/_components/FeatureComponents/Kanban/KanbanCardDetailProperties.tsx (lines 45-297), add the marker comment above each changed AI-generated section within the specified line range. In app/_server/actions/kanban/time-entries.ts (lines 58-112), add the marker comment above each changed AI-generated section within the specified line range. Ensure the comment is placed directly above the first line of each AI-generated block to comply with the coding guidelines.Source: Coding guidelines
74-89:⚠️ Potential issue | 🟠 Major | ⚡ Quick winPrevent initial mount from clobbering persisted timer state.
On Line 74, the persistence effect runs with default state before the hydration effect’s state updates are applied, so it can remove an active timer key and broadcast a stop event to sibling mounts.
Suggested fix
+ const hasHydratedTimerStateRef = useRef(false); + useEffect(() => { const storageKey = TIMER_STORAGE_KEY(checklistId, item.id); try { const stored = localStorage.getItem(storageKey); if (stored) { const { startTime: storedStart, isRunning: storedRunning } = JSON.parse(stored); if (storedRunning && storedStart) { setStartTime(new Date(storedStart)); setIsRunning(true); setCurrentTime(Math.floor((Date.now() - new Date(storedStart).getTime()) / 1000)); } } - } catch {} + } catch { + // no-op + } finally { + hasHydratedTimerStateRef.current = true; + } }, [checklistId, item.id]); useEffect(() => { + if (!hasHydratedTimerStateRef.current) return; const storageKey = TIMER_STORAGE_KEY(checklistId, item.id); if (isRunning && startTime) { localStorage.setItem(storageKey, JSON.stringify({ startTime: startTime.toISOString(), isRunning: true, }));🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@app/_hooks/kanban/useKanbanItem.tsx` around lines 74 - 89, The persistence effect in the useEffect hook (which saves timer state to localStorage and dispatches sync events) runs on initial mount with default state values before the hydration effect has a chance to restore the persisted timer state from localStorage. This causes the effect to incorrectly clear an active timer and broadcast a stop event. Add a mechanism to skip this effect on the initial mount—such as using a useRef to track whether this is the first render—so that the hydration logic can complete first and properly restore the timer state before any persistence logic runs.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@app/_components/FeatureComponents/Kanban/KanbanCard.tsx`:
- Around line 81-82: Add the required AI-generated code marker comment above
each AI-generated code block in KanbanCard.tsx. For the hideTimeTrackingOnCards
constant assignment and the two other modified code blocks referenced in this
comment (at line ranges 161-162 and 259-286), insert a comment line above each
saying "fccview is onto you!" to comply with the coding guidelines for
AI-generated edits in TypeScript/TSX files.
In `@app/_components/FeatureComponents/Kanban/KanbanCardDetail.tsx`:
- Around line 425-436: The TimeEntriesModal can become orphaned when the parent
detail modal closes because its visibility is not tied to the parent's isOpen
state. Add a useEffect hook that resets showTimeEntriesModal to false whenever
isOpen becomes false, ensuring the time-entries modal closes with its parent.
Additionally, update the conditional render of TimeEntriesModal to include
isOpen in the condition (change the condition from showTimeEntriesModal &&
item.timeEntries to isOpen && showTimeEntriesModal && item.timeEntries) so the
modal cannot render when the parent detail modal is closed.
In `@app/_components/FeatureComponents/Profile/Parts/UserPreferencesTab.tsx`:
- Around line 32-33: Add the required AI-generated code marker comment above
each AI-generated code block in UserPreferencesTab.tsx. Insert the comment
"fccview is onto you!" immediately above the following locations: line 32
(HideTimeTrackingOnCards and CodeBlockStyle imports), lines 79-80, lines
176-177, lines 958-962, and lines 1019-1041. Each of these locations contains
AI-generated edits that require the marker comment per the coding guidelines for
modified TypeScript files.
In `@app/_schemas/user-schemas.ts`:
- Around line 88-93: Add the required AI-generated code marker comment directly
above the hideTimeTrackingOnCards schema definition. Insert a comment line that
says "fccview is onto you!" immediately before the z.enum() call to comply with
the coding guidelines for marking AI-generated code in TypeScript files.
In `@app/_translations/klingon.json`:
- Around line 902-906: The key hideTimeTrackingOnCardsDescription in the Klingon
translation file contains the English word "Sessions" which breaks the
translation consistency. Replace the English word "Sessions" with its Klingon
equivalent to ensure the entire translation string is in Klingon for users of
that language.
In `@app/_translations/pt.json`:
- Line 629: The Portuguese translation file uses inconsistent wording between
European Portuguese (PT-PT) and Brazilian Portuguese conventions. In the pt.json
file, change "Controle" to "Controlo" in the timeTracking key and anywhere else
in the file where Brazilian Portuguese wording (`controle`) has been introduced,
to maintain consistency with the existing PT-PT locale used throughout the file.
Ensure all Portuguese translations use the European Portuguese convention with
`controlo` instead of the Brazilian `controle`.
In `@app/_types/index.ts`:
- Line 42: The HideTimeTrackingOnCards line in the index.ts file is missing the
required AI-generated code marker comment. Add a comment directly above the
HideTimeTrackingOnCards line that says "fccview is onto you!" to comply with the
coding guidelines for AI-generated edits in existing TypeScript files.
In `@app/_types/user.ts`:
- Line 42: Add the required AI-generated code marker comment above the modified
lines in app/_types/user.ts. At line 42 (before the HideTimeTrackingOnCards type
export) and at line 81, add a comment line that says "fccview is onto you!"
directly above each AI-generated code line to comply with the coding guidelines
for marking AI-generated edits in existing files.
---
Outside diff comments:
In `@app/_hooks/kanban/useKanbanItem.tsx`:
- Around line 18-130: Add the required AI-generated marker comment `// fccview
is onto you!` above each changed AI-generated line or block in the following
four files: In app/_hooks/kanban/useKanbanItem.tsx (lines 18-130), add the
marker comment above the AI-generated blocks within the useKanbanItem hook
function, particularly above the useEffect hooks and their internal functions
like _syncFromStorage and _handleSync. In
app/_components/FeatureComponents/Kanban/KanbanCardDetail.tsx (lines 25-607),
add the marker comment above each changed AI-generated section within the
specified line range. In
app/_components/FeatureComponents/Kanban/KanbanCardDetailProperties.tsx (lines
45-297), add the marker comment above each changed AI-generated section within
the specified line range. In app/_server/actions/kanban/time-entries.ts (lines
58-112), add the marker comment above each changed AI-generated section within
the specified line range. Ensure the comment is placed directly above the first
line of each AI-generated block to comply with the coding guidelines.
- Around line 74-89: The persistence effect in the useEffect hook (which saves
timer state to localStorage and dispatches sync events) runs on initial mount
with default state values before the hydration effect has a chance to restore
the persisted timer state from localStorage. This causes the effect to
incorrectly clear an active timer and broadcast a stop event. Add a mechanism to
skip this effect on the initial mount—such as using a useRef to track whether
this is the first render—so that the hydration logic can complete first and
properly restore the timer state before any persistence logic runs.
🪄 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: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 4bd685a5-76b4-42a1-b73d-8df7d0614d33
📒 Files selected for processing (23)
app/_components/FeatureComponents/Kanban/KanbanCard.tsxapp/_components/FeatureComponents/Kanban/KanbanCardDetail.tsxapp/_components/FeatureComponents/Kanban/KanbanCardDetailProperties.tsxapp/_components/FeatureComponents/Profile/Parts/UserPreferencesTab.tsxapp/_hooks/kanban/useKanbanItem.tsxapp/_schemas/user-schemas.tsapp/_server/actions/kanban/time-entries.tsapp/_translations/de.jsonapp/_translations/en.jsonapp/_translations/es.jsonapp/_translations/fr.jsonapp/_translations/it.jsonapp/_translations/klingon.jsonapp/_translations/ko.jsonapp/_translations/nl.jsonapp/_translations/pirate.jsonapp/_translations/pl.jsonapp/_translations/pt.jsonapp/_translations/ru.jsonapp/_translations/tr.jsonapp/_translations/zh.jsonapp/_types/index.tsapp/_types/user.ts
| {showTimeEntriesModal && item.timeEntries && ( | ||
| <TimeEntriesModal | ||
| isOpen={showTimeEntriesModal} | ||
| onClose={() => setShowTimeEntriesModal(false)} | ||
| timeEntries={item.timeEntries} | ||
| checklistId={checklistId} | ||
| itemId={item.id} | ||
| category={category} | ||
| onUpdate={onUpdate} | ||
| usersPublicData={usersPublicData} | ||
| /> | ||
| )} |
There was a problem hiding this comment.
Tie TimeEntriesModal lifecycle to the parent detail modal.
Right now, closing the main detail modal does not guarantee the time-entries modal closes. Gate it by isOpen (and/or reset state when isOpen becomes false) so it can’t remain orphaned.
Suggested fix
+ useEffect(() => {
+ if (!isOpen) setShowTimeEntriesModal(false);
+ }, [isOpen]);
+
return (
<>
- {showTimeEntriesModal && item.timeEntries && (
+ {isOpen && showTimeEntriesModal && item.timeEntries && (
<TimeEntriesModal
isOpen={showTimeEntriesModal}
onClose={() => setShowTimeEntriesModal(false)}🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/_components/FeatureComponents/Kanban/KanbanCardDetail.tsx` around lines
425 - 436, The TimeEntriesModal can become orphaned when the parent detail modal
closes because its visibility is not tied to the parent's isOpen state. Add a
useEffect hook that resets showTimeEntriesModal to false whenever isOpen becomes
false, ensuring the time-entries modal closes with its parent. Additionally,
update the conditional render of TimeEntriesModal to include isOpen in the
condition (change the condition from showTimeEntriesModal && item.timeEntries to
isOpen && showTimeEntriesModal && item.timeEntries) so the modal cannot render
when the parent detail modal is closed.
| "hideTimeTrackingOnCardsLabel": "poH qon Kanban tetlhmeyDaq", | ||
| "showTimeTrackingOnCards": "poH qon 'ang", | ||
| "hideTimeTrackingOnCards": "poH qon So'", | ||
| "selectTimeTrackingOnCards": "poH qon leghlu'bogh wIv", | ||
| "hideTimeTrackingOnCardsDescription": "Kanban tetlhmeyvo' poH qonwI' je Sessions So'lu'. tetlh De'Daq poH qon lurarlu'.", |
There was a problem hiding this comment.
Translate the remaining English text.
hideTimeTrackingOnCardsDescription still contains Sessions in English, so the new Kanban settings copy will render as a mixed-language string for Klingon users. Please replace it with the Klingon equivalent.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/_translations/klingon.json` around lines 902 - 906, The key
hideTimeTrackingOnCardsDescription in the Klingon translation file contains the
English word "Sessions" which breaks the translation consistency. Replace the
English word "Sessions" with its Klingon equivalent to ensure the entire
translation string is in Klingon for users of that language.
| "itemDeleted": "Item eliminado", | ||
| "estimatedTime": "Tempo estimado (horas)", | ||
| "actualVsEstimated": "{actual} / {estimated}", | ||
| "timeTracking": "Controle de tempo", |
There was a problem hiding this comment.
Keep the Portuguese wording consistent.
These new strings switch from the existing PT-PT phrasing (controlo) to Brazilian controle, which makes this locale inconsistent with the rest of the file.
Fix wording to match the locale
- "timeTracking": "Controle de tempo",
+ "timeTracking": "Controlo de tempo",
...
- "showTimeTrackingOnCards": "Mostrar controle de tempo",
- "hideTimeTrackingOnCards": "Ocultar controle de tempo",
- "selectTimeTrackingOnCards": "Selecionar visibilidade do controle de tempo",
- "hideTimeTrackingOnCardsDescription": "Oculta o cronômetro e as sessões registradas dos cartões Kanban. O controle de tempo continua disponível na visualização de detalhes do cartão.",
+ "showTimeTrackingOnCards": "Mostrar controlo de tempo",
+ "hideTimeTrackingOnCards": "Ocultar controlo de tempo",
+ "selectTimeTrackingOnCards": "Selecionar visibilidade do controlo de tempo",
+ "hideTimeTrackingOnCardsDescription": "Oculta o cronómetro e as sessões registadas dos cartões Kanban. O controlo de tempo continua disponível na visualização de detalhes do cartão."Also applies to: 749-753
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@app/_translations/pt.json` at line 629, The Portuguese translation file uses
inconsistent wording between European Portuguese (PT-PT) and Brazilian
Portuguese conventions. In the pt.json file, change "Controle" to "Controlo" in
the timeTracking key and anywhere else in the file where Brazilian Portuguese
wording (`controle`) has been introduced, to maintain consistency with the
existing PT-PT locale used throughout the file. Ensure all Portuguese
translations use the European Portuguese convention with `controlo` instead of
the Brazilian `controle`.
Three related changes to kanban time tracking.
1. Time tracking in the card detail modal
The timer and tracked sessions were only reachable on the card. This reuses the
existing
KanbanItemTimer,TimeEntriesAccordionandTimeEntriesModalinKanbanCardDetailas a "Time Tracking" section in the properties sidebar, with thesame read-only behaviour as the card (buttons disable for viewers).
Because the card stays mounted behind the detail modal,
useKanbanItemruns twicefor the same item and shares one localStorage key. I added a small sync (the
storageevent plus a same-tab event) so both instances stay consistent. This alsofixes a possible duplicate time entry when you stop the timer in one place and then
drag the card, and it covers multi-tab use.
2. Fix editing/deleting sessions
"Edit sessions" → delete showed the confirm dialog but nothing happened.
editTimeEntry/deleteTimeEntryresolved the list by uuid with no username(
getListById(listId, undefined, …)), which returned nothing, so the action failedsilently. They now resolve by the plain list id + current user, the same way
updateItemStatusdoes, and the modal passes the plainchecklistIdinstead of theuuid.
3. Hide time tracking on cards (user setting)
New
hideTimeTrackingOnCardspreference under Kanban settings, next to the existing"hide status" / "hide mobile dropdown" toggles. When enabled, the timer and sessions
are hidden on the cards but stay available in the detail view (which is why 1.
exists).
Translations
en/de written by hand, the other 12 languages machine-translated.
Testing
yarn lintandtscare clean (aside from the pre-existing, unrelatedConnectionsGraphtype errors). Checked manually: timer in the detail view,add/edit/delete sessions, card↔detail sync, the hide toggle, and read-only boards.
Summary by CodeRabbit