Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
6eeae28
Integrate billing popup, usage sidebar, and credit preview toggle
CJWTRUST Jan 20, 2026
160e082
Recover lost commit 488b47c and restore branch head
google-labs-jules[bot] Jan 28, 2026
ae085cf
Merge pull request #456 from QueueLab/jules-16847885310673003402-db9c…
ngoiyaeric Jan 28, 2026
73c385c
Restore branch history to 488b47c and integrate latest fixes
google-labs-jules[bot] Jan 28, 2026
1508c04
Restore branch history to 488b47c and resolve build errors
google-labs-jules[bot] Jan 28, 2026
c8c028b
Restore branch history, fix build errors, and re-enable pricing popup
google-labs-jules[bot] Jan 28, 2026
e2c0615
Finalize recovery with performance optimizations and UI fixes
google-labs-jules[bot] Jan 28, 2026
43179e7
Synchronize with main, restore history, and optimize performance
google-labs-jules[bot] Jan 29, 2026
7d45e02
Finalize recovery with prioritized main branch code and usage UI
google-labs-jules[bot] Jan 29, 2026
5623831
Refine usage UI and Lottie animation visibility
google-labs-jules[bot] Jan 29, 2026
44e86b6
Complete recovery, synchronization with main, and usage UI integration
google-labs-jules[bot] Jan 29, 2026
0a48018
feat: recover branch state, optimize resolution search, and fix UI st…
google-labs-jules[bot] Jan 29, 2026
6acfbe5
fix: resolve build error and ESLint warnings
google-labs-jules[bot] Jan 29, 2026
8ae549a
Update LICENSE
ngoiyaeric Feb 1, 2026
3495da1
Update LICENSE
ngoiyaeric Feb 1, 2026
ba36e58
Merge pull request #469 from QueueLab/ngoiyaeric-patch-4
ngoiyaeric Feb 1, 2026
6431b41
fix: reduce padding in mobile chat input area
google-labs-jules[bot] Feb 1, 2026
8a04d49
Merge pull request #470 from QueueLab/fix/mobile-chat-input-padding-1…
ngoiyaeric Feb 1, 2026
10ab3fe
feat: update Stripe checkout links to new URL
google-labs-jules[bot] Feb 1, 2026
250283e
Merge pull request #471 from QueueLab/update-stripe-links-17354207767…
ngoiyaeric Feb 1, 2026
6554775
fix: ensure long sentences wrap to the next line across UI components
google-labs-jules[bot] Feb 1, 2026
e95a25b
Merge pull request #473 from QueueLab/fix/text-overflow-wrapping-4739…
ngoiyaeric Feb 1, 2026
f80c87f
Resolve merge conflicts and synchronize with main
CJWTRUST Feb 2, 2026
c4278e9
feat: final stability and performance improvements
google-labs-jules[bot] Feb 2, 2026
813d264
Resolve merge conflicts and synchronize with main, preserving branch …
google-labs-jules[bot] Feb 2, 2026
c868dcd
Merge branch 'feature/billing-integration-recovery-648258468266820429…
ngoiyaeric Feb 2, 2026
3b5ed27
Resolve merge conflicts: synchronization with main while preserving b…
google-labs-jules[bot] Feb 2, 2026
3984b9b
Restore missing features from commit c4278e9: tenttree usage UI, popu…
CJWTRUST Feb 2, 2026
f45f687
Merge branch 'main' into jules-8488824498232079115-26d4e4cd
ngoiyaeric Feb 2, 2026
67c26d5
Merge pull request #476 from QueueLab/jules-8488824498232079115-26d4e4cd
ngoiyaeric Feb 2, 2026
a842df1
chore: update stripe payment links
google-labs-jules[bot] Feb 2, 2026
184f678
Merge pull request #477 from QueueLab/update-stripe-links-20260202-15…
ngoiyaeric Feb 2, 2026
9377934
feat: integrate resolution search fixes and mobile UI improvements
google-labs-jules[bot] Feb 2, 2026
895bf37
Update UsageView to yearly refresh model
google-labs-jules[bot] Feb 2, 2026
dc345b9
Update usage-view.tsx
ngoiyaeric Feb 2, 2026
86013ed
Update usage-view.tsx
ngoiyaeric Feb 2, 2026
2ba1f9e
Merge pull request #479 from QueueLab/update-usage-view-to-yearly-ref…
ngoiyaeric Feb 2, 2026
a77a5d4
Merge branch 'main' into integrate-resolution-search-and-ui-fixes-545…
ngoiyaeric Feb 2, 2026
5814452
feat: integrate resolution search fixes, mobile UI improvements, and …
google-labs-jules[bot] Feb 2, 2026
307738b
feat: fix resolution search response and improve UI responsiveness
google-labs-jules[bot] Feb 2, 2026
df52ed9
feat: integrate targeted fixes and UI improvements from PRs #466-#473
google-labs-jules[bot] Feb 2, 2026
dda7a32
fix: standardize header icon spacing and remove unused portals
google-labs-jules[bot] Feb 2, 2026
af8012e
feat: consolidated update of PR features and UI refinements
google-labs-jules[bot] Feb 2, 2026
23a1d3f
Merge pull request #480 from QueueLab/fix-header-icon-spacing-1628392…
ngoiyaeric Feb 2, 2026
a9bf40d
fix(resolution-search): use uiStream.append instead of update to fix …
CJWTRUST Feb 2, 2026
d519390
Merge branch 'main' into integrate-resolution-search-and-ui-fixes-545…
ngoiyaeric Feb 2, 2026
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
Binary file added CC BY-NC 4.0.docx
Binary file not shown.
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ APPENDIX: How to apply the Apache License to your work.
same "printed page" as the copyright notice for easier
identification within third-party archives.

