Skip to content

Commit 17c297c

Browse files
committed
fix: only switches between 2 cameras
1 parent 72e8608 commit 17c297c

File tree

1 file changed

+74
-5
lines changed

1 file changed

+74
-5
lines changed

src/app/search/page.tsx

Lines changed: 74 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,13 +71,78 @@ export default function ProductSearch() {
7171
const [pageLoading, setPageLoading] = useState(true);
7272
const [currentCameraIndex, setCurrentCameraIndex] = useState(0);
7373
const [availableCameras, setAvailableCameras] = useState<MediaDeviceInfo[]>([]);
74+
const [filteredCameras, setFilteredCameras] = useState<MediaDeviceInfo[]>([]);
7475
const videoRef = useRef<HTMLVideoElement>(null);
7576
const cameraControlsRef = useRef<{ stop: () => void } | null>(null);
7677
const router = useRouter();
7778
const { setNavigating } = useTopBar();
7879

7980
const debouncedQuery = useDebounce(query, 500); // Increased debounce delay
8081

82+
// Filter cameras to only include back, front, and ultrawide
83+
const filterCameras = async (devices: MediaDeviceInfo[]): Promise<MediaDeviceInfo[]> => {
84+
const filtered: MediaDeviceInfo[] = [];
85+
86+
for (const device of devices) {
87+
try {
88+
// Get camera capabilities to determine facing mode
89+
const stream = await navigator.mediaDevices.getUserMedia({
90+
video: { deviceId: device.deviceId }
91+
});
92+
93+
const track = stream.getVideoTracks()[0];
94+
const capabilities = track.getCapabilities();
95+
const settings = track.getSettings();
96+
97+
// Stop the stream immediately
98+
stream.getTracks().forEach(track => track.stop());
99+
100+
// Check for facing mode or camera type in label
101+
const label = device.label.toLowerCase();
102+
const facingMode = settings.facingMode || capabilities.facingMode;
103+
104+
// Include back camera (main camera)
105+
if (facingMode === 'environment' ||
106+
label.includes('back') ||
107+
label.includes('rear') ||
108+
(!label.includes('front') && !label.includes('selfie') && devices.indexOf(device) === 0)) {
109+
filtered.push(device);
110+
}
111+
// Include front camera
112+
else if (facingMode === 'user' ||
113+
label.includes('front') ||
114+
label.includes('selfie')) {
115+
filtered.push(device);
116+
}
117+
// Include ultrawide camera
118+
else if (label.includes('ultra') ||
119+
label.includes('wide') ||
120+
label.includes('0.5')) {
121+
filtered.push(device);
122+
}
123+
} catch (error) {
124+
// If we can't get capabilities, use label-based filtering
125+
const label = device.label.toLowerCase();
126+
if (label.includes('back') ||
127+
label.includes('rear') ||
128+
label.includes('front') ||
129+
label.includes('selfie') ||
130+
label.includes('ultra') ||
131+
label.includes('wide') ||
132+
(!label.includes('front') && devices.indexOf(device) === 0)) {
133+
filtered.push(device);
134+
}
135+
}
136+
}
137+
138+
// If no cameras matched our criteria, fall back to first available camera
139+
if (filtered.length === 0 && devices.length > 0) {
140+
filtered.push(devices[0]);
141+
}
142+
143+
return filtered;
144+
};
145+
81146
// Auth state listener
82147
useEffect(() => {
83148
const unsub = onAuthStateChanged(auth, (user) => {
@@ -133,8 +198,12 @@ export default function ProductSearch() {
133198
const devices = await BrowserMultiFormatReader.listVideoInputDevices();
134199
setAvailableCameras(devices);
135200

136-
if (devices.length > 0 && videoRef.current && active) {
137-
const selectedDevice = devices[currentCameraIndex] || devices[0];
201+
// Filter cameras to only include desired types
202+
const filtered = await filterCameras(devices);
203+
setFilteredCameras(filtered);
204+
205+
if (filtered.length > 0 && videoRef.current && active) {
206+
const selectedDevice = filtered[currentCameraIndex] || filtered[0];
138207
const codeReader = new BrowserMultiFormatReader();
139208
const controls = await codeReader.decodeFromVideoDevice(
140209
selectedDevice.deviceId,
@@ -179,15 +248,15 @@ export default function ProductSearch() {
179248
}, []);
180249

181250
const flipCamera = () => {
182-
if (availableCameras.length > 1) {
251+
if (filteredCameras.length > 1) {
183252
// Stop current camera before switching
184253
if (cameraControlsRef.current) {
185254
cameraControlsRef.current.stop();
186255
cameraControlsRef.current = null;
187256
}
188257

189258
setCurrentCameraIndex((prevIndex) =>
190-
(prevIndex + 1) % availableCameras.length
259+
(prevIndex + 1) % filteredCameras.length
191260
);
192261
}
193262
};
@@ -325,7 +394,7 @@ export default function ProductSearch() {
325394
<video ref={videoRef} className="w-full h-auto" />
326395
</div>
327396
{/* Flip Camera Button */}
328-
{availableCameras.length > 1 && (
397+
{filteredCameras.length > 1 && (
329398
<button
330399
onClick={flipCamera}
331400
className="absolute top-2 right-2 p-2 rounded-full shadow-lg transition-all duration-200 hover:scale-110 active:scale-95"

0 commit comments

Comments
 (0)