- Migrated Chat.tsx with message handling and UI structure - Migrated ChatInput.tsx with character limits and keyboard shortcuts - Migrated MessageList.tsx with thinking/reasoning display - Migrated ConversationSidebar.tsx (simplified placeholder) - Migrated BackendStatusBanner.tsx (simplified placeholder) - Created components/chat/index.ts barrel export - Created app/chat/page.tsx placeholder route These components are adapted from jarvis-fe but not yet fully functional: - API calls placeholder (need to wire up /api/brain/query) - Auth hooks stubbed (need useAuth implementation) - Project/conversation hooks stubbed (need implementation) - Imports changed from @jarvis/* to @mosaic/* Next steps: - Implement missing hooks (useAuth, useProjects, useConversations, useApi) - Wire up backend API endpoints - Add proper TypeScript types - Implement full conversation management
99 lines
2.9 KiB
TypeScript
99 lines
2.9 KiB
TypeScript
"use client";
|
|
|
|
import { useState, useEffect } from "react";
|
|
|
|
/**
|
|
* Banner that displays when the backend is unavailable.
|
|
* Shows error message, countdown to next retry, and manual retry button.
|
|
*
|
|
* TODO: Integrate with actual backend status checking hook
|
|
*/
|
|
export function BackendStatusBanner() {
|
|
const [isAvailable, setIsAvailable] = useState(true);
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [retryIn, setRetryIn] = useState(0);
|
|
|
|
// TODO: Replace with actual useBackendStatus hook
|
|
// const { isAvailable, error, retryIn, manualRetry } = useBackendStatus();
|
|
|
|
const manualRetry = () => {
|
|
// TODO: Implement manual retry logic
|
|
console.log("Manual retry triggered");
|
|
};
|
|
|
|
const handleSignOut = async () => {
|
|
try {
|
|
// TODO: Implement signOut
|
|
// await signOut();
|
|
} catch (error) {
|
|
console.warn("Sign-out failed during backend unavailability:", error);
|
|
}
|
|
window.location.href = "/login";
|
|
};
|
|
|
|
// Don't render if backend is available
|
|
if (isAvailable) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<div
|
|
className="flex items-center justify-between gap-4 px-4 py-2 text-sm"
|
|
style={{
|
|
backgroundColor: "#fef3c7", // amber-100
|
|
borderBottom: "1px solid #fcd34d", // amber-300
|
|
color: "#92400e", // amber-800
|
|
}}
|
|
role="alert"
|
|
aria-live="polite"
|
|
>
|
|
<div className="flex items-center gap-2">
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
className="h-5 w-5 flex-shrink-0"
|
|
viewBox="0 0 20 20"
|
|
fill="currentColor"
|
|
aria-hidden="true"
|
|
>
|
|
<path
|
|
fillRule="evenodd"
|
|
d="M8.257 3.099c.765-1.36 2.722-1.36 3.486 0l5.58 9.92c.75 1.334-.213 2.98-1.742 2.98H4.42c-1.53 0-2.493-1.646-1.743-2.98l5.58-9.92zM11 13a1 1 0 11-2 0 1 1 0 012 0zm-1-8a1 1 0 00-1 1v3a1 1 0 002 0V6a1 1 0 00-1-1z"
|
|
clipRule="evenodd"
|
|
/>
|
|
</svg>
|
|
<span>
|
|
{error || "Backend temporarily unavailable."}
|
|
{retryIn > 0 && (
|
|
<span className="ml-1">
|
|
Retrying in {retryIn}s...
|
|
</span>
|
|
)}
|
|
</span>
|
|
</div>
|
|
<div className="flex items-center gap-2">
|
|
<button
|
|
onClick={manualRetry}
|
|
className="rounded px-3 py-1 text-xs font-medium transition-colors hover:opacity-80"
|
|
style={{
|
|
backgroundColor: "#fcd34d", // amber-300
|
|
color: "#92400e", // amber-800
|
|
}}
|
|
>
|
|
Retry Now
|
|
</button>
|
|
<button
|
|
onClick={handleSignOut}
|
|
className="rounded px-3 py-1 text-xs font-medium transition-colors hover:opacity-80"
|
|
style={{
|
|
backgroundColor: "transparent",
|
|
color: "#92400e", // amber-800
|
|
border: "1px solid #fcd34d", // amber-300
|
|
}}
|
|
>
|
|
Sign in again
|
|
</button>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|