Create Staff Announcements page for company news and updates
cgen-5abf94bef5284d2f81eeac753e9abf26
This commit is contained in:
parent
8bb8e516be
commit
cbbb30d39d
1 changed files with 281 additions and 0 deletions
281
client/pages/staff/StaffAnnouncements.tsx
Normal file
281
client/pages/staff/StaffAnnouncements.tsx
Normal file
|
|
@ -0,0 +1,281 @@
|
|||
import { useState } from "react";
|
||||
import Layout from "@/components/Layout";
|
||||
import SEO from "@/components/SEO";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import {
|
||||
Card,
|
||||
CardContent,
|
||||
CardDescription,
|
||||
CardHeader,
|
||||
CardTitle,
|
||||
} from "@/components/ui/card";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Bell, Star, Archive, Pin } from "lucide-react";
|
||||
|
||||
interface Announcement {
|
||||
id: string;
|
||||
title: string;
|
||||
content: string;
|
||||
category: string;
|
||||
author: string;
|
||||
date: string;
|
||||
isPinned: boolean;
|
||||
isArchived: boolean;
|
||||
priority: "High" | "Normal" | "Low";
|
||||
}
|
||||
|
||||
const announcements: Announcement[] = [
|
||||
{
|
||||
id: "1",
|
||||
title: "Q1 2025 All-Hands Meeting Rescheduled",
|
||||
content:
|
||||
"The all-hands meeting has been moved to Friday at 2 PM PST. Please mark your calendars and join us for company updates.",
|
||||
category: "Company News",
|
||||
author: "Sarah Chen",
|
||||
date: "Today",
|
||||
isPinned: true,
|
||||
isArchived: false,
|
||||
priority: "High",
|
||||
},
|
||||
{
|
||||
id: "2",
|
||||
title: "New Benefits Portal is Live",
|
||||
content:
|
||||
"Welcome to our upgraded benefits portal! You can now view and manage your health insurance, retirement plans, and more.",
|
||||
category: "Benefits",
|
||||
author: "HR Team",
|
||||
date: "2 days ago",
|
||||
isPinned: true,
|
||||
isArchived: false,
|
||||
priority: "High",
|
||||
},
|
||||
{
|
||||
id: "3",
|
||||
title: "Summer Internship Program Open for Applications",
|
||||
content:
|
||||
"We're hiring summer interns across all departments. If you know someone talented, send them our way!",
|
||||
category: "Hiring",
|
||||
author: "Talent Team",
|
||||
date: "3 days ago",
|
||||
isPinned: false,
|
||||
isArchived: false,
|
||||
priority: "Normal",
|
||||
},
|
||||
{
|
||||
id: "4",
|
||||
title: "Server Maintenance Window This Weekend",
|
||||
content:
|
||||
"We'll be performing scheduled maintenance on Saturday evening. Services may be temporarily unavailable.",
|
||||
category: "Technical",
|
||||
author: "DevOps Team",
|
||||
date: "4 days ago",
|
||||
isPinned: false,
|
||||
isArchived: false,
|
||||
priority: "Normal",
|
||||
},
|
||||
{
|
||||
id: "5",
|
||||
title: "Welcome New Team Members!",
|
||||
content:
|
||||
"Please join us in welcoming 5 amazing new colleagues who started this week. Check out their profiles in the directory.",
|
||||
category: "Team",
|
||||
author: "HR Team",
|
||||
date: "1 week ago",
|
||||
isPinned: false,
|
||||
isArchived: false,
|
||||
priority: "Low",
|
||||
},
|
||||
];
|
||||
|
||||
const getPriorityColor = (priority: string) => {
|
||||
switch (priority) {
|
||||
case "High":
|
||||
return "bg-red-500/20 text-red-300 border-red-500/30";
|
||||
case "Normal":
|
||||
return "bg-blue-500/20 text-blue-300 border-blue-500/30";
|
||||
case "Low":
|
||||
return "bg-slate-500/20 text-slate-300 border-slate-500/30";
|
||||
default:
|
||||
return "bg-slate-500/20 text-slate-300";
|
||||
}
|
||||
};
|
||||
|
||||
const categories = [
|
||||
"All",
|
||||
"Company News",
|
||||
"Benefits",
|
||||
"Hiring",
|
||||
"Technical",
|
||||
"Team",
|
||||
];
|
||||
|
||||
export default function StaffAnnouncements() {
|
||||
const [selectedCategory, setSelectedCategory] = useState("All");
|
||||
const [showArchived, setShowArchived] = useState(false);
|
||||
|
||||
const filtered = announcements.filter((ann) => {
|
||||
const matchesCategory =
|
||||
selectedCategory === "All" || ann.category === selectedCategory;
|
||||
const matchesArchived = showArchived ? ann.isArchived : !ann.isArchived;
|
||||
return matchesCategory && matchesArchived;
|
||||
});
|
||||
|
||||
const pinnedAnnouncements = filtered.filter((a) => a.isPinned);
|
||||
const unpinnedAnnouncements = filtered.filter((a) => !a.isPinned);
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<SEO title="Announcements" description="Company news and updates" />
|
||||
|
||||
<div className="min-h-screen bg-gradient-to-br from-slate-900 via-slate-800 to-slate-900">
|
||||
{/* Background effects */}
|
||||
<div className="absolute inset-0 opacity-30">
|
||||
<div className="absolute top-20 left-10 w-96 h-96 bg-rose-600 rounded-full mix-blend-multiply filter blur-3xl animate-pulse" />
|
||||
<div className="absolute bottom-20 right-10 w-96 h-96 bg-pink-600 rounded-full mix-blend-multiply filter blur-3xl animate-pulse" />
|
||||
</div>
|
||||
|
||||
<div className="relative z-10">
|
||||
{/* Header */}
|
||||
<div className="container mx-auto max-w-4xl px-4 py-16">
|
||||
<div className="flex items-center gap-3 mb-6">
|
||||
<div className="p-3 rounded-lg bg-rose-500/20 border border-rose-500/30">
|
||||
<Bell className="h-6 w-6 text-rose-400" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="text-4xl font-bold text-rose-100">
|
||||
Announcements
|
||||
</h1>
|
||||
<p className="text-rose-200/70">
|
||||
Company news, updates, and important information
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Category Filter */}
|
||||
<div className="mb-8 space-y-4">
|
||||
<div className="flex gap-2 flex-wrap">
|
||||
{categories.map((category) => (
|
||||
<Button
|
||||
key={category}
|
||||
variant={selectedCategory === category ? "default" : "outline"}
|
||||
size="sm"
|
||||
onClick={() => setSelectedCategory(category)}
|
||||
className={
|
||||
selectedCategory === category
|
||||
? "bg-rose-600 hover:bg-rose-700"
|
||||
: "border-rose-500/30 text-rose-300 hover:bg-rose-500/10"
|
||||
}
|
||||
>
|
||||
{category}
|
||||
</Button>
|
||||
))}
|
||||
</div>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
onClick={() => setShowArchived(!showArchived)}
|
||||
className="border-rose-500/30 text-rose-300 hover:bg-rose-500/10"
|
||||
>
|
||||
<Archive className="h-4 w-4 mr-2" />
|
||||
{showArchived ? "Show Active" : "Show Archived"}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Pinned Announcements */}
|
||||
{pinnedAnnouncements.length > 0 && (
|
||||
<div className="mb-12">
|
||||
<h2 className="text-lg font-semibold text-rose-100 mb-4 flex items-center gap-2">
|
||||
<Pin className="h-5 w-5" />
|
||||
Pinned
|
||||
</h2>
|
||||
<div className="space-y-4">
|
||||
{pinnedAnnouncements.map((announcement) => (
|
||||
<Card
|
||||
key={announcement.id}
|
||||
className="bg-slate-800/50 border-rose-500/50 hover:border-rose-400/80 transition-all"
|
||||
>
|
||||
<CardHeader>
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex-1">
|
||||
<CardTitle className="text-rose-100">
|
||||
{announcement.title}
|
||||
</CardTitle>
|
||||
<CardDescription className="text-slate-400">
|
||||
by {announcement.author} • {announcement.date}
|
||||
</CardDescription>
|
||||
</div>
|
||||
<Badge
|
||||
className={`border ${getPriorityColor(announcement.priority)}`}
|
||||
>
|
||||
{announcement.priority}
|
||||
</Badge>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-slate-300 mb-3">
|
||||
{announcement.content}
|
||||
</p>
|
||||
<Badge className="bg-slate-700 text-slate-300">
|
||||
{announcement.category}
|
||||
</Badge>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Regular Announcements */}
|
||||
{unpinnedAnnouncements.length > 0 && (
|
||||
<div>
|
||||
<h2 className="text-lg font-semibold text-rose-100 mb-4">
|
||||
Recent Announcements
|
||||
</h2>
|
||||
<div className="space-y-4">
|
||||
{unpinnedAnnouncements.map((announcement) => (
|
||||
<Card
|
||||
key={announcement.id}
|
||||
className="bg-slate-800/50 border-slate-700/50 hover:border-rose-500/50 transition-all"
|
||||
>
|
||||
<CardHeader>
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex-1">
|
||||
<CardTitle className="text-rose-100">
|
||||
{announcement.title}
|
||||
</CardTitle>
|
||||
<CardDescription className="text-slate-400">
|
||||
by {announcement.author} • {announcement.date}
|
||||
</CardDescription>
|
||||
</div>
|
||||
<Badge
|
||||
className={`border ${getPriorityColor(announcement.priority)}`}
|
||||
>
|
||||
{announcement.priority}
|
||||
</Badge>
|
||||
</div>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-slate-300 mb-3">
|
||||
{announcement.content}
|
||||
</p>
|
||||
<Badge className="bg-slate-700 text-slate-300">
|
||||
{announcement.category}
|
||||
</Badge>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{filtered.length === 0 && (
|
||||
<div className="text-center py-12">
|
||||
<p className="text-slate-400">No announcements found</p>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in a new issue