Job Summary :
The Registered Nurse will be responsible for providing skilled nursing care, case management, and hospice care to individuals facing advancing age, frailty, and serious illness. Daily tasks include patient assessments, medication administration, treatment planning, and collaborating with the interdisciplinary team. Critical to this role is strong communication and collaboration with patients, providers, and other members of our team. At least 2 years of experience and exceptional skill is required.
Location : Portland, Oregon, United States
Responsibilities :
Required Skills & Certifications :
Preferred Skills & Certifications :
Special Considerations :
Scheduling : 'use client';
import { useState, useEffect } from 'react';
import { useRouter, useSearchParams } from 'next / navigation';
import { MessageSquare, ChevronLeft } from 'lucide-react';
import type {
AnalyzeRFPContentOutput,
GenerateClientProfileOutput,
DraftProposalSectionsOutput,
GenerateComplianceMatrixOutput,
ChatMessage,
KnowledgeItem,
ProposalType,
AttachedDocument,
} from '@ / lib / types';
import { Button } from '@ / components / ui / button';
import { RfpInputForm } from '@ / components / rfp-input-form';
import { ResultsDisplay } from '@ / components / results-display';
import { ChatPanel } from '@ / components / chat-panel';
import Logo from '@ / components / logo';
import { useToast } from '@ / hooks / use-toast';
import { MOCK_KB_CONTENT } from '@ / lib / mock-data';
import { AttachedDocuments } from '@ / components / attached-documents';
/ / Types
type LoadingStates = {
analysis : boolean;
capture : boolean;
outline : boolean;
draft : boolean;
compliance : boolean;
};
/ / Retry helper
async function retry(fn : () =>
Promise, retries = 3, delay = 1000) : Promise {
let lastError : Error | undefined;
for (let i = 0; i
try {
return await fn();
} catch (error : unknown) {
lastError = error as Error;
if (lastError?.message?.includes('503')) {
console.warn(`Attempt ${i + 1} failed with 503. Retrying in ${delay}ms...`);
await new Promise(res =>
setTimeout(res, delay));
} else {
throw lastError;
throw lastError;
/ / Component
interface Props {
proposalId : string;
export default function ProposalPageClient({ proposalId } : Readonly) {
const router = useRouter();
const searchParams = useSearchParams();
const name = searchParams.get('name') ?? 'Unnamed Proposal';
const isNew = searchParams.get('new') === 'true';
const mode = searchParams.get('mode') ?? 'edit'; / / default edit
const isViewOnly = mode === 'view';
/ / State
const [proposalName, setProposalName] = useState('');
const [rfpContent, setRfpContent] = useState('');
const [isRfpSubmitted, setIsRfpSubmitted] = useState(false);
const [loading, setLoading] = useState({
analysis : false,
capture : false,
outline : false,
draft : false,
compliance : false,
});
const [knowledgeBase] = useState(MOCK_KB_CONTENT);
const [relevantKb, setRelevantKb] = useState('');
const [analysisResult, setAnalysisResult] = useState(null);
const [captureResult, setCaptureResult] = useState(null);
const [proposalDraft, setProposalDraft] = useState(null);
const [complianceMatrix, setComplianceMatrix] = useState(null);
const [chatMessages, setChatMessages] = useState([]);
const [isChatOpen, setIsChatOpen] = useState(false);
const [isDocsModalOpen, setIsDocsModalOpen] = useState(false);
const [attachedDocs, setAttachedDocs] = useState([]);
const { toast } = useToast();
/ / Load proposal
useEffect(() =>
const fetchProposal = async () =>
if (isNew) {
setProposalName('New Proposal');
setIsRfpSubmitted(false);
setAttachedDocs([]);
setRfpContent('');
} else {
try {
const apiUrl = process.env.NEXT_PUBLIC_API_URL;
if (!apiUrl) throw new Error('API URL not defined');
const res = await fetch(`${apiUrl} / api / proposals / ${proposalId}`);
if (!res.ok) throw new Error('Failed to fetch proposal');
const data = await res.json();
setProposalName(data.name ?? `Proposal ${name}`);
setRfpContent(data.content ?? '');
setIsRfpSubmitted(true);
/ / Map backend files to state
if (Array.isArray(data.files) && data.files.length >
0) {
const files : AttachedDocument[] = data.files.map((f : any) =>
({
id : f.id ?? f.name,
name : f.name,
type : f.type,
textContent : f.textContent ?? '',
size : f.size ?? undefined,
}));
setAttachedDocs(files);
} else {
setAttachedDocs([]);
/ / Knowledge base setup
const filteredKb = knowledgeBase.filter(
item =>
item.category === 'General' || item.category === data.type
);
const kbContent = filteredKb.map(item =>
item.content).join('
');
setRelevantKb(kbContent);
} catch (err : any) {
toast({
variant : 'destructive',
title : 'Error fetching proposal',
description : err.message ?? 'Something went wrong',
});
};
fetchProposal();
}, [proposalId, isNew, name, knowledgeBase, toast]);
/ / Listen for analysisUpdated
useEffect(() =>
const handleAnalysisUpdate = (event : Event) =>
const customEvent = event as CustomEvent;
if (customEvent.detail) {
setAnalysisResult(customEvent.detail); / / update analysis directly
};
document.addEventListener("analysisUpdated", handleAnalysisUpdate);
return () =>
document.removeEventListener("analysisUpdated", handleAnalysisUpdate);
};
}, []);
/ / Submit RFP
const handleRfpSubmit = (
content : string,
name : string,
type : ProposalType,
initialDocs? : AttachedDocument[]
) =>
setRfpContent(content);
setProposalName(name);
if (initialDocs) setAttachedDocs(initialDocs);
const filteredKb = knowledgeBase.filter(item =>
item.category === 'General' || item.category === type);
const kbContent = filteredKb.map(item =>
item.content).join('
');
setRelevantKb(kbContent);
setIsRfpSubmitted(true);
triggerAnalysisAndCapture(content, kbContent);
};
/ / Run analysis
const triggerAnalysisAndCapture = async (content : string, kbContent : string) =>
setLoading({ analysis : true, capture : true, compliance : true, outline : true, draft : false });
setAnalysisResult(null);
setCaptureResult(null);
setComplianceMatrix(null);
setProposalDraft(null);
setChatMessages([]);
try {
const [analysis, capture, compliance] = await Promise.all([
retry(() =>
analyzeRFPContent({ rfpContent : content, knowledgeBaseContent : kbContent })),
retry(() =>
generateClientProfile({ rfpContent : content, knowledgeBaseContent : kbContent })),
retry(() =>
generateComplianceMatrix({ rfpContent : content, knowledgeBaseContent : kbContent })),
]);
setAnalysisResult(analysis);
setCaptureResult(capture);
setComplianceMatrix(compliance);
} catch (error) {
console.error('Error during initial analysis : ', error);
toast({
variant : 'destructive',
title : 'Analysis Failed',
description : 'There was an error processing the RFP content. Please try again.',
});
} finally {
setLoading(prev =>
({ ...prev, analysis : false, capture : false, compliance : false, outline : false }));
};
/ / Generate draft
const handleGenerateDraft = async (proposalOutline : string) =>
setLoading(prev =>
({ ...prev, draft : true }));
setProposalDraft(null);
try {
const draft = await retry(() =>
draftProposalSections({
rfpContent,
proposalOutline,
knowledgeBaseContent : relevantKb,
})
);
setProposalDraft(draft);
} catch (error) {
console.error('Error generating proposal draft : ', error);
toast({
variant : 'destructive',
title : 'Draft Generation Failed',
description : 'Could not generate the proposal draft. Please try again.',
});
} finally {
setLoading(prev =>
({ ...prev, draft : false }));
};
/ / Render
return (
{ /
router.push(' / ')} className="h-8 w-8">
{proposalName}
{isRfpSubmitted && (
setIsDocsModalOpen(true)}>
Attached Documents
setIsChatOpen(true)}>
Chat with RFP
)}
{ /
{!isRfpSubmitted ? (
) : (
{ /
{isDocsModalOpen && (
setIsDocsModalOpen(false)}
className="absolute top-3 right-3 text-gray-500 hover : text-gray-700"
)}
)}
{ /
);
Xray Technician • Portland, OR, United States