VA DVS Cybersecurity Analyst
use client;
import React useEffect useMemo useState from react;
import Card CardHeader CardTitle CardContent from @/components/ui/card;
import Button from @/components/ui/button;
import Input from @/components/ui/input;
import Badge from @/components/ui/badge;
import
GripVertical
Plus
Download
Trash2
RefreshCw
Edit3
Check
X
Save
from lucide-react;
import Textarea from @/components/ui/textarea;
import saveAs from file-saver;
const APIBASE ;
// Types
export type OutlineNode
id: string;
title: string;
description: string;
children: OutlineNode;
;
type BackendSubsection
subname: string;
subdescription: string;
;
type BackendSection
sectionname: string;
sectiondescription: string;
subsections: BackendSubsection;
;
type BackendOutline
opportunityname: string;
submittedtoname: string;
submittedtoemail: string;
submittedtophone: string;
submittedbyemail: string;
submittedbyaddress: string;
coverletterdate: string;
coverletterclientcontact: string;
coverlettersubjectline: string;
coverletterbody: string;
proposaltype: string;
sections: BackendSection;
tableofcontents: string;
k: string: any;
;
export type OutlineBuilderProps
proposalId: string;
onGenerate: (outlineText: string) > void;
isLoading: boolean;
;
// Generic helpers
const cloneSafe (v: T): T >
try
return ((v)) as T;
catch
return v;
;
const findAndRemoveNode (tree: OutlineNode id: string): OutlineNode null OutlineNode >
let removed: OutlineNode null null;
const walk (list: OutlineNode): OutlineNode >
let changed false;
const out: OutlineNode ;
for (let i 0; i < ; i)
const n listi;
if ( id)
removed n;
changed true;
continue;
if (() && )
const newChildren walk();
if (newChildren ! )
changed true;
( ...n children: newChildren );
else
(n);
else
(n);
return changed out : list;
;
const newTree walk(tree);
return removed newTree;
;
const insertNodeAt (tree: OutlineNode nodeToInsert: OutlineNode parentId: string null index: number): OutlineNode >
if (parentId null)
const safeIndex (0 ( index));
return ...(0 safeIndex) nodeToInsert ...(safeIndex);
let inserted false;
const walk (list: OutlineNode): OutlineNode >
let changed false;
const out: OutlineNode ;
for (let i 0; i < ; i)
const n listi;
if ( parentId)
const children () ... : ;
const safe (0 ( index));
(safe 0 nodeToInsert);
inserted true;
changed true;
( ...n children );
continue;
if (() && )
const nchild walk();
if (nchild ! )
changed true;
( ...n children: nchild );
else
(n);
else
(n);
return changed out : list;
;
const newTree walk(tree);
return inserted newTree : tree;
;
const findNode (tree: OutlineNode id: string): OutlineNode null >
const walk (list: OutlineNode): OutlineNode null >
for (let i 0; i < ; i)
const n listi;
if ( id) return n;
if (() && )
const f walk();
if (f) return f;
return null;
;
return walk(tree);
;
const numberOutline (nodes: OutlineNode null prefix: number ): no: string; title: string >
const out: no: string; title: string ;
const arr (nodes) nodes : ;
((n idx) >
const no ...prefix idx (.);
( no title: );
if ()
const sub numberOutline( ...prefix idx 1);
(...sub);
);
return out;
;
const outlineToText (nodes: OutlineNode null): string >
numberOutline(nodes).map((x) > $ $).join(n);
const OutlineBuilder: ( proposalId onGenerate isLoading ) >
const nodes setNodes useState();
const outlineJson setOutlineJson useState(null);
const loadingOutline setLoadingOutline useState(true);
const saving setSaving useState(false);
const deleting setDeleting useState(false);
const draggedId setDraggedId useState(null);
const dropHint setDropHint useState(null);
const selectedTemplate setSelectedTemplate useState();
const meta setMeta useState(
opportunityname:
submittedtoname:
submittedtoemail:
submittedtophone:
coverletterdate:
coverletterclientcontact:
coverlettersubjectline:
coverletterbody:
);
const mapBackendToNodes (outline: BackendOutline null): OutlineNode >
if (!outline) return ;
const sections () : ;
return ((s idx) > (
id: ()
title: Section $idx 1
description:
children: ()
((sub j) > (
id: ()
title: Subsection $j 1
description:
children:
))
:
));
;
const mapNodesToBackendSections (list: OutlineNode): BackendSection >
return ((list) list : ).map((n) > (
sectionname:
sectiondescription:
subsections: ()
((c) > (
subname:
subdescription:
))
:
));
;
const fetchOutline async () >
if (!proposalId !APIBASE) return;
try
setLoadingOutline(true);
const res await fetch($APIBASE/api/proposals/$proposalId/outline method: GET );
if (!)
const txt await ().catch(() > );
throw new Error(GET failed: $ $txt);
const data await ();
const outline: BackendOutline data;
setOutlineJson(outline);
setMeta(
opportunityname:
submittedtoname:
submittedtoemail:
submittedtophone:
coverletterdate:
coverletterclientcontact:
coverlettersubjectline:
coverletterbody:
);
const mapped mapBackendToNodes(outline);
setNodes(mapped);
catch (err)
(fetchOutline error: err);
alert(Failed to load outline.);
finally
setLoadingOutline(false);
;
useEffect(() >
fetchOutline();
// eslint-disable-next-line react-hooks/exhaustive-deps
proposalId);
const outlineText useMemo(() > outlineToText(nodes) nodes);
const removeNodeById (id: string) >
const newTree findAndRemoveNode(nodes as any id);
setNodes(newTree as any);
;
const updateTitle (id: string text: string) >
const node findNode(nodes as any id);
if (node)
text;
setNodes(...nodes);
;
const updateDescription (id: string desc: string) >
const node findNode(nodes id);
if (node)
const updatedNode ...node description: desc ;
const newNodes ((n) > ( id updatedNode : n));
setNodes(newNodes);
;
const addChild (parentId: string) >
const newChild: OutlineNode
id: ()
title: New Subsection
description:
children:
;
const parentNode findNode(nodes as any parentId);
const newIndex 0;
const newTree insertNodeAt(nodes as any newChild as any parentId newIndex);
if (newTree ! nodes) setNodes(newTree as any);
;
const addRoot () >
setNodes(...nodes id: () title: New Section description: );
;
const onDragStart (e: id: string) >
setDraggedId(id);
(text/plain id);
;
const onDragOverGeneric (e: ) >
();
;
const endDragCleanup () >
setDraggedId(null);
setDropHint(null);
;
useEffect(() >
const cleanup () > endDragCleanup();
(dragend cleanup);
return () > (dragend cleanup);
);
const findParentAndIndex (tree: OutlineNode id: string): parentId: string null; index: number null >
const walk (arr: OutlineNode parentId: string null): parentId: string null; index: number null >
for (let i 0; i < ; i)
const n arri;
if ( id) return parentId index: i ;
if ()
const found walk( );
if (found) return found;
return null;
;
return walk(tree null);
;
const handleDragLeaveRoot (e: ) >
const to as HTMLElement null;
if (!to !(.outline-left-column))
setDropHint(null);
;
const onDropBetween (e: parentId: string null index: number) >
();
let dragged (text/plain);
if (!dragged && draggedId) dragged draggedId;
if (!dragged) return endDragCleanup();
const origin findParentAndIndex(nodes dragged);
const originParent null;
const originIndex -1;
let targetIndex index;
if (originParent parentId && originIndex < index) targetIndex index - 1;
if (originParent parentId && targetIndex originIndex) return endDragCleanup();
const removed afterRemove findAndRemoveNode(nodes as any dragged);
if (!removed) return endDragCleanup();
const newTree insertNodeAt(afterRemove as any removed as any parentId targetIndex);
if (newTree ! nodes) setNodes(newTree as any);
endDragCleanup();
;
const onDropInto (e: parentId: string null) >
();
let dragged (text/plain);
if (!dragged && draggedId) dragged draggedId;
if (!dragged) return endDragCleanup();
if (parentId && isDescendant(nodes dragged parentId)) return endDragCleanup();
const origin findParentAndIndex(nodes dragged);
const originParent null;
const originIndex -1;
const removed afterRemove findAndRemoveNode(nodes as any dragged);
if (!removed) return endDragCleanup();
const parentNode parentId findNode(afterRemove as any parentId) : null;
let newIndex ;
if (originParent parentId && originIndex < newIndex) newIndex (0 newIndex - 1);
const newTree insertNodeAt(afterRemove as any removed as any parentId newIndex);
if (newTree ! nodes) setNodes(newTree as any);
endDragCleanup();
;
const TitleInline: ( id value ) >
const editing setEditing useState(false);
const val setVal useState(value);
useEffect(() > setVal(value) value);
return (
editing (
setVal() />
updateTitle(id val value);
setEditing(false);
>
setVal(value);
setEditing(false);
>
) : (
value
setEditing(true)>
)
;
return (
Proposal Outline
Type: $ :
Reload
saving (
Saving
) : (
Save Outline
)
onGenerate(outlineText) disabled!>
Generate Draft
downloadDocx(selectedTemplate) disabled!>
Download DOCX
Delete Outline
> 0 (
) : (
No sections found. Add or reload.
)
Add Top-Level Section
Cover & Metadata
Opportunity Name
setMeta( ...meta opportunityname: )
/>
Submitted To (Name)
setMeta( ...meta submittedtoname: )
/>
Email
setMeta( ...meta submittedtoemail: )
/>
Phone
setMeta( ...meta submittedtophone: )
/>
Cover Letter Date
setMeta( ...meta coverletterdate: )
/>
Client Contact
setMeta(
...meta
coverletterclientcontact:
)
/>
Subject Line
setMeta(
...meta
coverlettersubjectline:
)
/>
Cover Letter Body
setMeta(
...meta
coverletterbody:
)
/>
Template
Choose Template
setSelectedTemplate()
>
Tip: Edit outline on left. Edit cover details here. Save to Firestore or Export DOCX anytime.
);
;
export default OutlineBuilder;
Location:Richmond Virginia United States
Responsibilities:
- Support the development and scoping of the risk assessment plan.
- Identify assess and document applicable security controls.
- Collaborate with stakeholders to collect data and evidence.
- Perform detailed analysis of access control measures.
- Review security documentation and system procedures.
- Prepare draft and final risk assessment reports.
- Collect and review artifacts demonstrating compliance with applicable security controls.
- Incorporate feedback and deliver a final report.
Required Skills & Certifications:
- Bachelors degree in Cybersecurity Information Technology Computer Science or related field.
- Minimum 5 years of experience in cybersecurity risk assessment or compliance projects.
- Strong understanding of NIST 800-53 and SEC530 Information Security Standards.
- Hands-on experience with access control evaluations and documentation of compliance evidence.
- Excellent analytical reporting and communication skills.
Preferred Skills & Certifications:
- Certifications such as CISSP CISA CISM CRISC or Security.
- Experience working with state or federal agencies or similar regulatory environments.
Special Considerations:
- N/A
Scheduling:
- N/A
Recommended Jobs
Senior HVAC Technician
Join Our Team as a Senior HVAC Technician At Wisler Plumbing, Heating, Cooling and Electric, we don’t just hire techs—we build careers rooted in respect, growth, and purpose. If you’re a seasoned …
Client Service Representative (Moneta Branch)
The position is an all-encompassing role which requires the teammate to deliver best in class client experience sales/service solutions as well as handle teller transactions. The Client Services Repr…
Senior Associate, CRE Loan Screening
Senior Associate, CRE Loan Screening The Senior Associate, CRE Loan Screening role will sit on a team of screeners and analysts to pre-qualify and structure Commercial Real Estate (CRE) Balance Sheet …
Server Assistant
We Wine. We Dine. We Build Careers! For this position, pay will be variable by location - plus tips. We cordially invite you to apply. Joining our team provides exceptionally distinct…
Construction Inspector
Responsibilities: Mead & Hunt is an employee-owned, flexible company that believes in giving back to our communities, investing in our employees, and building relationships that last. We value taking…
Technical Service Representative - VA Area
About AkzoNobel Since 1792, we’ve been supplying the innovative paints and coatings that help to color people’s lives and protect what matters most. Our world class portfolio of brands – including…
Electrical Design Engineer
Electrical Design Engineer - Ashburn, VA Our client is a global provider and manufacturer of industrial power equipment used in emergency back up power applications for mission critical operations…
Lead Mechanic
VACANCY ANNOUNCEMENT Lead Mechanic Starting Salary Range: $50,896 - $55,985 Job Summary: Join our team as a skilled Wastewater Treatment Plant Lead Mechanic. This position involves main…
US Tech - Technical Business Analyst Manager Save for Later Remove job
At PwC, our people in software and product innovation focus on developing cutting-edge software solutions and driving product innovation to meet the evolving needs of clients. These individuals com…