Copyright 2024 Yoshiki Miura
Copyright 2025 Eric Ngoiya

Comment on lines +189 to 190
Copy link

Choose a reason for hiding this comment

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

The LICENSE boilerplate line is being edited to a specific person/year. This may be legally incorrect if the project is not solely authored/owned by that person, and it may conflict with repository ownership/CLA expectations.

This is not a code issue but it is a release-blocking compliance risk if inaccurate.

Suggestion

Confirm the correct copyright holder for the repository (individual vs organization) and ensure this line matches the project’s legal ownership and contribution model. If this was accidental, revert this line and manage attribution via NOTICE/AUTHORS instead.

Reply with "@CharlieHelps yes please" if you'd like me to add a commit reverting the LICENSE line pending confirmation.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
23 changes: 10 additions & 13 deletions app/actions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,14 @@ async function submit(formData?: FormData, skip?: boolean) {
// Create a streamable value for the summary.
const summaryStream = createStreamableValue<string>('');

async function processResolutionSearch() {
// Immediately append the BotMessage component to the UI stream.
uiStream.append(
<Section title="response">
<BotMessage content={summaryStream.value} />
</Section>
);

(async () => {
try {
// Call the simplified agent, which now returns a stream.
const streamResult = await resolutionSearch(messages, timezone, drawnFeatures);
Expand All @@ -109,7 +116,7 @@ async function submit(formData?: FormData, skip?: boolean) {
const analysisResult = await streamResult.object;

// Mark the summary stream as done with the result.
summaryStream.done(analysisResult.summary || 'Analysis complete.');
summaryStream.done(analysisResult.summary || fullSummary || 'Analysis complete.');

messages.push({ role: 'assistant', content: analysisResult.summary || 'Analysis complete.' });

Expand Down Expand Up @@ -171,17 +178,7 @@ async function submit(formData?: FormData, skip?: boolean) {
isGenerating.done(false);
uiStream.done();
}
}

// Start the background process without awaiting it.
processResolutionSearch();

// Immediately update the UI stream with the BotMessage component.
uiStream.update(
<Section title="response">
<BotMessage content={summaryStream.value} />
</Section>
);
})();

return {
id: nanoid(),
Expand Down
58 changes: 1 addition & 57 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@

.mobile-chat-input-area {
height: auto;
padding: 10px;
padding: 4px 10px;
background-color: hsl(var(--background));
/* border-top: 1px solid hsl(var(--border)); */ /* Removed for cleaner separation */
border-bottom: 1px solid hsl(var(--border)); /* Added for separation from messages area below */
Expand All @@ -198,62 +198,6 @@
display: flex;
align-items: center;
}

.mobile-chat-input {
/* position: relative; */ /* No longer fixed to bottom */
/* bottom: 0; */
/* left: 0; */ /* Handled by parent flex */
/* right: 0; */ /* Handled by parent flex */
width: 100%; /* Ensure it takes full width of its container */
padding: 10px;
background-color: hsl(var(--background));
/* border-top: 1px solid hsl(var(--border)); */ /* Removed to avoid double border */
/* z-index: 30; */ /* No longer needed */
}

.mobile-chat-input input {
width: 100%;
padding: 8px;
border: 1px solid hsl(var(--input));
border-radius: var(--radius);
background-color: hsl(var(--input));
color: hsl(var(--foreground));
box-sizing: border-box;
}

.mobile-icons-bar-content .icon-button {
display: flex;
align-items: center;
justify-content: center;
width: 40px;
height: 40px;
border-radius: 50%;
background-color: hsl(var(--secondary));
color: hsl(var(--secondary-foreground));
cursor: pointer;
}

.mobile-icons-bar-content .icon-button:hover {
background-color: hsl(var(--secondary-foreground));
color: hsl(var(--secondary));
}

.mobile-chat-input .icon-button {
position: absolute;
top: 50%;
transform: translateY(-50%);
background-color: transparent;
border: none;
cursor: pointer;
}

.mobile-chat-input .icon-button.paperclip {
right: 40px;
}

.mobile-chat-input .icon-button.arrow-right {
right: 10px;
}
}

/* Added for MapboxDraw controls */
Expand Down
52 changes: 30 additions & 22 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ import { SpeedInsights } from "@vercel/speed-insights/next"
import { Toaster } from '@/components/ui/sonner'
import { MapToggleProvider } from '@/components/map-toggle-context'
import { ProfileToggleProvider } from '@/components/profile-toggle-context'
import { UsageToggleProvider } from '@/components/usage-toggle-context'
import { CalendarToggleProvider } from '@/components/calendar-toggle-context'
import { HistoryToggleProvider } from '@/components/history-toggle-context'
import { HistorySidebar } from '@/components/history-sidebar'
import { MapLoadingProvider } from '@/components/map-loading-context';
import ConditionalLottie from '@/components/conditional-lottie';
import { MapProvider as MapContextProvider } from '@/components/map/map-context'
Expand Down Expand Up @@ -70,28 +73,33 @@ export default function RootLayout({
)}
>
<CalendarToggleProvider>
<MapToggleProvider>
<ProfileToggleProvider>
<ThemeProvider
attribute="class"
defaultTheme="earth"
enableSystem
disableTransitionOnChange
themes={['light', 'dark', 'earth']}
>
<MapContextProvider>
<MapLoadingProvider>
<Header />
<ConditionalLottie />
{children}
<Sidebar />
<Footer />
<Toaster />
</MapLoadingProvider>
</MapContextProvider>
</ThemeProvider>
</ProfileToggleProvider>
</MapToggleProvider>
<HistoryToggleProvider>
<MapToggleProvider>
<ProfileToggleProvider>
<UsageToggleProvider>
<ThemeProvider
attribute="class"
defaultTheme="earth"
enableSystem
disableTransitionOnChange
themes={['light', 'dark', 'earth']}
>
<MapContextProvider>
<MapLoadingProvider>
<Header />
<ConditionalLottie />
{children}
<Sidebar />
<HistorySidebar />
<Footer />
<Toaster />
</MapLoadingProvider>
</MapContextProvider>
</ThemeProvider>
</UsageToggleProvider>
</ProfileToggleProvider>
</MapToggleProvider>
</HistoryToggleProvider>
</CalendarToggleProvider>
<Analytics />
<SpeedInsights />
Expand Down
19 changes: 9 additions & 10 deletions components/chat-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ export const ChatPanel = forwardRef<ChatPanelRef, ChatPanelProps>(({ messages, i
}
}, 500) // 500ms debounce delay
},
[mapData]
[mapData, setSuggestions]
)

useEffect(() => {
Expand Down Expand Up @@ -199,13 +199,12 @@ export const ChatPanel = forwardRef<ChatPanelRef, ChatPanelProps>(({ messages, i
onSubmit={handleSubmit}
className={cn(
'max-w-full w-full',
isMobile ? 'px-2 pb-2 pt-1 h-full flex flex-col justify-center' : ''
isMobile ? 'px-2 pb-1 pt-0 h-full flex flex-col justify-center' : ''
)}
>
<div
className={cn(
'relative flex items-start w-full',
isMobile && 'mobile-chat-input' // Apply mobile chat input styling
'relative flex items-start w-full'
)}
>
<input type="hidden" name="mapProvider" value={mapProvider} />
Expand Down Expand Up @@ -241,10 +240,10 @@ export const ChatPanel = forwardRef<ChatPanelRef, ChatPanelProps>(({ messages, i
value={input}
data-testid="chat-input"
className={cn(
'resize-none w-full min-h-12 rounded-fill border border-input pl-14 pr-12 pt-3 pb-1 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
'resize-none w-full rounded-fill border border-input pr-12 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
isMobile
? 'mobile-chat-input input bg-background'
: 'bg-muted'
? 'bg-background min-h-10 pl-4 pt-2 pb-1'
: 'bg-muted min-h-12 pl-14 pt-3 pb-1'
)}
onChange={e => {
setInput(e.target.value)
Expand Down Expand Up @@ -293,11 +292,11 @@ export const ChatPanel = forwardRef<ChatPanelRef, ChatPanelProps>(({ messages, i
</form>
{selectedFile && (
<div className="w-full px-4 pb-2 mb-2">
<div className="flex items-center justify-between p-2 bg-muted rounded-lg">
<span className="text-sm text-muted-foreground truncate max-w-xs">
<div className="flex items-start justify-between p-2 bg-muted rounded-lg">
<span className="text-sm text-muted-foreground break-all mr-2">
{selectedFile.name}
</span>
<Button variant="ghost" size="icon" onClick={clearAttachment} data-testid="clear-attachment-button">
<Button variant="ghost" size="icon" className="shrink-0" onClick={clearAttachment} data-testid="clear-attachment-button">
<X size={16} />
</Button>
</div>
Expand Down
7 changes: 5 additions & 2 deletions components/chat.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@ import { MapProvider } from './map/map-provider'
import { useUIState, useAIState } from 'ai/rsc'
import MobileIconsBar from './mobile-icons-bar'
import { useProfileToggle, ProfileToggleEnum } from "@/components/profile-toggle-context";
import { useUsageToggle } from "@/components/usage-toggle-context";
import SettingsView from "@/components/settings/settings-view";
import { UsageView } from "@/components/usage-view";
import { MapDataProvider, useMapData } from './map/map-data-context'; // Add this and useMapData
import { updateDrawingContext } from '@/lib/actions/chat'; // Import the server action
import dynamic from 'next/dynamic'
Expand All @@ -31,6 +33,7 @@ export function Chat({ id }: ChatProps) {
const [aiState] = useAIState()
const [isMobile, setIsMobile] = useState(false)
const { activeView } = useProfileToggle();
const { isUsageOpen } = useUsageToggle();
const { isCalendarOpen } = useCalendarToggle()
const [input, setInput] = useState('')
const [showEmptyScreen, setShowEmptyScreen] = useState(false)
Expand Down Expand Up @@ -107,7 +110,7 @@ export function Chat({ id }: ChatProps) {
<HeaderSearchButton />
<div className="mobile-layout-container">
<div className="mobile-map-section">
{activeView ? <SettingsView /> : <MapProvider />}
{activeView ? <SettingsView /> : isUsageOpen ? <UsageView /> : <MapProvider />}
</div>
<div className="mobile-icons-bar">
<MobileIconsBar onAttachmentClick={handleAttachment} onSubmitClick={handleMobileSubmit} />
Expand Down Expand Up @@ -218,7 +221,7 @@ export function Chat({ id }: ChatProps) {
className="w-1/2 p-4 fixed h-[calc(100vh-0.5in)] top-0 right-0 mt-[0.5in]"
style={{ zIndex: 10 }} // Added z-index
>
{activeView ? <SettingsView /> : <MapProvider />}
{activeView ? <SettingsView /> : isUsageOpen ? <UsageView /> : <MapProvider />}
</div>
</div>
</MapDataProvider>
Expand Down
4 changes: 3 additions & 1 deletion components/conditional-lottie.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,15 @@
import LottiePlayer from '@/components/ui/lottie-player';
import { useMapLoading } from '@/components/map-loading-context';
import { useProfileToggle } from '@/components/profile-toggle-context'; // Added import
import { useUsageToggle } from '@/components/usage-toggle-context';

const ConditionalLottie = () => {
const { isMapLoaded } = useMapLoading();
const { activeView } = useProfileToggle(); // Added this line
const { isUsageOpen } = useUsageToggle();

// Updated isVisible logic
return <LottiePlayer isVisible={!isMapLoaded && activeView === null} />;
return <LottiePlayer isVisible={!isMapLoaded && activeView === null && !isUsageOpen} />;
};

export default ConditionalLottie;
6 changes: 3 additions & 3 deletions components/empty-screen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,14 +41,14 @@ export function EmptyScreen({
<Button
key={item.message} // Use a unique property as the key.
variant="link"
className="h-auto p-0 text-base flex items-center"
className="h-auto p-0 text-base flex items-start whitespace-normal text-left"
name={item.message}
onClick={async () => {
submitMessage(item.message);
}}
>
<Icon size={16} className="mr-2 text-muted-foreground" />
{item.heading}
<Icon size={16} className="mr-2 mt-1 text-muted-foreground shrink-0" />
<span className="flex-1">{item.heading}</span>
</Button>
);
})}
Expand Down
17 changes: 10 additions & 7 deletions components/header-search-button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { useActions, useUIState } from 'ai/rsc'
import { AI } from '@/app/actions'
import { nanoid } from 'nanoid'
import { UserMessage } from './user-message'
import { toast } from 'react-toastify'
import { toast } from 'sonner'
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify Toaster component is mounted in the app
rg -n "Toaster" --type=tsx --type=ts -g '!node_modules'

Repository: QueueLab/QCX

Length of output: 83


🏁 Script executed:

# Check for any remaining react-toastify imports
rg -n "react-toastify" --type=tsx --type=ts -g '!node_modules'

Repository: QueueLab/QCX

Length of output: 83


🏁 Script executed:

# Verify the migration in the file
rg -n "from 'sonner'" --type=tsx --type=ts -g '!node_modules'

Repository: QueueLab/QCX

Length of output: 83


🏁 Script executed:

#!/bin/bash
# Search for Toaster component in TypeScript/React files
rg -n "Toaster" --type-add 'web:*.{ts,tsx,js,jsx}' -t web -g '!node_modules'

Repository: QueueLab/QCX

Length of output: 970


🏁 Script executed:

# Search for react-toastify to ensure it was fully removed
rg "react-toastify" -g '!node_modules'

Repository: QueueLab/QCX

Length of output: 558


🏁 Script executed:

# Search for sonner imports
rg "from ['\"]sonner['\"]" -g '!node_modules'

Repository: QueueLab/QCX

Length of output: 382


🏁 Script executed:

# List the app entry/layout files to check for Toaster
fd -e tsx -e ts . -path '*/app*' -o -path '*/layout*' -o -path '*/main*' -o -path '*/index*' | head -20

Repository: QueueLab/QCX

Length of output: 224


Complete the sonner migration across the codebase.

The migration from react-toastify to sonner in this file is correct. The <Toaster /> component is properly mounted in app/layout.tsx. However, components/map/mapbox-map.tsx still imports and uses react-toastify. Complete the migration by updating this file and any other remaining references to use sonner instead, then remove the react-toastify dependency from package.json.

🤖 Prompt for AI Agents
In `@components/header-search-button.tsx` at line 12, Update remaining uses of
react-toastify (notably in components/map/mapbox-map.tsx) to import and call
sonner's toast API: replace any imports from 'react-toastify' and calls to
toast.success/toast.error etc. with "import { toast } from 'sonner'" and use
toast.success/toast.error (or toast) accordingly; remove any <ToastContainer />
usage since <Toaster /> is mounted in app/layout.tsx. Search the repo for other
'react-toastify' imports/usages and convert them to sonner likewise, then remove
the 'react-toastify' entry from package.json and run install to update
dependencies.

import { useSettingsStore } from '@/lib/store/settings'
import { useMapData } from './map/map-data-context'

Expand Down Expand Up @@ -37,7 +37,11 @@ export function HeaderSearchButton() {

const handleResolutionSearch = async () => {
if (mapProvider === 'mapbox' && !map) {
toast.error('Map is not available yet. Please wait for it to load.')
toast.error('Mapbox is not available yet. Please wait for it to load.')
return
}
if (mapProvider === 'google' && !mapData.cameraState) {
toast.error('Google Maps state is not available yet.')
return
}
if (!actions) {
Expand Down Expand Up @@ -73,7 +77,7 @@ export function HeaderSearchButton() {
const { center, range } = mapData.cameraState
const zoom = Math.round(Math.log2(40000000 / (range || 1)));

let staticMapUrl = `https://maps.googleapis.com/maps/api/staticmap?center=${center.lat},${center.lng}&zoom=${zoom}&size=640x480&maptype=satellite&key=${apiKey}`;
let staticMapUrl = `https://maps.googleapis.com/maps/api/staticmap?center=${center.lat},${center.lng}&zoom=${zoom}&size=640x480&scale=2&maptype=satellite&key=${apiKey}`;

const response = await fetch(staticMapUrl);
if (!response.ok) {
Expand Down Expand Up @@ -107,7 +111,7 @@ export function HeaderSearchButton() {
variant="ghost"
size="icon"
onClick={handleResolutionSearch}
disabled={isAnalyzing || !map || !actions}
disabled={isAnalyzing || !actions || (mapProvider === 'mapbox' && !map) || (mapProvider === 'google' && !mapData.cameraState)}
Copy link
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Disable logic consistency is good but verbose.

The disable condition is duplicated between desktop and mobile buttons. Consider extracting to a computed variable for maintainability.

♻️ Extract shared disable condition
+  const isDisabled = isAnalyzing || !actions || (mapProvider === 'mapbox' && !map) || (mapProvider === 'google' && !mapData.cameraState)
+
   const desktopButton = (
     <Button
       variant="ghost"
       size="icon"
       onClick={handleResolutionSearch}
-      disabled={isAnalyzing || !actions || (mapProvider === 'mapbox' && !map) || (mapProvider === 'google' && !mapData.cameraState)}
+      disabled={isDisabled}
       title="Analyze current map view"
     >

And similarly for mobileButton.

Also applies to: 126-126

🤖 Prompt for AI Agents
In `@components/header-search-button.tsx` at line 114, Extract the repeated
disable expression into a single computed boolean (e.g., const isDisabled =
isAnalyzing || !actions || (mapProvider === 'mapbox' && !map) || (mapProvider
=== 'google' && !mapData.cameraState)) and replace the duplicated uses in both
the desktop button and the mobileButton with this variable; update any JSX props
that currently use the long expression to use isDisabled to improve
maintainability and avoid divergence between HeaderSearchButton and mobileButton
render paths.

title="Analyze current map view"
>
{isAnalyzing ? (
Expand All @@ -119,9 +123,8 @@ export function HeaderSearchButton() {
)

const mobileButton = (
<Button variant="ghost" size="sm" onClick={handleResolutionSearch} disabled={isAnalyzing || !map || !actions}>
<Search className="h-4 w-4 mr-2" />
Search
<Button variant="ghost" size="icon" onClick={handleResolutionSearch} disabled={isAnalyzing || !actions || (mapProvider === 'mapbox' && !map) || (mapProvider === 'google' && !mapData.cameraState)}>
<Search className="h-[1.2rem] w-[1.2rem]" />
</Button>
)

Expand Down
Loading