-
Notifications
You must be signed in to change notification settings - Fork 417
Refactor utilities and cleanup legacy components #1583
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
354ed35
b3ccb72
157e751
fdeff9c
99174e7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,9 +1,9 @@ | ||
| import { addMonths, eachDayOfInterval, endOfMonth, format, getDay, isSameMonth, startOfMonth } from "@hypr/utils"; | ||
| import { clsx } from "clsx"; | ||
| import { addMonths, eachDayOfInterval, endOfMonth, format, getDay, isSameMonth, startOfMonth } from "date-fns"; | ||
| import { CalendarIcon, FileTextIcon, Pen } from "lucide-react"; | ||
| import { CalendarIcon, ChevronLeftIcon, ChevronRightIcon, FileTextIcon, Pen } from "lucide-react"; | ||
| import { useState } from "react"; | ||
|
|
||
| import { CalendarStructure } from "@hypr/ui/components/block/calendar-structure"; | ||
| import { Button } from "@hypr/ui/components/ui/button"; | ||
| import { Popover, PopoverContent, PopoverTrigger } from "@hypr/ui/components/ui/popover"; | ||
| import * as persisted from "../../../store/tinybase/persisted"; | ||
| import { type Tab, useTabs } from "../../../store/zustand/tabs"; | ||
|
|
@@ -43,6 +43,7 @@ export function TabContentCalendar({ tab }: { tab: Tab }) { | |
| const days = eachDayOfInterval({ start: monthStart, end: monthEnd }).map((day) => format(day, "yyyy-MM-dd")); | ||
| const startDayOfWeek = getDay(monthStart); | ||
| const weekDays = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"]; | ||
| const monthLabel = format(tab.month, "MMMM yyyy"); | ||
|
|
||
| const handlePreviousMonth = () => { | ||
| openCurrent({ ...tab, month: addMonths(tab.month, -1) }); | ||
|
|
@@ -58,18 +59,56 @@ export function TabContentCalendar({ tab }: { tab: Tab }) { | |
|
|
||
| return ( | ||
| <StandardTabWrapper> | ||
| <CalendarStructure | ||
| monthLabel={format(tab.month, "MMMM yyyy")} | ||
| weekDays={weekDays} | ||
| startDayOfWeek={startDayOfWeek} | ||
| onPreviousMonth={handlePreviousMonth} | ||
| onNextMonth={handleNextMonth} | ||
| onToday={handleToday} | ||
| > | ||
| {days.map((day) => ( | ||
| <TabContentCalendarDay key={day} day={day} isCurrentMonth={isSameMonth(new Date(day), tab.month)} /> | ||
| ))} | ||
| </CalendarStructure> | ||
| <div className="flex flex-col h-full rounded-lg border"> | ||
| <div className="p-4 pb-2 flex items-center relative "> | ||
| <div className="text-xl font-semibold absolute left-1/2 transform -translate-x-1/2">{monthLabel}</div> | ||
| <div className="flex h-fit rounded-md overflow-clip border border-neutral-200 ml-auto"> | ||
| <Button | ||
| variant="outline" | ||
| className="p-0.5 rounded-none border-none" | ||
| onClick={handlePreviousMonth} | ||
| > | ||
| <ChevronLeftIcon size={16} /> | ||
| </Button> | ||
|
|
||
| <Button | ||
| variant="outline" | ||
| className="text-sm px-1 py-0.5 rounded-none border-none" | ||
| onClick={handleToday} | ||
| > | ||
| Today | ||
| </Button> | ||
|
|
||
| <Button | ||
| variant="outline" | ||
| className="p-0.5 rounded-none border-none" | ||
| onClick={handleNextMonth} | ||
| > | ||
| <ChevronRightIcon size={16} /> | ||
| </Button> | ||
| </div> | ||
| </div> | ||
| <div className="h-full"> | ||
| <div className="grid grid-cols-7 border-b border-neutral-200"> | ||
| {weekDays.map((day) => ( | ||
| <div | ||
| key={day} | ||
| className="text-center text-sm font-medium text-muted-foreground p-2" | ||
| > | ||
| {day} | ||
| </div> | ||
| ))} | ||
| </div> | ||
| <div className="grid grid-cols-7 divide-x divide-neutral-200 h-[calc(100%-48px)] grid-rows-6 gap-0"> | ||
| {Array.from({ length: startDayOfWeek }).map((_, i) => ( | ||
| <div key={`empty-${i}`} className="border-b border-neutral-200" /> | ||
| ))} | ||
| {days.map((day) => ( | ||
| <TabContentCalendarDay key={day} day={day} isCurrentMonth={isSameMonth(new Date(day), tab.month)} /> | ||
| ))} | ||
| </div> | ||
| </div> | ||
|
Comment on lines
+102
to
+110
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fill trailing empty cells to complete the 6×7 calendar grid. Only leading blanks are rendered; trailing cells are missing, causing broken borders/layout in shorter months. Apply: @@
- const monthLabel = format(tab.month, "MMMM yyyy");
+ const monthLabel = format(tab.month, "MMMM yyyy");
+ // ensure grid is always 6x7
+ const TOTAL_CELLS = 42;
+ const trailingEmptyCount = Math.max(TOTAL_CELLS - (startDayOfWeek + days.length), 0);
@@
- <div className="grid grid-cols-7 divide-x divide-neutral-200 h-[calc(100%-48px)] grid-rows-6 gap-0">
+ <div className="grid grid-cols-7 divide-x divide-neutral-200 h-[calc(100%-48px)] grid-rows-6 gap-0">
{Array.from({ length: startDayOfWeek }).map((_, i) => (
<div key={`empty-${i}`} className="border-b border-neutral-200" />
))}
{days.map((day) => (
<TabContentCalendarDay key={day} day={day} isCurrentMonth={isSameMonth(new Date(day), tab.month)} />
))}
+ {Array.from({ length: trailingEmptyCount }).map((_, i) => (
+ <div key={`empty-trailing-${i}`} className="border-b border-neutral-200" />
+ ))}
</div>Also applies to: 46-47 🤖 Prompt for AI Agents |
||
| </div> | ||
| </StandardTabWrapper> | ||
| ); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,7 +1,7 @@ | ||
| import { SparklesIcon } from "lucide-react"; | ||
| import { useState } from "react"; | ||
|
|
||
| import { cn } from "@hypr/ui/lib/utils"; | ||
| import { cn } from "@hypr/utils"; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chainLGTM! Import path updated consistently. The refactoring to centralize utilities appears complete across all reviewed files. Consider running a codebase-wide verification to ensure no imports were missed. Run the following script to verify all import paths have been updated consistently: 🏁 Script executed: #!/bin/bash
# Verify all utility imports have been migrated to @hypr/utils
echo "=== Checking for any remaining old cn imports ==="
rg -n "from ['\"]@hypr/ui/lib/utils['\"]" -g '*.{ts,tsx}' -g '!node_modules'
echo -e "\n=== Verifying new @hypr/utils imports ==="
rg -n "from ['\"]@hypr/utils['\"]" -g '*.{ts,tsx}' -g '!node_modules' | head -20
echo -e "\n=== Checking @hypr/utils package exists and exports cn ==="
cat packages/utils/src/index.ts 2>/dev/null || echo "Could not find packages/utils/src/index.ts"
cat packages/utils/src/cn.ts 2>/dev/null || echo "Could not find packages/utils/src/cn.ts"Length of output: 2852 Incomplete import migration detected. Two files still use the old path. The refactoring is incomplete. While most imports have been updated to
These must be updated to import from 🤖 Prompt for AI Agents |
||
| import * as persisted from "../../../../../store/tinybase/persisted"; | ||
|
|
||
| import { FloatingButton } from "./shared"; | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,8 +1,8 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Icon } from "@iconify-icon/react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import useMediaQuery from "beautiful-react-hooks/useMediaQuery"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useCallback, useState } from "react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useCallback, useEffect, useState } from "react"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { SoundIndicator } from "@hypr/ui/components/block/sound-indicator"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { DancingSticks } from "@hypr/ui/components/ui/dancing-sticks"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { Spinner } from "@hypr/ui/components/ui/spinner"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useListener } from "../../../../../contexts/listener"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| import { useSTTConnection } from "../../../../../hooks/useSTTConnection"; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -88,6 +88,20 @@ function BeforeMeeingButton({ tab }: { tab: Extract<Tab, { type: "sessions" }> } | |||||||||||||||||||||||||||||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function SoundIndicator({ value, color }: { value: number | Array<number>; color?: string }) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const [amplitude, setAmplitude] = useState(0); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const u16max = 65535; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| useEffect(() => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const sample = Array.isArray(value) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ? (value.reduce((sum, v) => sum + v, 0) / value.length) / u16max | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| : value / u16max; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| setAmplitude(Math.min(sample, 1)); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, [value]); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return <DancingSticks amplitude={amplitude} color={color} size="long" />; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+91
to
+103
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chainHandle empty array edge case and verify value range assumptions. The amplitude calculation has a potential edge case issue:
const u16max = 65535;
useEffect(() => {
+ if (Array.isArray(value) && value.length === 0) {
+ setAmplitude(0);
+ return;
+ }
const sample = Array.isArray(value)
? (value.reduce((sum, v) => sum + v, 0) / value.length) / u16max
: value / u16max;
setAmplitude(Math.min(sample, 1));
}, [value]);
🏁 Script executed: #!/bin/bash
# Search for amplitude value assignments in listener context to verify range
rg -nP --type=ts --type=tsx -C5 'amplitude\s*[=:].*\{.*mic.*speaker.*\}' Length of output: 27 🏁 Script executed: #!/bin/bash
# Search for where amplitude object with mic/speaker properties is created/assigned
rg -nP -C8 'amplitude\s*[=:]\s*\{[^}]*mic' -g '*.ts' -g '*.tsx'Length of output: 2245 🏁 Script executed: #!/bin/bash
# Search for SoundIndicator usage and the amplitude values being passed
rg -nP -C5 'SoundIndicator' -g '*.ts' -g '*.tsx'Length of output: 2205 🏁 Script executed: #!/bin/bash
# Search for audio capture or amplitude processing that creates mic/speaker values
rg -nP -C5 '\.mic|\.speaker' -g '*.ts' -g '*.tsx' | head -100Length of output: 8082 🏁 Script executed: #!/bin/bash
# Check if there's any validation on payload values or plugin listener type definitions
rg -nP -C10 'audioAmplitude' -g '*.ts' -g '*.tsx'Length of output: 3987 🏁 Script executed: #!/bin/bash
# Search for @hypr/plugin-listener to understand the types
rg -nP '@hypr/plugin-listener' -g '*.ts' -g '*.tsx' -g '*.json'Length of output: 490 🏁 Script executed: #!/bin/bash
# Look for any normalization or validation of audio amplitude values
rg -nP -C5 'payload\.(mic|speaker)' -g '*.ts' -g '*.tsx'Length of output: 966 Remove incorrect empty array concern; fix normalization to clamp negative values. The empty array edge case is not applicable— However, the normalization logic has a real issue: const u16max = 65535;
useEffect(() => {
const sample = Array.isArray(value)
? (value.reduce((sum, v) => sum + v, 0) / value.length) / u16max
: value / u16max;
- setAmplitude(Math.min(sample, 1));
+ setAmplitude(Math.max(0, Math.min(sample, 1)));
}, [value]);📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
| function DuringMeetingButton() { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const stop = useListener((state) => state.stop); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const { amplitude, seconds } = useListener(({ amplitude, seconds }) => ({ amplitude, seconds })); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use
cnfrom@hypr/utilsand remove incorrectclsxnamed import.Named import
clsxbreaks (it’s a default export), and our standard iscnfor Tailwind merging. Replace usages accordingly. Based on learnings.Apply:
And merge into the first import:
Replace usages:
Also applies to: 163-167, 169-177, 176-184
🤖 Prompt for AI Agents