feat(4.1-05-07): create frontend components for spare-parts search integration - useItemSearch hook, LoadingModal, ErrorModal with tests

This commit is contained in:
2026-04-22 16:46:50 +03:00
parent 54813067e2
commit 2647f0428c
6 changed files with 374 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
'use client';
interface SearchErrorModalProps {
isOpen: boolean;
error: string | null;
onRetry?: () => void;
onSkip?: () => void;
canRetry?: boolean;
}
export function SearchErrorModal({ isOpen, error, onRetry, onSkip, canRetry = true }: SearchErrorModalProps) {
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
<div className="bg-white rounded-lg p-6 max-w-md shadow-xl">
<h2 className="text-xl font-normal mb-2 text-rose-500">Search failed</h2>
<p className="text-sm text-slate-600 mb-4">{error || 'Unable to retrieve specs from the web'}</p>
<div className="flex gap-3">
{canRetry && (
<button
onClick={onRetry}
className="flex-1 px-4 py-2 bg-primary text-white rounded font-normal text-sm hover:bg-primary/90"
>
Retry
</button>
)}
<button
onClick={onSkip}
className="flex-1 px-4 py-2 border border-slate-300 rounded font-normal text-sm hover:bg-slate-50"
>
Skip
</button>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,57 @@
'use client';
import { useEffect, useState } from 'react';
interface SearchLoadingModalProps {
isOpen: boolean;
onTimeout?: () => void;
maxSeconds?: number;
}
export function SearchLoadingModal({ isOpen, onTimeout, maxSeconds = 30 }: SearchLoadingModalProps) {
const [seconds, setSeconds] = useState(maxSeconds);
useEffect(() => {
if (!isOpen) {
setSeconds(maxSeconds);
return;
}
const interval = setInterval(() => {
setSeconds(prev => {
if (prev <= 1) {
clearInterval(interval);
onTimeout?.();
return maxSeconds;
}
return prev - 1;
});
}, 1000);
return () => clearInterval(interval);
}, [isOpen, maxSeconds, onTimeout]);
if (!isOpen) return null;
return (
<div className="fixed inset-0 bg-black/50 flex items-center justify-center z-50">
<div className="bg-white rounded-lg p-6 max-w-md shadow-xl">
<h2 className="text-xl font-normal mb-4">Searching for specs...</h2>
<p className="text-sm text-slate-600 mb-4">This may take up to {maxSeconds} seconds</p>
<div className="mb-4">
<div className="relative h-2 bg-slate-200 rounded-full overflow-hidden">
<div
className="h-full bg-primary transition-all duration-1000"
style={{ width: `${(seconds / maxSeconds) * 100}%` }}
/>
</div>
</div>
<p className="text-center text-sm font-normal">
<span className="text-primary text-lg">{seconds}</span> seconds remaining
</p>
</div>
</div>
);
}