Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions apps/web/__tests__/unit/share-transcript-rendering.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -296,10 +296,12 @@ describe("share transcript rendering", () => {
await click(button("Save"));
expect(button("Save").disabled).toBe(true);
expect(button("Cancel").disabled).toBe(true);
await editCue(3);
expect(container.querySelector("textarea")?.value).toMatch(/^Cue 3:/);
expect(button("Save").disabled).toBe(true);
expect(button("Cancel").disabled).toBe(true);
expect(container.querySelector("textarea")?.disabled).toBe(true);
expect(
cue(3).parentElement?.querySelector(
'button[title="Edit transcript entry"]',
),
).toBeNull();
await act(async () => finish({ success: true }));
expect(container.querySelector("textarea")).toBeNull();
expect(container.textContent).toContain("Saved after waiting");
Expand Down
41 changes: 27 additions & 14 deletions apps/web/app/s/[videoId]/_components/tabs/Transcript.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -250,60 +250,73 @@ export const Transcript: React.FC<TranscriptProps> = ({ data, onSeek }) => {

const handleTranscriptClick = useCallback(
(entry: TranscriptEntry) => {
if (editingEntry === entry.id) {
if (isSaving || editingEntry === entry.id) {
return;
}

setSelectedEntry(entry.id);
onSeek?.(entry.startTime);
},
[editingEntry, onSeek],
[editingEntry, isSaving, onSeek],
);

const startEditing = useCallback((entry: TranscriptEntry) => {
setEditingEntry(entry.id);
}, []);
const startEditing = useCallback(
(entry: TranscriptEntry) => {
if (isSaving) {
return;
}
setEditingEntry(entry.id);
},
[isSaving],
);

const cancelEditing = () => {
const cancelEditing = useCallback(() => {
if (isSaving) {
return;
}
setEditingEntry(null);
};
}, [isSaving]);

const saveEdit = async (editText: string) => {
const normalizedEditText = normalizeTranscriptCueText(editText);

if (!editingEntry || !normalizedEditText) {
if (!editingEntry || !normalizedEditText || isSaving) {
return;
}

const entryIdToSave = editingEntry;

setIsSaving(true);
try {
const result = await editTranscriptEntry(
data.id,
editingEntry,
entryIdToSave,
normalizedEditText,
);

if (result.success) {
setTranscriptData((prev) =>
prev.map((entry) =>
entry.id === editingEntry
entry.id === entryIdToSave
? { ...entry, text: normalizedEditText }
: entry,
),
);
setEditingEntry(null);
setEditingEntry((current) =>
current === entryIdToSave ? null : current,
);
invalidateTranscript(data.id);
} else {
console.error("[Transcript] Failed to save transcript edit:", {
entryId: editingEntry,
entryId: entryIdToSave,
videoId: data.id,
errorMessage: result.message,
result,
});
}
} catch (error) {
console.error("[Transcript] Error saving transcript edit:", {
entryId: editingEntry,
entryId: entryIdToSave,
videoId: data.id,
error: error instanceof Error ? error.message : error,
stack: error instanceof Error ? error.stack : undefined,
Expand Down Expand Up @@ -808,7 +821,7 @@ export const Transcript: React.FC<TranscriptProps> = ({ data, onSeek }) => {
key={entry.id}
entry={entry}
selected={selectedEntry === entry.id}
canEdit={canEdit}
canEdit={canEdit && !isSaving}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P1 Existing transcript test fails

The pending-save test in share-transcript-rendering.test.ts:299 calls editCue(3) while a save is pending. This change removes that row's edit button, so the helper throws Missing edit button before the test finishes. Update the test to expect editing to stay blocked, check that the textarea is disabled, and then resolve the save.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/web/app/s/[videoId]/_components/tabs/Transcript.tsx
Line: 824

Comment:
**Existing transcript test fails**

The pending-save test in `share-transcript-rendering.test.ts:299` calls `editCue(3)` while a save is pending. This change removes that row's edit button, so the helper throws `Missing edit button` before the test finishes. Update the test to expect editing to stay blocked, check that the textarea is disabled, and then resolve the save.

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in commit \2c33594b: updated test assertions in \share-transcript-rendering.test.ts\ to verify the active textarea is disabled, other cue edit buttons remain blocked (null) during pending saves, and then resolves the save cleanly.

onSelect={handleTranscriptClick}
onEdit={startEditing}
/>
Expand Down
3 changes: 2 additions & 1 deletion apps/web/app/s/[videoId]/_components/tabs/transcript-row.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ export function TranscriptEditor({
<textarea
value={editText}
onChange={(e) => setEditText(e.target.value)}
className="w-full resize-none rounded-lg border border-gray-4 bg-gray-1 p-2.5 text-[13px] leading-[22px] text-gray-12 outline-none transition placeholder:text-gray-8 focus:border-blue-500/60 focus:ring-2 focus:ring-blue-500/20"
disabled={isSaving}
className="w-full resize-none rounded-lg border border-gray-4 bg-gray-1 p-2.5 text-[13px] leading-[22px] text-gray-12 outline-none transition placeholder:text-gray-8 focus:border-blue-500/60 focus:ring-2 focus:ring-blue-500/20 disabled:cursor-not-allowed disabled:opacity-50"
rows={Math.max(2, Math.ceil(editText.length / 60))}
onClick={(e) => e.stopPropagation()}
placeholder="Edit transcript text..."
Expand Down
Loading