🪻 distributed transcription service thistle.dunkirk.sh
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: allow selecting a date for the recording

+58 -18
+58 -18
src/components/upload-recording-modal.ts
··· 30 30 @state() private uploadComplete = false; 31 31 @state() private uploadedTranscriptionId: string | null = null; 32 32 @state() private submitting = false; 33 + @state() private selectedDate: string = ""; 33 34 34 35 static override styles = css` 35 36 :host { ··· 230 231 231 232 .meeting-time-selector { 232 233 display: flex; 233 - flex-direction: column; 234 234 gap: 0.5rem; 235 235 } 236 236 ··· 292 292 this.uploadComplete = false; 293 293 this.uploadedTranscriptionId = null; 294 294 this.submitting = false; 295 + this.selectedDate = ""; 295 296 296 297 if (this.selectedFile && this.classId) { 298 + // Set initial date from file 299 + const fileDate = new Date(this.selectedFile.lastModified); 300 + this.selectedDate = fileDate.toISOString().split("T")[0] || ""; 297 301 // Start both detection and upload in parallel 298 302 this.detectMeetingTime(); 299 303 this.startBackgroundUpload(); ··· 360 364 } 361 365 362 366 private async detectMeetingTime() { 363 - if (!this.selectedFile || !this.classId) return; 367 + if (!this.classId) return; 364 368 365 369 this.detectingMeetingTime = true; 366 370 367 371 try { 368 372 const formData = new FormData(); 369 - formData.append("audio", this.selectedFile); 370 373 formData.append("class_id", this.classId); 371 374 372 - // Send the file's original lastModified timestamp (preserved by browser) 373 - // This is more accurate than server-side file timestamps 374 - if (this.selectedFile.lastModified) { 375 - formData.append( 376 - "file_timestamp", 377 - this.selectedFile.lastModified.toString(), 378 - ); 375 + // Use selected date or file's lastModified timestamp 376 + let timestamp: number; 377 + if (this.selectedDate) { 378 + // Convert YYYY-MM-DD to timestamp (noon local time to avoid timezone issues) 379 + const date = new Date(`${this.selectedDate}T12:00:00`); 380 + timestamp = date.getTime(); 381 + } else if (this.selectedFile?.lastModified) { 382 + timestamp = this.selectedFile.lastModified; 383 + } else { 384 + return; 379 385 } 386 + 387 + formData.append("file_timestamp", timestamp.toString()); 380 388 381 389 const response = await fetch("/api/transcriptions/detect-meeting-time", { 382 390 method: "POST", ··· 403 411 404 412 private handleMeetingTimeSelect(meetingTimeId: string) { 405 413 this.selectedMeetingTimeId = meetingTimeId; 414 + } 415 + 416 + private handleDateChange(e: Event) { 417 + const input = e.target as HTMLInputElement; 418 + this.selectedDate = input.value; 419 + // Re-detect meeting time when date changes 420 + if (this.selectedDate && this.classId) { 421 + this.detectMeetingTime(); 422 + } 406 423 } 407 424 408 425 private handleSectionChange(e: Event) { ··· 458 475 this.uploadProgress = 0; 459 476 this.uploadedTranscriptionId = null; 460 477 this.submitting = false; 478 + this.selectedDate = ""; 461 479 this.dispatchEvent(new CustomEvent("close")); 462 480 } 463 481 ··· 506 524 this.selectedFile 507 525 ? html` 508 526 <div class="form-group"> 527 + <label for="date">Recording Date</label> 528 + <input 529 + type="date" 530 + id="date" 531 + .value=${this.selectedDate} 532 + @change=${this.handleDateChange} 533 + ?disabled=${this.uploading} 534 + style="padding: 0.75rem; border: 1px solid var(--secondary); border-radius: 4px; font-size: 0.875rem; color: var(--text); background: var(--background);" 535 + /> 536 + <div class="help-text"> 537 + Change the date to detect the correct meeting time 538 + </div> 539 + </div> 540 + 541 + <div class="form-group"> 509 542 <label>Meeting Time</label> 510 543 ${ 511 544 this.detectingMeetingTime ··· 540 573 } 541 574 542 575 ${ 543 - this.sections.length > 1 && this.selectedFile 576 + this.sections.length > 0 && this.selectedFile 544 577 ? html` 545 578 <div class="form-group"> 546 - <label for="section">Section (optional)</label> 579 + <label for="section">Section</label> 547 580 <select 548 581 id="section" 549 582 @change=${this.handleSectionChange} 550 583 ?disabled=${this.uploading} 584 + .value=${this.selectedSectionId || this.userSection || ""} 551 585 > 552 586 <option value="">Use my section ${this.userSection ? `(${this.sections.find((s) => s.id === this.userSection)?.section_number})` : ""}</option> 553 - ${this.sections.map( 554 - (section) => html` 587 + ${this.sections 588 + .filter((section) => section.id !== this.userSection) 589 + .map( 590 + (section) => html` 555 591 <option value=${section.id}>${section.section_number}</option> 556 592 `, 557 - )} 593 + )} 558 594 </select> 559 595 <div class="help-text"> 560 - Override which section this recording is for 596 + Select which section this recording is for (defaults to your section) 561 597 </div> 562 598 </div> 563 599 ` ··· 597 633 <button class="btn-cancel" @click=${this.handleClose} ?disabled=${this.uploading || this.submitting}> 598 634 Cancel 599 635 </button> 600 - ${this.uploadComplete && this.selectedMeetingTimeId ? html` 636 + ${ 637 + this.uploadComplete && this.selectedMeetingTimeId 638 + ? html` 601 639 <button class="btn-upload" @click=${this.handleSubmit} ?disabled=${this.submitting}> 602 640 ${this.submitting ? "Submitting..." : "Confirm & Submit"} 603 641 </button> 604 - ` : ""} 642 + ` 643 + : "" 644 + } 605 645 </div> 606 646 </div> 607 647 </div>